Pygments support for markslider

This commit is contained in:
ville rantanen
2019-06-16 12:00:36 +03:00
parent 768ee7773b
commit 50d9b96f00
3 changed files with 140 additions and 26 deletions

View File

@@ -20,7 +20,7 @@
'''Markslider: a slideshow engine based on markdown.'''
__author__ = "Ville Rantanen <ville.q.rantanen@gmail.com>"
__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()

Binary file not shown.

View File

@@ -81,6 +81,7 @@ def parse(data):
block=new_block
return data
def colorize(data, remove_colors = False, dark_colors = False, debug = False):
# Start inserting colors, and printing
bc = ansi.code()
@@ -99,7 +100,10 @@ def colorize(data,remove_colors=False,dark_colors=False,debug=False):
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)
else:
@@ -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']