Pygments support for markslider
This commit is contained in:
@@ -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.
@@ -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']
|
||||
|
||||
Reference in New Issue
Block a user