summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/scripts/pythontex/pythontex_engines.py
diff options
context:
space:
mode:
Diffstat (limited to 'Master/texmf-dist/scripts/pythontex/pythontex_engines.py')
-rwxr-xr-xMaster/texmf-dist/scripts/pythontex/pythontex_engines.py534
1 files changed, 372 insertions, 162 deletions
diff --git a/Master/texmf-dist/scripts/pythontex/pythontex_engines.py b/Master/texmf-dist/scripts/pythontex/pythontex_engines.py
index 518820c8a7b..83ae0acd50e 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-2013, Geoffrey M. Poore
+Copyright (c) 2012-2014, Geoffrey M. Poore
All rights reserved.
Licensed under the BSD 3-Clause License:
http://www.opensource.org/licenses/BSD-3-Clause
@@ -25,25 +25,27 @@ Licensed under the BSD 3-Clause License:
'''
# Imports
+import os
import sys
import textwrap
from hashlib import sha1
from collections import OrderedDict, namedtuple
-interpreter_dict = {k:k for k in ('python', 'ruby', 'julia')}
+interpreter_dict = {k:k for k in ('python', 'ruby', 'julia', 'octave')}
# The {file} field needs to be replaced by itself, since the actual
# substitution of the real file can only be done at runtime, whereas the
# substitution for the interpreter should be done when the engine is
# initialized.
interpreter_dict['file'] = '{file}'
+interpreter_dict['File'] = '{File}'
engine_dict = {}
-CodeIndex = namedtuple('CodeIndex', ['input_file', 'input_command',
- 'input_line_int', 'lines_total',
+CodeIndex = namedtuple('CodeIndex', ['input_file', 'command',
+ 'line_int', 'lines_total',
'lines_user', 'lines_input',
'inline_count'])
@@ -100,19 +102,13 @@ class CodeEngine(object):
self.template = template
self.wrapper = wrapper
self.formatter = formatter
- # Perform some additional formatting on some strings. Dedent.
- # Change from {{ }} tags for replacement fields to { } tags that
- # are compatible with Python's string format() method, which is much
- # more efficient than a template engine.
+ # Perform some additional formatting on some strings.
self.extension = self.extension.lstrip('.')
- self.command = self._dejinja(self.command)
- self.template = self._dedent(self._dejinja(self.template))
- self.wrapper = self._dedent(self._dejinja(self.wrapper))
+ self.template = self._dedent(self.template)
+ self.wrapper = self._dedent(self.wrapper)
# Make sure formatter string ends with a newline
- if self.formatter.endswith('\n'):
- self.formatter = self._dejinja(self.formatter)
- else:
- self.formatter = self._dejinja(self.formatter) + '\n'
+ if not self.formatter.endswith('\n'):
+ self.formatter = self.formatter + '\n'
# Type check errors, warnings, and linenumbers
if errors is None:
@@ -158,7 +154,7 @@ class CodeEngine(object):
raise TypeError('CodeEngine needs "warnings" to contain strings')
self.warnings = warnings
if linenumbers is None:
- linenumbers = 'line {{number}}'
+ linenumbers = 'line {number}'
if sys.version_info[0] == 2:
if isinstance(linenumbers, basestring):
linenumbers = [linenumbers]
@@ -177,7 +173,7 @@ class CodeEngine(object):
if not isinstance(l, str):
raise TypeError('CodeEngine needs "linenumbers" to contain strings')
# Need to replace tags
- linenumbers = [l.replace('{{number}}', r'(\d+)') for l in linenumbers]
+ linenumbers = [l.replace('{number}', r'(\d+)') for l in linenumbers]
self.linenumbers = linenumbers
# Type check lookbehind
@@ -251,25 +247,6 @@ class CodeEngine(object):
while s.startswith('\n'):
s = s[1:]
return s
-
- def _dejinja(self, s):
- '''
- Switch all `{{ }}` tags into `{ }`, and all normal braces `{ }` into
- `{{ }}`, so that Python's string format() method may be used. Also
- strip any whitespace surrounding the field name.
-
- This will fail if literal `{{` and `}}` are needed. If those are
- ever needed, then options for custom tags will be needed.
- '''
- lst = [t.replace('{', '{{') for t in s.split('{{')]
- for n in range(1, len(lst)):
- lst[n] = lst[n].lstrip(' ')
- s = '{'.join(lst)
- lst = [t.replace('}', '}}') for t in s.split('}}')]
- for n in range(0, len(lst)-1):
- lst[n] = lst[n].rstrip(' ')
- s = '}'.join(lst)
- return s
def _register(self):
'''
@@ -290,6 +267,8 @@ class CodeEngine(object):
`__future__` be at the very beginning of a script.
'''
# Take care of `--interpreter`
+ # The `interpreter_dict` has entries that allow `{file}` and
+ # `{outputdir}` fields to be replaced with themselves
self.command = self.command.format(**interpreter_dict)
# Take care of `__future__`
if self.language.startswith('python'):
@@ -419,8 +398,8 @@ class CodeEngine(object):
else:
return cc_future + code_future
- def get_script(self, encoding, utilspath, workingdir,
- cc_list_begin, code_list, cc_list_end):
+ def get_script(self, encoding, utilspath, outputdir, workingdir,
+ cc_list_begin, code_list, cc_list_end, debug, interactive):
'''
Assemble the script that will be executed. In the process, assemble
an index of line numbers that may be used to correlate script line
@@ -441,15 +420,28 @@ class CodeEngine(object):
try:
script_begin, script_end = self.template.split('{body}')
except:
- raise ValueError('Template for ' + self.name + ' is missing {{body}}')
+ raise ValueError('Template for ' + self.name + ' is missing {body}')
# Add beginning to script
+ if os.path.isabs(os.path.expanduser(os.path.normcase(workingdir))):
+ workingdir_full = workingdir
+ else:
+ workingdir_full = os.path.join(os.getcwd(), workingdir).replace('\\', '/')
+ # Correct workingdir if in debug or interactive mode, so that it's
+ # relative to the script path
+ # #### May refactor this once debugging functionality is more
+ # fully implemented
+ if debug is not None or interactive is not None:
+ if not os.path.isabs(os.path.expanduser(os.path.normcase(workingdir))):
+ workingdir = os.path.relpath(workingdir, outputdir)
script_begin = script_begin.format(encoding=encoding, future=future,
- utilspath=utilspath, workingdir=workingdir,
+ utilspath=utilspath,
+ workingdir=os.path.expanduser(os.path.normcase(workingdir)),
+ Workingdir=workingdir_full,
extend=self.extend,
- input_family=code_list[0].input_family,
- input_session=code_list[0].input_session,
- input_restart=code_list[0].input_restart,
+ family=code_list[0].family,
+ session=code_list[0].session,
+ restart=code_list[0].restart,
dependencies_delim='=>PYTHONTEX:DEPENDENCIES#',
created_delim='=>PYTHONTEX:CREATED#')
script.append(script_begin)
@@ -459,7 +451,7 @@ class CodeEngine(object):
try:
wrapper_begin, wrapper_end = self.wrapper.split('{code}')
except:
- raise ValueError('Wrapper for ' + self.name + ' is missing {{code}}')
+ raise ValueError('Wrapper for ' + self.name + ' is missing {code}')
if not self.language.startswith('python'):
# In the event of a syntax error at the end of user code, Ruby
# (and perhaps others) will use the line number from the NEXT
@@ -472,9 +464,9 @@ class CodeEngine(object):
# parts of the wrapper.
wrapper_begin = wrapper_begin.rstrip(' \t\n') + '\n'
wrapper_end = wrapper_end.lstrip(' \t\n')
- stdout_delim = '=>PYTHONTEX:STDOUT#{input_instance}#{input_command}#'
- stderr_delim = '=>PYTHONTEX:STDERR#{input_instance}#{input_command}#'
- wrapper_begin = wrapper_begin.replace('{stdout_delim}', stdout_delim).replace('{stderr_delim}', stderr_delim)
+ stdoutdelim = '=>PYTHONTEX:STDOUT#{instance}#{command}#'
+ stderrdelim = '=>PYTHONTEX:STDERR#{instance}#{command}#'
+ wrapper_begin = wrapper_begin.replace('{stdoutdelim}', stdoutdelim).replace('{stderrdelim}', stderrdelim)
wrapper_begin_offset = wrapper_begin.count('\n')
wrapper_end_offset = wrapper_end.count('\n')
@@ -486,15 +478,15 @@ class CodeEngine(object):
for c in cc_list_begin:
# Wrapper before
lines_total += wrapper_begin_offset
- script.append(wrapper_begin.format(input_command=c.input_command,
- input_context=c.input_context,
- input_args=c.input_args_run,
- input_instance=c.input_instance,
- input_line=c.input_line))
+ script.append(wrapper_begin.format(command=c.command,
+ context=c.context,
+ args=c.args_run,
+ instance=c.instance,
+ line=c.line))
# Actual code
lines_input = c.code.count('\n')
- code_index[c.input_instance] = CodeIndex(c.input_file, c.input_command, c.input_line_int, lines_total, lines_user, lines_input, inline_count)
+ code_index[c.instance] = CodeIndex(c.input_file, c.command, c.line_int, lines_total, lines_user, lines_input, inline_count)
script.append(c.code)
if c.is_inline:
inline_count += 1
@@ -511,16 +503,16 @@ class CodeEngine(object):
for c in code_list:
# Wrapper before
lines_total += wrapper_begin_offset
- script.append(wrapper_begin.format(input_command=c.input_command,
- input_context=c.input_context,
- input_args=c.input_args_run,
- input_instance=c.input_instance,
- input_line=c.input_line))
+ script.append(wrapper_begin.format(command=c.command,
+ context=c.context,
+ args=c.args_run,
+ instance=c.instance,
+ line=c.line))
# Actual code
lines_input = c.code.count('\n')
- code_index[c.input_instance] = CodeIndex(c.input_file, c.input_command, c.input_line_int, lines_total, lines_user, lines_input, inline_count)
- if c.input_command == 'i':
+ code_index[c.instance] = CodeIndex(c.input_file, c.command, c.line_int, lines_total, lines_user, lines_input, inline_count)
+ if c.command == 'i':
script.append(self.formatter.format(code=c.code.rstrip('\n')))
inline_count += 1
else:
@@ -538,15 +530,15 @@ class CodeEngine(object):
for c in cc_list_end:
# Wrapper before
lines_total += wrapper_begin_offset
- script.append(wrapper_begin.format(input_command=c.input_command,
- input_context=c.input_context,
- input_args=c.input_args_run,
- input_instance=c.input_instance,
- input_line=c.input_line))
+ script.append(wrapper_begin.format(command=c.command,
+ context=c.context,
+ args=c.args_run,
+ instance=c.instance,
+ line=c.line))
# Actual code
lines_input = c.code.count('\n')
- code_index[c.input_instance] = CodeIndex(c.input_file, c.input_command, c.input_line_int, lines_total, lines_user, lines_input, inline_count)
+ code_index[c.instance] = CodeIndex(c.input_file, c.command, c.line_int, lines_total, lines_user, lines_input, inline_count)
script.append(c.code)
if c.is_inline:
inline_count += 1
@@ -558,7 +550,7 @@ class CodeEngine(object):
lines_total += wrapper_end_offset
# Finish script
- script.append(script_end)
+ script.append(script_end.format(dependencies_delim='=>PYTHONTEX:DEPENDENCIES#', created_delim='=>PYTHONTEX:CREATED#'))
return script, code_index
@@ -625,67 +617,70 @@ class PythonConsoleEngine(CodeEngine):
python_template = '''
- # -*- coding: {{encoding}} -*-
-
- {{future}}
+ # -*- coding: {encoding} -*-
+ {future}
+
import os
import sys
import codecs
- if sys.version_info[0] == 2:
- sys.stdout = codecs.getwriter('{{encoding}}')(sys.stdout, 'strict')
- sys.stderr = codecs.getwriter('{{encoding}}')(sys.stderr, 'strict')
- else:
- sys.stdout = codecs.getwriter('{{encoding}}')(sys.stdout.buffer, 'strict')
- sys.stderr = codecs.getwriter('{{encoding}}')(sys.stderr.buffer, 'strict')
+ if '--interactive' not in sys.argv[1:]:
+ if sys.version_info[0] == 2:
+ sys.stdout = codecs.getwriter('{encoding}')(sys.stdout, 'strict')
+ sys.stderr = codecs.getwriter('{encoding}')(sys.stderr, 'strict')
+ else:
+ sys.stdout = codecs.getwriter('{encoding}')(sys.stdout.buffer, 'strict')
+ sys.stderr = codecs.getwriter('{encoding}')(sys.stderr.buffer, 'strict')
- sys.path.append('{{utilspath}}')
+ if '{utilspath}' and '{utilspath}' not in sys.path:
+ sys.path.append('{utilspath}')
from pythontex_utils import PythonTeXUtils
pytex = PythonTeXUtils()
pytex.docdir = os.getcwd()
- if os.path.isdir('{{workingdir}}'):
- os.chdir('{{workingdir}}')
+ if os.path.isdir('{workingdir}'):
+ os.chdir('{workingdir}')
if os.getcwd() not in sys.path:
sys.path.append(os.getcwd())
else:
if len(sys.argv) < 2 or sys.argv[1] != '--manual':
- sys.exit('Cannot find directory {{workingdir}}')
+ sys.exit('Cannot find directory {workingdir}')
if pytex.docdir not in sys.path:
sys.path.append(pytex.docdir)
- {{extend}}
+ {extend}
- pytex.input_family = '{{input_family}}'
- pytex.input_session = '{{input_session}}'
- pytex.input_restart = '{{input_restart}}'
+ pytex.id = '{family}_{session}_{restart}'
+ pytex.family = '{family}'
+ pytex.session = '{session}'
+ pytex.restart = '{restart}'
- {{body}}
+ {body}
pytex.cleanup()
'''
python_wrapper = '''
- pytex.input_command = '{{input_command}}'
- pytex.input_context = '{{input_context}}'
- pytex.input_args = '{{input_args}}'
- pytex.input_instance = '{{input_instance}}'
- pytex.input_line = '{{input_line}}'
-
- print('{{stdout_delim}}')
- sys.stderr.write('{{stderr_delim}}\\n')
+ pytex.command = '{command}'
+ pytex.set_context('{context}')
+ pytex.args = '{args}'
+ pytex.instance = '{instance}'
+ pytex.line = '{line}'
+
+ print('{stdoutdelim}')
+ sys.stderr.write('{stderrdelim}\\n')
pytex.before()
- {{code}}
+ {code}
pytex.after()
'''
-CodeEngine('python', 'python', '.py', '{{python}} {{file}}.py',
- python_template, python_wrapper, 'print(pytex.formatter({{code}}))',
- 'Error:', 'Warning:', ['line {{number}}', ':{{number}}:'])
+CodeEngine('python', 'python', '.py', '{python} {file}.py',
+ python_template, python_wrapper, 'print(pytex.formatter({code}))',
+ 'Error:', 'Warning:', ['line {number}', ':{number}:'])
SubCodeEngine('python', 'py')
@@ -711,18 +706,22 @@ PythonConsoleEngine('sympycon', startup='from sympy import *')
ruby_template = '''
- # -*- coding: {{encoding}} -*-
+ # -*- coding: {encoding} -*-
- $stdout.set_encoding('{{encoding}}')
- $stderr.set_encoding('{{encoding}}')
+ unless ARGV.include?('--interactive')
+ $stdout.set_encoding('{encoding}')
+ $stderr.set_encoding('{encoding}')
+ end
class RubyTeXUtils
- attr_accessor :input_family, :input_session, :input_restart,
- :input_command, :input_context, :input_args,
- :input_instance, :input_line, :dependencies, :created, :docdir
+ attr_accessor :id, :family, :session, :restart,
+ :command, :context, :args,
+ :instance, :line, :dependencies, :created,
+ :docdir, :_context_raw
def initialize
@dependencies = Array.new
@created = Array.new
+ @_context_raw = nil
end
def formatter(expr)
return expr.to_s
@@ -737,14 +736,39 @@ ruby_template = '''
def add_created(*expr)
self.created.push(*expr)
end
+ def set_context(expr)
+ if expr != "" and expr != @_context_raw
+ @context = expr.split(',').map{{|x| x1,x2 = x.split('='); {{x1.strip() => x2.strip()}}}}.reduce(:merge)
+ @_context_raw = expr
+ end
+ end
+ def pt_to_in(expr)
+ if expr.is_a?String
+ if expr.end_with?'pt'
+ expr = expr[0..-3]
+ end
+ return expr.to_f/72.27
+ else
+ return expr/72.27
+ end
+ end
+ def pt_to_cm(expr)
+ return pt_to_in(expr)*2.54
+ end
+ def pt_to_mm(expr)
+ return pt_to_in(expr)*25.4
+ end
+ def pt_to_bp(expr)
+ return pt_to_in(expr)*72
+ end
def cleanup
- puts '{{dependencies_delim}}'
+ puts '{dependencies_delim}'
if @dependencies
- @dependencies.each { |x| puts x }
+ @dependencies.each {{ |x| puts x }}
end
- puts '{{created_delim}}'
+ puts '{created_delim}'
if @created
- @created.each { |x| puts x }
+ @created.each {{ |x| puts x }}
end
end
end
@@ -752,44 +776,45 @@ ruby_template = '''
rbtex = RubyTeXUtils.new
rbtex.docdir = Dir.pwd
- if File.directory?('{{workingdir}}')
- Dir.chdir('{{workingdir}}')
+ if File.directory?('{workingdir}')
+ Dir.chdir('{workingdir}')
$LOAD_PATH.push(Dir.pwd) unless $LOAD_PATH.include?(Dir.pwd)
elsif ARGV[0] != '--manual'
- abort('Cannot change to directory {{workingdir}}')
+ abort('Cannot change to directory {workingdir}')
end
$LOAD_PATH.push(rbtex.docdir) unless $LOAD_PATH.include?(rbtex.docdir)
- {{extend}}
+ {extend}
- rbtex.input_family = '{{input_family}}'
- rbtex.input_session = '{{input_session}}'
- rbtex.input_restart = '{{input_restart}}'
+ rbtex.id = '{family}_{session}_{restart}'
+ rbtex.family = '{family}'
+ rbtex.session = '{session}'
+ rbtex.restart = '{restart}'
- {{body}}
+ {body}
rbtex.cleanup
'''
ruby_wrapper = '''
- rbtex.input_command = '{{input_command}}'
- rbtex.input_context = '{{input_context}}'
- rbtex.input_args = '{{input_args}}'
- rbtex.input_instance = '{{input_instance}}'
- rbtex.input_line = '{{input_line}}'
-
- puts '{{stdout_delim}}'
- $stderr.puts '{{stderr_delim}}'
+ rbtex.command = '{command}'
+ rbtex.set_context('{context}')
+ rbtex.args = '{args}'
+ rbtex.instance = '{instance}'
+ rbtex.line = '{line}'
+
+ puts '{stdoutdelim}'
+ $stderr.puts '{stderrdelim}'
rbtex.before
- {{code}}
+ {code}
rbtex.after
'''
-CodeEngine('ruby', 'ruby', '.rb', '{{ruby}} {{file}}.rb', ruby_template,
- ruby_wrapper, 'puts rbtex.formatter({{code}})',
- ['Error)', '(Errno', 'error'], 'warning:', ':{{number}}:')
+CodeEngine('ruby', 'ruby', '.rb', '{ruby} {file}.rb', ruby_template,
+ ruby_wrapper, 'puts rbtex.formatter({code})',
+ ['Error)', '(Errno', 'error'], 'warning:', ':{number}:')
SubCodeEngine('ruby', 'rb')
@@ -803,24 +828,31 @@ julia_template = '''
# So can't set stdout and stderr encoding
type JuliaTeXUtils
- input_family::String
- input_session::String
- input_restart::String
- input_command::String
- input_context::String
- input_args::String
- input_instance::String
- input_line::String
+ id::String
+ family::String
+ session::String
+ restart::String
+ command::String
+ context::Dict
+ args::String
+ instance::String
+ line::String
- _dependencies::Array{String}
- _created::Array{String}
+ _dependencies::Array{{String}}
+ _created::Array{{String}}
docdir::String
+ _context_raw::String
formatter::Function
before::Function
after::Function
add_dependencies::Function
add_created::Function
+ set_context::Function
+ pt_to_in::Function
+ pt_to_cm::Function
+ pt_to_mm::Function
+ pt_to_bp::Function
cleanup::Function
self::JuliaTeXUtils
@@ -830,6 +862,7 @@ julia_template = '''
self.self = self
self._dependencies = Array(String, 0)
self._created = Array(String, 0)
+ self._context_raw = ""
function formatter(expr)
string(expr)
@@ -854,12 +887,47 @@ julia_template = '''
end
self.add_created = add_created
+ function set_context(expr)
+ if expr != "" && expr != self._context_raw
+ self.context = {{strip(x[1]) => strip(x[2]) for x in map(x -> split(x, "="), split(expr, ","))}}
+ self._context_raw = expr
+ end
+ end
+ self.set_context = set_context
+
+ function pt_to_in(expr)
+ if isa(expr, String)
+ if sizeof(expr) > 2 && expr[end-1:end] == "pt"
+ expr = expr[1:end-2]
+ end
+ return float(expr)/72.27
+ else
+ return expr/72.27
+ end
+ end
+ self.pt_to_in = pt_to_in
+
+ function pt_to_cm(expr)
+ return self.pt_to_in(expr)*2.54
+ end
+ self.pt_to_cm = pt_to_cm
+
+ function pt_to_mm(expr)
+ return self.pt_to_in(expr)*25.4
+ end
+ self.pt_to_mm = pt_to_mm
+
+ function pt_to_bp(expr)
+ return self.pt_to_in(expr)*72
+ end
+ self.pt_to_bp = pt_to_bp
+
function cleanup()
- println("{{dependencies_delim}}")
+ println("{dependencies_delim}")
for f in self._dependencies
println(f)
end
- println("{{created_delim}}")
+ println("{created_delim}")
for f in self._created
println(f)
end
@@ -874,49 +942,191 @@ julia_template = '''
jltex.docdir = pwd()
try
- cd("{{workingdir}}")
- if !(contains(LOAD_PATH, pwd()))
- push!(LOAD_PATH, pwd())
- end
+ cd("{workingdir}")
catch
if !(length(ARGS) > 0 && ARGS[1] == "--manual")
- error("Could not find directory {{workingdir}}")
+ error("Could not find directory {workingdir}")
end
end
- if !(contains(LOAD_PATH, jltex.docdir))
+ if !(in(jltex.docdir, LOAD_PATH))
push!(LOAD_PATH, jltex.docdir)
end
- {{extend}}
+ {extend}
- jltex.input_family = "{{input_family}}"
- jltex.input_session = "{{input_session}}"
- jltex.input_restart = "{{input_restart}}"
+ jltex.id = "{family}_{session}_{restart}"
+ jltex.family = "{family}"
+ jltex.session = "{session}"
+ jltex.restart = "{restart}"
- {{body}}
+ {body}
jltex.cleanup()
'''
julia_wrapper = '''
- jltex.input_command = "{{input_command}}"
- jltex.input_context = "{{input_context}}"
- jltex.input_args = "{{input_args}}"
- jltex.input_instance = "{{input_instance}}"
- jltex.input_line = "{{input_line}}"
-
- println("{{stdout_delim}}")
- write(STDERR, "{{stderr_delim}}\\n")
+ jltex.command = "{command}"
+ jltex.set_context("{context}")
+ jltex.args = "{args}"
+ jltex.instance = "{instance}"
+ jltex.line = "{line}"
+
+ println("{stdoutdelim}")
+ write(STDERR, "{stderrdelim}\\n")
jltex.before()
- {{code}}
+ {code}
jltex.after()
'''
-CodeEngine('julia', 'julia', '.jl', '{{julia}} {{file}}.jl', julia_template,
- julia_wrapper, 'println(jltex.formatter({{code}}))',
- 'ERROR:', 'WARNING:', ':{{number}}', True)
+CodeEngine('julia', 'julia', '.jl', '{julia} "{file}.jl"', julia_template,
+ julia_wrapper, 'println(jltex.formatter({code}))',
+ 'ERROR:', 'WARNING:', ':{number}', True)
SubCodeEngine('julia', 'jl')
+
+octave_template = '''
+ # Octave only supports @CLASS, not classdef
+ # So use a struct plus functions as a substitute for a utilities class
+
+ global octavetex = struct();
+ octavetex.docdir = pwd();
+ try
+ cd '{Workingdir}';
+ catch
+ arg_list = argv()
+ if size(arg_list, 1) == 1 && arg_list{{1}} == '--manual'
+ else
+ error("Could not find directory {workingdir}");
+ end
+ end
+ if find_dir_in_path(octavetex.docdir)
+ else
+ addpath(octavetex.docdir);
+ end
+
+ {extend}
+
+ octavetex.dependencies = {{}};
+ octavetex.created = {{}};
+ octavetex._context_raw = '';
+
+ function octavetex_formatter(argin)
+ disp(argin);
+ end
+ octavetex.formatter = @(argin) octavetex_formatter(argin);
+
+ function octavetex_before()
+ end
+ octavetex.before = @() octavetex_before();
+
+ function octavetex_after()
+ end
+ octavetex.after = @() octavetex_after();
+
+ function octavetex_add_dependencies(varargin)
+ global octavetex;
+ for i = 1:length(varargin)
+ octavetex.dependencies{{end+1}} = varargin{{i}};
+ end
+ end
+ octavetex.add_dependencies = @(varargin) octavetex_add_dependencies(varargin{{:}});
+
+ function octavetex_add_created(varargin)
+ global octavetex;
+ for i = 1:length(varargin)
+ octavetex.created{{end+1}} = varargin{{i}};
+ end
+ end
+ octavetex.add_created = @(varargin) octavetex_add_created(varargin{{:}});
+
+ function octavetex_set_context(argin)
+ global octavetex;
+ if ~strcmp(argin, octavetex._context_raw)
+ octavetex._context_raw = argin;
+ hash = struct;
+ argin_kv = strsplit(argin, ',');
+ for i = 1:length(argin_kv)
+ kv = strsplit(argin_kv{{i}}, '=');
+ k = strtrim(kv{{1}});
+ v = strtrim(kv{{2}});
+ hash = setfield(hash, k, v);
+ end
+ octavetex.context = hash;
+ end
+ end
+ octavetex.set_context = @(argin) octavetex_set_context(argin);
+
+ function out = octavetex_pt_to_in(argin)
+ if ischar(argin)
+ if length(argin) > 2 && argin(end-1:end) == 'pt'
+ out = str2num(argin(1:end-2))/72.27;
+ else
+ out = str2num(argin)/72.27;
+ end
+ else
+ out = argin/72.27;
+ end
+ end
+ octavetex.pt_to_in = @(argin) octavetex_pt_to_in(argin);
+
+ function out = octavetex_pt_to_cm(argin)
+ out = octavetex_pt_to_in(argin)*2.54;
+ end
+ octavetex.pt_to_cm = @(argin) octavetex_pt_to_cm(argin);
+
+ function out = octavetex_pt_to_mm(argin)
+ out = octavetex_pt_to_in(argin)*25.4;
+ end
+ octavetex.pt_to_mm = @(argin) octavetex_pt_to_mm(argin);
+
+ function out = octavetex_pt_to_bp(argin)
+ out = octavetex_pt_to_in(argin)*72;
+ end
+ octavetex.pt_to_bp = @(argin) octavetex_pt_to_bp(argin);
+
+ function octavetex_cleanup()
+ global octavetex;
+ fprintf(strcat('{dependencies_delim}', "\\n"));
+ for i = 1:length(octavetex.dependencies)
+ fprintf(strcat(octavetex.dependencies{{i}}, "\\n"));
+ end
+ fprintf(strcat('{created_delim}', "\\n"));
+ for i = 1:length(octavetex.created)
+ fprintf(strcat(octavetex.created{{i}}, "\\n"));
+ end
+ end
+ octavetex.cleanup = @() octavetex_cleanup();
+
+ octavetex.id = '{family}_{session}_{restart}';
+ octavetex.family = '{family}';
+ octavetex.session = '{session}';
+ octavetex.restart = '{restart}';
+
+ {body}
+
+ octavetex.cleanup()
+ '''
+
+octave_wrapper = '''
+ octavetex.command = '{command}';
+ octavetex.set_context('{context}');
+ octavetex.args = '{args}';
+ octavetex.instance = '{instance}';
+ octavetex.line = '{line}';
+
+ octavetex.before()
+
+ fprintf(strcat('{stdoutdelim}', "\\n"));
+ fprintf(stderr, strcat('{stderrdelim}', "\\n"));
+ {code}
+
+ octavetex.after()
+ '''
+
+CodeEngine('octave', 'octave', '.m',
+ '{octave} -q "{File}.m"',
+ octave_template, octave_wrapper, 'disp({code})',
+ 'error', 'warning', 'line {number}')