diff --git a/Slides/math_helper.py b/Slides/math_helper.py
index a292e5b..ce4c1da 100644
--- a/Slides/math_helper.py
+++ b/Slides/math_helper.py
@@ -1,137 +1,140 @@
#!/usr/bin/env pyton
################################################################
import numpy as np
from sympy import latex
from IPython.display import display, Math
from . import presentation_helper as ph
################################################################
-def print_latex(sstr, *argv):
+def print_latex(sstr, *argv, ret=False):
args = []
# print argv
for a in argv:
try:
ff = a._repr_latex_()
ff = ff[2:-2]
except Exception:
# print(e)
ff = latex(a)
args.append(ff)
sstr = sstr.format(*args)
# print (sstr)
- display(Math(latex(sstr)))
+ res = Math(latex(sstr))
+ display(res)
+ if ret is True:
+ return res
################################################################
class ColoredMatrix:
color_def = {
'b': 'blue',
'g': 'green',
'r': 'red',
'p': 'purple'
}
def __init__(self, mat):
if isinstance(mat, ColoredMatrix):
self.mat = mat.mat
else:
self.mat = mat
self.colors = np.zeros(self.mat.shape, dtype='S10')
self.alternative = np.zeros(self.mat.shape, dtype='S10')
self.sym = False
def __len__(self):
return self.mat.__len__()
def dot(self, mat):
return self.mat.dot(mat)
def __mul__(self, n):
return self.mat.__mul__(n)
def __rmul__(self, n):
return n*self.mat
def __div__(self, n):
temp = ColoredMatrix(self.mat.__div__(n))
temp.colors[:] = self.colors[:]
return temp
def evalf(self, *args):
mat_eval = self.mat.evalf(*args)
new_mat = ColoredMatrix(mat_eval)
new_mat.colors = self.colors.copy()
return new_mat
def __getitem__(self, index):
return self.mat.__getitem__(index)
def __setitem__(self, index, value):
return self.mat.__setitem__(index, value)
def _get_coeff(self, i, j=0):
if self.alternative[i, j] != '':
return self.alternative[i, j]
else:
return latex(self.mat[i, j])
def _colored_coeff(self, i, j=0):
if self.sym is True:
if i == self.mat.shape[0]-1 and j == 0:
return 'Sym.'
elif i > j:
return ''
if self.colors[i, j] in self.color_def:
color = self.color_def[self.colors[i, j]]
else:
color = 'black'
coeff = self._get_coeff(i, j)
if coeff == '':
return ''
return (r'{\color{' + color + '}{' + coeff + '}}')
def _repr_latex_(self):
m = self.mat.shape[0]
if len(self.mat.shape) > 1 and self.mat.shape[1] > 1:
n = self.mat.shape[1]
result = ''
for i in range(0, m):
row = []
for j in range(0, n):
row.append(self._colored_coeff(i, j))
result += ' & '.join(row)
if i < m-1:
result += r'\\'
result = (r'\left[\begin{array}{' + 'c'*n + '}' +
result + r'\end{array}\right]')
else:
rows = []
for i in range(0, m):
rows.append(self._colored_coeff(i))
result = r'\\'.join(rows)
result = (r'\left\{\begin{matrix}' +
result + r'\end{matrix}\right\}')
return '$$' + result + '$$'
################################################################
def init_printing():
ph.registerFormatter(ColoredMatrix, 'image/png', ph._print_latex_png)
################################################################
init_printing()
diff --git a/Slides/snippet_helper.py b/Slides/snippet_helper.py
index e3fa2a9..6d65b4a 100644
--- a/Slides/snippet_helper.py
+++ b/Slides/snippet_helper.py
@@ -1,312 +1,323 @@
#!/usr/bin/env python3
import subprocess
import os
import re
from pygments import highlight
from pygments.lexers import CppLexer
# from pygments.lexer import RegexLexer
# from pygments.lexers import MatlabLexer
from pygments.formatters import HtmlFormatter
from pygments.formatters import LatexFormatter
from pygments import token
from IPython.display import HTML
from tempfile import NamedTemporaryFile
################################################################
class Snippet(object):
default_output = 'html'
default_line_numbering = False
def __init__(self, inp, format_flag=False, compile_flag=False):
try:
self.loadfile(inp)
except Exception as e:
self.content = inp.strip()
if format_flag:
self.clang_format()
if compile_flag:
self.compile()
def save(self, filename):
- open(filename, 'w').write(self.content)
+ f = open(filename, 'w')
+ f.write(self.content)
+ f.close()
def loadfile(self, inp):
filename = inp
full_filename = os.path.realpath(filename)
- self.content = open(full_filename).read()
+ f = open(full_filename)
+ self.content = f.read()
+ f.close()
def clang_format(self):
f = NamedTemporaryFile()
f.write(self.content.encode())
f.flush()
p = subprocess.Popen(
'clang-format {0}'.format(f.name),
shell=True, stdout=subprocess.PIPE)
stdout, stderr = p.communicate()
formatted_file = stdout
self.content = formatted_file.decode('utf-8')
def compile(self, working_dir='/tmp'):
f = NamedTemporaryFile(suffix='.cpp', delete=False)
f.write(self.content.encode())
f.flush()
working_dir = os.path.dirname(f.name)
# file_dir = os.path.dirname(self.full_filename)
previous_dir = os.getcwd()
os.chdir(working_dir)
p = subprocess.Popen(
'g++ -Wall -Wextra -I {1} -c {0}'.format(f.name, working_dir),
shell=True, stderr=subprocess.PIPE)
stdout, stderr = p.communicate()
ret = p.returncode
os.chdir(previous_dir)
if ret != 0:
print(stderr.decode('utf-8'))
raise Exception('compilation failed')
os.remove(f.name)
o_file = os.path.splitext(f.name)[0] + '.o'
os.remove(o_file)
+ def get_lines(self):
+ return self.content.split('\n')
+
+ def get_content(self):
+ return self.content
+
def __str__(self):
+ _content = self.content.split('\n')
ret = ""
- for i, line in enumerate(self.content):
- ret += '{0}: {1}'.format(i, line)
+ for i, line in enumerate(_content):
+ ret += '{0}: {1}\n'.format(i, line)
return ret
class KeywordLexer(object):
def __init__(self, keyword):
if keyword == 'curly_brackets':
keyword = '{|}'
self.keyword = keyword
def get_tokens(self, text):
pattern = '(' + self.keyword + ')'
splits = re.split(pattern, text)
if len(splits) == 1:
return [(token.Text, text)]
res = []
for count, s in enumerate(splits):
if count % 2 == 0:
res.append((token.Text, s))
else:
res.append((token.Keyword.Type, s))
# print(res)
return res
class LineLexer(object):
def __init__(self, line_number):
self.line_number = line_number
def get_tokens(self, text):
splits = text.split('\n')
res = []
splits1 = '\n'.join(splits[:self.line_number]) + '\n'
splits2 = splits[self.line_number] + '\n'
splits3 = '\n' + '\n'.join(splits[self.line_number + 1:]) + '\n'
splits = [splits1] + [splits2] + [splits3]
# print(splits)
for count, s in enumerate(splits):
if count == 1:
res.append((token.Keyword.Type, s))
else:
res.append((token.Text, s))
# print(res)
return res
class CustomLatexFormatter(LatexFormatter):
def __init__(self, **kwargs):
LatexFormatter.__init__(self, **kwargs)
def format(self, tokens, outfile):
res = []
for t, s in tokens:
if t == token.Keyword.Type:
import pygments.formatters.latex as la
s = la.escape_tex(s, self.commandprefix)
s = '\color{red}{\huge{' + s + '}}'
t = token.Escape
res.append((t, s))
LatexFormatter.format(self, res, outfile)
class CustomHtmlFormatter(HtmlFormatter):
def __init__(self, **kwargs):
HtmlFormatter.__init__(self, **kwargs)
def format(self, tokens, outfile_final):
# HtmlFormatter.format(self, tokens, outfile_final)
# return
from io import StringIO
outfile = StringIO()
res = []
ss = []
for t, s in tokens:
if t == token.Keyword.Type:
ss.append(s)
s = 'A' * 24
t = token.Text
res.append((t, s))
HtmlFormatter.format(self, res, outfile)
final = outfile.getvalue()
while ss:
s = ss.pop()
final = final.replace(
'A' * 24,
'{0}'.format(
s),
1)
outfile_final.write(final)
def pigment(self,
keyword=None, line_highlight=None,
start=None, end=None,
output=None, line_numbering=None):
_content = self.content.split('\n')
_content = [(c + '\n') for c in _content]
if start is None:
start = 1
if end is None:
end = len(_content)
if output is None:
output = self.default_output
lexer = CppLexer()
if keyword is not None:
lexer = self.KeywordLexer(keyword)
elif line_highlight is not None:
lexer = self.LineLexer(line_highlight - 1)
if line_numbering is None:
line_numbering = self.default_line_numbering
if output == 'html':
formatter = HtmlFormatter(
full=False, linenos=line_numbering, linenostart=start)
elif output == 'latex':
formatter = LatexFormatter(
full=False, linenos=line_numbering, linenostart=start)
if (keyword is not None) or (line_highlight is not None):
format_class = self.CustomHtmlFormatter
if output == 'latex':
format_class = self.CustomLatexFormatter
formatter = format_class(
full=False, linenos=line_numbering,
linenostart=start)
snip = _content[start - 1:end]
snip = ''.join(snip)
colored_snippet = highlight(snip, lexer, formatter)
if output == 'html':
HTML_TEMPLATE = """
{}
"""
css = formatter.get_style_defs()
colored_snippet = HTML(HTML_TEMPLATE.format(css, colored_snippet))
return colored_snippet
@staticmethod
def getLatexStyleDefs():
return LatexFormatter(full=True).get_style_defs()
################################################################
class SnippetCollection(Snippet):
def __init__(self):
self.functions = dict()
self.func_names = []
def addFunction(self, f_name, code):
self.func_names.append(f_name)
self.functions[f_name] = Snippet(code, format_flag=True)
self.compile()
def __getitem__(self, key):
return self.functions[key]
def flatten(self):
global_input = """
#include
#include
""" + '/' * 70 + '\n\n'
for f_name in self.func_names:
global_input += "void {0}(){{\n".format(f_name)
global_input += self.functions[f_name].content
global_input += '\n}\n\n' + '/' * 70 + '\n\n'
global_input += """
int main(int argc, char ** argv){\n"""
for f_name in self.func_names:
global_input += f_name + '();\n'
global_input += '\n}\n'
flat = Snippet(global_input,
format_flag=True)
return flat
def compile(self, **kwargs):
global_snippet = self.flatten()
global_snippet.compile(**kwargs)
def save(self, filename):
global_snippet = self.flatten()
open(filename, 'w').write(global_snippet.content)
def pigment(self, *args):
return self.flatten().pigment(*args)
def last(self):
return self.functions[self.func_names[-1]]
################################################################
# def printMatlab(code):
#
# html_snippet = highlight(
# code, MatlabLexer(),
# HtmlFormatter(full=True, style='colorful',
# classprefix='matlab_'))
#
# display(HTML(html_snippet))
# # return html_snippet
# ## testing
#Snippet.default_output = 'latex'
#Snippet.default_line_numbering = True
#
#snippet = SnippetCollection()
# snippet.addFunction('if_syntax', '''
# int p, q;
# if (p > q) {
# /*
# Statement1;
# Statement2;
# */
# }
#''')
#
#print (snippet['if_syntax'].pigment())
diff --git a/Slides/test/test_math_helper.py b/Slides/test/test_math_helper.py
deleted file mode 100644
index 7a3a8f9..0000000
--- a/Slides/test/test_math_helper.py
+++ /dev/null
@@ -1,10 +0,0 @@
-from Slides import math_helper as mh
-import numpy as np
-from sympy import Matrix, latex
-from IPython.display import display, Math
-
-a = Matrix(np.zeros((2, 2)))
-# display(a)
-a = mh.ColoredMatrix(a)
-# print (a)
-mh.print_latex('{0}',a)
diff --git a/setup.py b/setup.py
index 0b420e5..9c600a6 100644
--- a/setup.py
+++ b/setup.py
@@ -1,23 +1,24 @@
from setuptools import setup
setup(name="slides",
packages=['Slides'],
version="0.0.1",
author="Guillaume Anciaux",
author_email="guillaume.anciaux@epfl.ch",
description=("Slides making/convertion tools"),
scripts=['scripts/slides'],
+ test_suite="tests",
license="""
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 3 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 .
""")
diff --git a/tests/__init__.py b/tests/__init__.py
new file mode 100644
index 0000000..bee0b98
--- /dev/null
+++ b/tests/__init__.py
@@ -0,0 +1,3 @@
+#!/usr/bin/env python
+# -*- coding:utf-8 -*-
+
diff --git a/tests/snippet.cpp b/tests/snippet.cpp
new file mode 100644
index 0000000..2275b43
--- /dev/null
+++ b/tests/snippet.cpp
@@ -0,0 +1,33 @@
+#include
+
+int main(int argc, char *argv[]) {
+ /* This is a comment and will be ignored by the compiler
+Comments are useful to explain in English what
+the program does */
+
+ // Print "Hello World" to the screen
+ std::cout << "Hello World\\n";
+ return 0;
+
+ int row, column;
+ double temperature;
+ row = 1;
+ column = 2;
+ temperature = 3.0;
+
+ double tolerance1 = 0.0001;
+ double tolerance2 = 1e-4;
+
+ const double density = 45.621;
+
+ int integer1;
+ short int integer2;
+ long int integer3;
+
+ signed long int integer4;
+ unsigned int integer5;
+
+ float x1;
+ double x2;
+ long double x3;
+}
diff --git a/tests/test_math_helper.py b/tests/test_math_helper.py
new file mode 100644
index 0000000..8a483b9
--- /dev/null
+++ b/tests/test_math_helper.py
@@ -0,0 +1,20 @@
+#!/bin/env python3
+
+from __future__ import print_function
+import unittest
+
+
+class MathHelperTest(unittest.TestCase):
+ "Unit tests for MathHelper"
+
+ def setUp(self, ):
+ pass
+
+ def test_print_colored_matrix(self):
+ from Slides import math_helper as mh
+ import numpy as np
+ from sympy import Matrix
+
+ a = Matrix(np.zeros((2, 2)))
+ a = mh.ColoredMatrix(a)
+ mh.print_latex('{0}', a)
diff --git a/tests/test_snippet_helper.py b/tests/test_snippet_helper.py
new file mode 100644
index 0000000..01306ab
--- /dev/null
+++ b/tests/test_snippet_helper.py
@@ -0,0 +1,26 @@
+#!/bin/env python3
+
+from __future__ import print_function
+import unittest
+
+
+class SnippetHelperTest(unittest.TestCase):
+ "Unit tests for SnippetHelper"
+
+ def setUp(self, ):
+ pass
+
+ def test_cpp_snippet(self):
+ from Slides import snippet_helper as sh
+ sh.Snippet.default_line_number = True
+ sh.Snippet.default_output = 'latex'
+ snip = sh.Snippet('tests/snippet.cpp')
+ snip.save('snippet2.cpp')
+ f = open('snippet2.cpp')
+ snip2 = f.read()
+ f.close()
+ if snip.get_content() != snip2:
+ print('AAA ', snip.get_content())
+ print('BBB ', snip2)
+ raise RuntimeError('failed test')
+