diff --git a/Slides/math_helper.py b/Slides/math_helper.py index cb2adc1..1bb545c 100644 --- a/Slides/math_helper.py +++ b/Slides/math_helper.py @@ -1,140 +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, ret=False): args = [] # print argv for a in argv: try: ff = a._repr_latex_() ff = ff[1:-1] except Exception: # print(e) ff = latex(a) args.append(ff) sstr = sstr.format(*args) # print (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] + if self.alternative[i, j].decode('utf8') != '': + return self.alternative[i, j].decode('utf8') 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]] + if self.colors[i, j].decode('utf8') in self.color_def: + color = self.color_def[self.colors[i, j].decode('utf8')] 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 + '$$' + 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 25063fa..d376cd5 100644 --- a/Slides/snippet_helper.py +++ b/Slides/snippet_helper.py @@ -1,425 +1,427 @@ #!/usr/bin/env python3 import subprocess import os import re from pygments import highlight from pygments.lexers import CppLexer from pygments.lexers import PythonLexer # 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 SlicedSnippet(object): """ When you slice a snippet, this object is returned so that all your operations can apply directly to the snippet if need be. """ def __init__(self, snippet, slice): self.start = slice.start - self.end = slice.stop + if slice.start is None: + self.start = 1 + self.end = slice.stop-1 self.snippet = snippet def pigment(self, **kwargs): kwargs['start'] = self.start kwargs['end'] = self.end return self.snippet.pigment(**kwargs) class Snippet(object): """ Snippet objects manipulate codes. At construction it can be formatted using clang-format and it can be compiled to check for consistency. """ class CompilationError(Exception): """ Compilation error """ pass default_output = 'html' default_line_numbering = False def __getitem__(self, slice): return SlicedSnippet(self, slice) def __init__(self, inp, format_flag=False, compile_flag=False, include_paths=None, language='cpp'): try: self.loadfile(inp) except Exception: self.content = inp.strip() if include_paths is None: self.include_paths = [] else: self.include_paths = [ os.path.abspath(i) for i in include_paths] if format_flag: self.clang_format() if compile_flag: self.compile() if language == 'cpp': self.lexer = CppLexer() elif language == 'python': self.lexer = PythonLexer() elif language == 'matlab': self.lexer = MatlabLexer() def save(self, filename): """ Saves the snippet in another file :param filename: The filename to save the snippet to """ f = open(filename, 'w') f.write(self.content) f.close() def loadfile(self, inp): filename = inp full_filename = os.path.realpath(filename) 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() if p.returncode: raise RuntimeError('Failed to launch clang-format') formatted_file = stdout self.content = formatted_file.decode('utf-8') def execute(self, working_dir='/tmp', args='', libraries=''): self.compile(working_dir=working_dir) 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) include_paths = self.include_paths + [working_dir] include_paths = ['-I {0}'.format(a) for a in include_paths] include_paths = ' '.join(include_paths) p = subprocess.Popen( 'g++ -Wall -Wextra {1} {2} -o exec {0}'.format( f.name, include_paths, libraries), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout, stderr = p.communicate() ret = p.returncode if ret != 0: return ret, stdout, stderr p = subprocess.Popen( './exec {0}'.format(args), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout, stderr = p.communicate() ret = p.returncode os.chdir(previous_dir) return ret, stdout, stderr 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) include_paths = self.include_paths + [working_dir] include_paths = ['-I {0}'.format(a) for a in include_paths] include_paths = ' '.join(include_paths) p = subprocess.Popen( 'g++ -Wall -Wextra {1} -c {0}'.format(f.name, include_paths), shell=True, stderr=subprocess.PIPE) stdout, stderr = p.communicate() ret = p.returncode os.chdir(previous_dir) if ret != 0: raise Snippet.CompilationError('compilation failed\n' + stderr.decode('utf-8')) 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(_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 = [] # print(splits) # print(token.Keyword.Type) for count, s in enumerate(splits): # print(count, s) 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)) # print(res) HtmlFormatter.format(self, res, outfile) final = outfile.getvalue() while ss: s = ss.pop(0) 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 = self.lexer if keyword is not None: lexer = self.KeywordLexer(keyword) elif line_highlight is not None: if line_highlight < start or line_highlight > end: raise RuntimeError('line_highlight out of the sub snippet') line_highlight -= start lexer = self.LineLexer(line_highlight) 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) # print(colored_snippet) 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): if f_name in self.functions: raise RuntimeError('function already declared') 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 #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/tests/test_snippet_helper.py b/tests/test_snippet_helper.py index 12ab815..ea057b9 100644 --- a/tests/test_snippet_helper.py +++ b/tests/test_snippet_helper.py @@ -1,71 +1,71 @@ #!/bin/env python3 # -*- coding: utf-8 -*- from Slides import snippet_helper as sh def test_cpp_snippet_from_file(): sh.Snippet.default_line_number = True 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') def test_cpp_snippet_format(): sh.Snippet.default_line_number = True code = """ #include int main(int argc, char **argv){ return 0; } """ code = code.replace(';\n', ';') snip = sh.Snippet(code, format_flag=True) snip.save('snippet2.cpp') f = open('snippet2.cpp') snip2 = f.read() f.close() assert snip.get_content() == snip2 assert not snip.get_content() == code def test_cpp_snippet_compile_fail(): sh.Snippet.default_line_number = True code = """ #include int main(int argc, char **argv){ return 0 } """ code = code.replace(';\n', ';') try: sh.Snippet(code, compile_flag=True) raise RuntimeError("compilation error not detected") - except sh.Snippet.CompilationError as e: + except sh.Snippet.CompilationError: pass except Exception as e: raise RuntimeError('wrong exception:' + str(e)) def test_cpp_snippet_compile(): sh.Snippet.default_line_number = True code = """ #include int main(int argc, char **argv){ return 0; } """ code = code.replace(';\n', ';') try: sh.Snippet(code, compile_flag=True) except Exception as e: raise RuntimeError('should compile: ' + str(e))