From 50d9b96f00891ff201f343148f4b6744649a862a Mon Sep 17 00:00:00 2001 From: ville rantanen Date: Sun, 16 Jun 2019 12:00:36 +0300 Subject: [PATCH] Pygments support for markslider --- reporting/markslider.py | 125 +++++++++++++++++++++++++++++++++--- reporting/markslider.tar.gz | Bin 12137 -> 12906 bytes reporting/md_color.py | 41 +++++++----- 3 files changed, 140 insertions(+), 26 deletions(-) diff --git a/reporting/markslider.py b/reporting/markslider.py index c1d4964..65c42fc 100755 --- a/reporting/markslider.py +++ b/reporting/markslider.py @@ -20,7 +20,7 @@ '''Markslider: a slideshow engine based on markdown.''' __author__ = "Ville Rantanen " -__version__ = "1.2.1" +__version__ = "1.3" import sys,os,argparse,re,datetime from argparse import ArgumentParser @@ -68,6 +68,16 @@ class slide_reader: #~ self.control_char_re = re.compile('[%s]' % re.escape(self.control_chars)) self.background = [] self.read() + self.pygments = False + if opts.syntax_pygments: + try: + self.pygments = Pygmentizer( + opts.syntax_formatter, + opts.syntax_style + ) + except ImportError as e: + self.pygments = False + def read(self): ''' Read a file, set pages and data ''' @@ -278,6 +288,59 @@ class slide_reader: if titles[page[0]] > 1: page[0] += " [%d/%d]"%( page_no, titles[page[0]] ) +class Pygmentizer(): + def __init__(self, formatter, style): + import pygments + import pygments.lexers + import pygments.formatters + import pygments.styles + self.pygments = pygments + self.lexers = pygments.lexers + self.formatters = pygments.formatters + self.styles = pygments.styles + + self.style = self.styles.get_style_by_name(style) + self.formatter = self.formatters.get_formatter_by_name( + formatter, + style = self.style + ) + self.lexer = None + + + def format(self, code): + in_block = False + blocks = [] + current_block = -1 + for i, row in enumerate(code): + if row.startswith("```"): + in_block = not in_block + lexer_name = row.replace("```","").strip() + if len(lexer_name) == 0: + in_block = False + if in_block: + blocks.append({ + "lexer": lexer_name, + "code": [], + "rows": [] + }) + current_block += 1 + else: + if in_block: + blocks[current_block]["code"].append(row) + blocks[current_block]["rows"].append(i) + + preformatted_rows = [] + for block in blocks: + lexer = self.lexers.get_lexer_by_name(block["lexer"]) + tokens = self.pygments.lex("\n".join(block["code"]), lexer) + formatted = self.pygments.format(tokens, self.formatter) + # ~ print(block["rows"]) + # ~ print(formatted.split("\n")) + for row, formatted_row in zip(block["rows"], formatted.split("\n")): + code[row] = formatted_row + preformatted_rows.append(row) + return code, preformatted_rows + def get_interactive_help_text(): return ''' left/right,page up/down,home,end @@ -331,6 +394,23 @@ Keyboard shortcuts: help="Disable color.") content.add_argument("--no-rename","--nr",action="store_false",dest="rename_title", default=True, help="Disable automatic renaming of duplicate titles.") + content.add_argument("--toc",action="store",dest="toc",default=False, + const="Table of Contents", type=str, nargs='?', + help="Insert table of contents. Define the header, or use default: %(const)s") + content.add_argument("--toc-page",action="store",dest="toc_page",default=2, type=int, + help="Insert table of contents on a chosen page. default: %(const)s") + content.add_argument("--toc-depth",action="store",dest="toc_depth",default=2, type=int, + choices=list(range(1,5)), + help="Table of contents display depth. default: %(const)s") + + content.add_argument("--no-pygments",action="store_false",dest="syntax_pygments",default = True, + help="Disable autocoloring syntax with Pygments. Used only for ``` code blocks, if language is mentioned, ex.: ```python . Note! Do not have empty lines after ```") + content.add_argument("--syntax-formatter",action="store",dest="syntax_formatter",default = "terminal256", + choices=['terminal', 'terminal256', 'terminal16m'], + help="Syntax highlighter formatter. default: %(default)s") + content.add_argument("--syntax-style",action="store",dest="syntax_style",default = "monokai", + help="Syntax highlighter style, see Pygments styles. default: %(default)s") + execution.add_argument("-e",action="store_true",dest="execute",default=False, help="Execute commands in `! or `> tags at show time with Enter key. WARNING: Potentially very dangerous to run others' slides with this switch!") @@ -347,14 +427,7 @@ Keyboard shortcuts: content.add_argument("-w",action="store_false",dest="wrap",default=True, help="Disable line wrapping. Cuts long lines.") - content.add_argument("--toc",action="store",dest="toc",default=False, - const="Table of Contents", type=str, nargs='?', - help="Insert table of contents. Define the header, or use default: %(const)s") - content.add_argument("--toc-page",action="store",dest="toc_page",default=2, type=int, - help="Insert table of contents on a chosen page. default: %(const)s") - content.add_argument("--toc-depth",action="store",dest="toc_depth",default=2, type=int, - choices=list(range(1,5)), - help="Table of contents display depth. default: %(const)s") + parser.add_argument("files",type=str, nargs='+', help="File(s) to show") opts=parser.parse_args() @@ -365,6 +438,7 @@ Keyboard shortcuts: opts.exit_last=True return opts + def page_print(reader,opts,offset): ''' Print a page ''' @@ -407,6 +481,22 @@ def page_print(reader,opts,offset): page = [cut_line(row,scrsize[1]-1) for row in page] parsed = md_color.parse(page) if opts.autocolor: + if reader.pygments: + + # ~ to_pygmentize = [] + # ~ pygmented_rows = [] + # ~ for token_i in range(len(parsed)): + # ~ if parsed[token_i][0] == 'multiline_code': + # ~ to_pygmentize.append(parsed[token_i][1]) + # ~ pygmented_rows.append(token_i) + # ~ if len(to_pygmentize) > 0: + preformatted, preformatted_rows = reader.pygments.format( + [x[1] for x in parsed] + ) + + for row_i in preformatted_rows: + parsed[row_i][0] = 'preformatted' + parsed[row_i][1] = preformatted[row_i] colored = md_color.colorize( parsed, not opts.color, @@ -440,6 +530,7 @@ def page_print(reader,opts,offset): sys.stdout.flush() return + def print_menu(reader,opts): bc.posprint( opts.size[0], 0, @@ -450,6 +541,7 @@ def print_menu(reader,opts): "slideshow" if opts.slideShow else ""), opts)) + def print_time(opts): now=datetime.datetime.now() bc.posprint( @@ -464,6 +556,7 @@ def print_time(opts): ) ) + def print_help(reader,opts): ''' Create a window with help message ''' helptext=get_interactive_help_text().split('\n') @@ -476,6 +569,7 @@ def print_help(reader,opts): sys.stdout.write(bc.pos(opts.size[0], opts.size[1])) inkey=getch.get() + def print_toc(reader,opts): ''' Create a window with TOC ''' text=reader.get_toc(display_position=True) @@ -506,16 +600,19 @@ def offset_change(opts,reader,offset,new_offset): offseth=min(reader.get_page_height(),new_offset[1]) return [max(0,o) for o in (offsety,offseth)] + def timeouthandler(sig,frame): #~ print(sig,frame) raise IOError("Input timeout") + def getkeypress(): try: return ord(getch.get()) except: return False + def browser(opts,files): ''' Main function for printing ''' @@ -617,10 +714,12 @@ def browser(opts,files): print(traceback.format_exc()) sys.exit(1) + def get_console_size(): rows, columns = os.popen('stty size', 'r').read().split() return (int(rows),int(columns)) + def colorify(s,opts): """ Add colors to string """ if not opts.color: @@ -628,6 +727,7 @@ def colorify(s,opts): c=bc.color_string(s)#+bc.Z return c + def cut_line(s,i): """ cut a color tagged string, and remove control chars """ s=s[:i] @@ -637,6 +737,7 @@ def cut_line(s,i): s))) return s + def add_highlight(s,opts): """ Add cursor position highlight """ if len(s.strip())==0: @@ -646,6 +747,7 @@ def add_highlight(s,opts): tagged="${Y}"+cleaned+"${Z}" return colorify(tagged,opts) + def launch(reader,opts,offset): """ Launch in a string using tags $!command$! or $>command$> Remove empty lines from beginning and end of stdout in $> commands. @@ -723,6 +825,7 @@ def launch(reader,opts,offset): return return + def modify_file(reader,offset): row=1 row_restarts=reader.file_start_page @@ -741,6 +844,7 @@ def modify_file(reader,offset): shell = True ) + def take_screenshot(reader,opts): out_file = os.path.join( opts.screenshots, @@ -758,12 +862,14 @@ def take_screenshot(reader,opts): shell = True ) + def get_open_command(): if sys.platform.startswith("darwin"): return "open" else: return "xdg-open" + def main(): global bc global getch @@ -797,5 +903,6 @@ def main(): os.path.basename(opts.screenshots), )) + if __name__ == "__main__": main() diff --git a/reporting/markslider.tar.gz b/reporting/markslider.tar.gz index 667a55455e5d0004df21957f9748ca22c184b5e5..11ce773d8e7434c7203d258fce9198c996d64961 100644 GIT binary patch literal 12906 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 Uc{b1H`R70X2b+w7jsWlg0A}?T761SM literal 12137 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 WN`>VA2m2nL0r|m0Awc&)K>q`H>bb`N diff --git a/reporting/md_color.py b/reporting/md_color.py index 180c14f..975fb36 100755 --- a/reporting/md_color.py +++ b/reporting/md_color.py @@ -81,32 +81,36 @@ def parse(data): block=new_block return data -def colorize(data,remove_colors=False,dark_colors=False,debug=False): + +def colorize(data, remove_colors = False, dark_colors = False, debug = False): # Start inserting colors, and printing - bc=ansi.code() - colorized=[] - cs='dc' if dark_colors else 'bc' - csc=cs+'c' - for i,line in enumerate(data): - row=line[1] - block=line[0] - multiline_block=block.startswith('multiline') + bc = ansi.code() + colorized = [] + cs = 'dc' if dark_colors else 'bc' + csc = cs + 'c' + for i, line in enumerate(data): + row = line[1] + block = line[0] + multiline_block = block.startswith('multiline') if multiline_block: - row=block_match[block][csc]+row + row = block_match[block][csc] + row if block_match[block][cs]: - row=block_match[block]['re'].sub(block_match[block][cs],row) + row = block_match[block]['re'].sub(block_match[block][cs], row) # No coloring inside block_code, nor multiline - if not (multiline_block or block=='block_code'): + if not (multiline_block or block == 'block_code'): for match in inlines: if inline_match[match]['re'].search(row): - row=inline_match[match]['re'].sub(inline_match[match][cs]+block_match[block][csc],row) + row = inline_match[match]['re'].sub( + inline_match[match][cs] + block_match[block][csc], + row + ) if remove_colors: - colored=bc.nocolor_string(row) + colored = bc.nocolor_string(row) else: - colored=bc.color_string(row) + colored = bc.color_string(row) if debug: - multistr="*" if multiline_block else " " - colored="{:<18}{:}:".format(data[i][0],multistr)+colored + multistr = "*" if multiline_block else " " + colored = "{:<18}{:}:".format(data[i][0], multistr) + colored colorized.append(colored) return colorized @@ -202,6 +206,9 @@ block_match_str={ 'empty': {'re':'(^$)', 'bc':'${Z}\\1','bcc':'${Z}', 'dc':'${Z}\\1','dcc':'${Z}'}, + 'preformatted': {'re': 'a^', # Never matches anything + 'bc':'','bcc':'', + 'dc':'','dcc':''}, } block_match=md_re_compile(block_match_str) blocks=['block_quote', 'multiline_code','hrule', 'heading','lheading','list_bullet', 'block_code', 'text', 'empty']