revamping markdown libraries

This commit is contained in:
q
2016-06-06 23:45:23 +03:00
parent 543820b04b
commit 0ced78d059
6 changed files with 426 additions and 265 deletions

View File

@@ -1 +1 @@
../reporting/md-color.py ../reporting/md_color.py

View File

@@ -1,7 +1,7 @@
# Python library for ansi colorization # Python library for ansi colorization
import re import re,sys
class ansi: class code:
K="\033[1;30m" K="\033[1;30m"
R="\033[1;31m" R="\033[1;31m"
G="\033[1;32m" G="\033[1;32m"
@@ -59,7 +59,7 @@ class ansi:
sys.stdout.write( self.pos(y,x) + str(s) ) sys.stdout.write( self.pos(y,x) + str(s) )
def clear(self): def clear(self):
sys.stdout.write( self.CLR+self.pos(0,0) ) sys.stdout.write( self.CLRSCR+self.pos(0,0) )
def clear_to_end(self): def clear_to_end(self):
sys.stdout.write( self.CLREND ) sys.stdout.write( self.CLREND )
def clear_to_beginning(self): def clear_to_beginning(self):

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
# coding=utf-8 # coding=utf-8
# #
# Copyright 2015 Ville Rantanen # Copyright 2016 Ville Rantanen
# #
# This program is free software: you can redistribute it and/or modify it # This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published # under the terms of the GNU Lesser General Public License as published
@@ -20,84 +20,17 @@
'''Markslider: a slideshow engine based on markdown.''' '''Markslider: a slideshow engine based on markdown.'''
__author__ = "Ville Rantanen <ville.q.rantanen@gmail.com>" __author__ = "Ville Rantanen <ville.q.rantanen@gmail.com>"
__version__ = "0.6" __version__ = "0.7"
import sys,os,argparse,re import sys,os,argparse,re
from argparse import ArgumentParser from argparse import ArgumentParser
import traceback,tty,termios,subprocess,signal import traceback,tty,termios,subprocess,signal
sys.path.append(os.path.dirname(os.path.realpath(__file__)))
import ansi,md_color
HL=">" HL=">"
EOS="# End of Slides" EOS="# End of Slides"
class bc:
K="\033[1;30m"
R="\033[1;31m"
G="\033[1;32m"
B="\033[1;34m"
Y="\033[1;33m"
M="\033[1;35m"
C="\033[1;36m"
W="\033[1;37m"
k="\033[30m"
r="\033[31m"
g="\033[32m"
b="\033[34m"
y="\033[33m"
m="\033[35m"
c="\033[36m"
w="\033[37m"
S = '\033[1m'
U = '\033[4m'
Z = '\033[0m'
CLR = '\033[2J'
CLREND = '\033[K'
CLRBEG = '\033[1K'
color_keys="KRGBYMCWkrgbymcwSUZ"
color_list=[K,R,G,B,Y,M,C,W,k,r,g,b,y,m,c,w,S,U,Z]
def pos(self,y,x):
return "\033["+str(y)+";"+str(x)+"H"
def column(self,x):
return "\033["+str(x)+"G"
def posprint(self, y,x,s):
sys.stdout.write( self.pos(y,x) + str(s) )
def clear(self):
sys.stdout.write( self.CLR+self.pos(0,0) )
def clear_to_end(self):
sys.stdout.write( self.CLREND )
def clear_to_beginning(self):
sys.stdout.write( self.CLRBEG )
def up(self,n=1):
sys.stdout.write( "\033["+str(n)+"A" )
def down(self,n=1):
sys.stdout.write( "\033["+str(n)+"B" )
def right(self,n=1):
sys.stdout.write( "\033["+str(n)+"C" )
def left(self,n=1):
sys.stdout.write( "\033["+str(n)+"D" )
def up_line(self,n=1):
sys.stdout.write( "\033["+str(n)+"F" )
def down_line(self,n=1):
sys.stdout.write( "\033["+str(n)+"E" )
def save(self):
sys.stdout.write( "\033[s" )
def restore(self):
sys.stdout.write( "\033[u" )
def color_string(self,s):
for i,c in enumerate(self.color_keys):
s=s.replace("${"+c+"}",self.color_list[i])
return s
def nocolor_string(self,s):
for i,c in enumerate(self.color_keys):
s=s.replace("${"+c+"}","")
return s
class getch: class getch:
def get(self): def get(self):
fd = sys.stdin.fileno() fd = sys.stdin.fileno()
@@ -226,14 +159,14 @@ class slide_reader:
self.data.insert(self.opts.toc_page-1,TOC) self.data.insert(self.opts.toc_page-1,TOC)
def launch(self,s): def launch(self,s):
""" Launch in a string using tags $!command$! """ Launch in a string using tags `command`>
Remove empty lines from beginning and end of stdout. Remove empty lines from beginning and end of stdout.
""" """
if not self.opts.execute_read: if not self.opts.execute_read:
return [s] return [s]
if s.find("$>")==-1: if s.find("`>")==-1:
return [s] return [s]
command=re.match("(.*)\$>(.*)\$>(.*)",s) command=re.match("(.*)`(.*)`>(.*)",s)
if command != None: if command != None:
output = subprocess.check_output(command.group(2).strip(),shell=True).split("\n") output = subprocess.check_output(command.group(2).strip(),shell=True).split("\n")
while len(output[0].strip())==0: while len(output[0].strip())==0:
@@ -267,8 +200,8 @@ Special syntaxes:
* Colors: insert string ${C}, where C is one of KRGBYMCWkrgbymcwSUZ * Colors: insert string ${C}, where C is one of KRGBYMCWkrgbymcwSUZ
* Text before first "# header" is not shown * Text before first "# header" is not shown
* Text after a "# End of Slides" is not shown * Text after a "# End of Slides" is not shown
* Execute shell: "$! command -switch $!" Beware of malicious code! * Execute shell: "` command -switch `!" Beware of malicious code!
* Execute and print output: "$> command $>" Beware of malicious code! * Execute and print output: "` command `>" Beware of malicious code!
Keyboard shortcuts: Keyboard shortcuts:
'''+get_interactive_help_text() '''+get_interactive_help_text()
@@ -282,7 +215,7 @@ Keyboard shortcuts:
parser.add_argument("--dc",action="store_true",dest="dark_colors",default=False, parser.add_argument("--dc",action="store_true",dest="dark_colors",default=False,
help="Use dark colorscheme, better for white background terminals.") help="Use dark colorscheme, better for white background terminals.")
parser.add_argument("-e",action="store_true",dest="execute",default=False, parser.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!") help="Execute commands in `! or `> tags at show time with Enter key. WARNING: Potentially very dangerous to run others' slides with this switch!")
parser.add_argument("-E",action="store_true",dest="execute_read",default=False, parser.add_argument("-E",action="store_true",dest="execute_read",default=False,
help="Execute commands in $> tags at file read time. WARNING: Potentially very dangerous to run others' slides with this switch!") help="Execute commands in $> tags at file read time. WARNING: Potentially very dangerous to run others' slides with this switch!")
parser.add_argument("-m",action="store_true",dest="autocolor",default=False, parser.add_argument("-m",action="store_true",dest="autocolor",default=False,
@@ -324,23 +257,28 @@ def page_print(reader,opts,offset):
print(colorify(coloring+page[0],opts)) print(colorify(coloring+page[0],opts))
# Print page rows # Print page rows
parsed=md_color.parse(page)
colored=md_color.colorize(parsed,not opts.color,opts.dark_colors)
r=0 r=0
for row in page[1+offset[0]:]: for row_i in range(len(page)):
if row_i==0: continue
if row_i<offset[0]: continue
row=page[row_i]
#page[1+offset[0]:]:
if not opts.wrap: if not opts.wrap:
row=cut_line(row,scrsize[1]-1) row=cut_line(row,scrsize[1]-1)
row_lines=0 row_lines=0
else: else:
row_lines=int(float(len(row))/scrsize[1]) row_lines=int(float(len(row))/scrsize[1])
colored=colorify(row,opts) colored_row=colored[row_i]#=colorify(row,opts)
if offset[1]==r+1+offset[0]: if offset[1]==r+1+offset[0]:
colored=add_highlight(row,opts) colored_row=add_highlight(row,opts)
sys.stdout.write(colored) sys.stdout.write(colored_row)
if r>=scrsize[0]-2: if r>=scrsize[0]-2:
break break
r+=row_lines+1 r+=row_lines+1
sys.stdout.write("\n") sys.stdout.write("\n")
return return
def menu_print(reader,opts): def menu_print(reader,opts):
@@ -466,46 +404,9 @@ def colorify(s,opts):
""" Add colors to string """ """ Add colors to string """
if not opts.color: if not opts.color:
return bc.nocolor_string(s) return bc.nocolor_string(s)
if opts.autocolor and not s.startswith("${"):
rules=["(^\s*\*.*)", # * bullets
"(^\s*[0-9]+\..*)", # 1. ordered
"(^#.*)", ## Header
"(^\s\s\s\s[^\*0-9\s].*)", # code block
"(\`[^\s]*[^\`]+\`)", # code inline
"(\$[>!].*\$[>!])", # code tags
"(\[[^]]+\]\([^\)]+\))", # [link](url)
"(\*{1,2}[^\s]*[^\*\s]+\*{1,2})", # *bold*
"(_[^\s]*[^_\s]+_)", # _bold_
"(<[^>]+>)"] # <Tags>
if opts.dark_colors:
colors=["${r}\\1", # * bullets
"${r}\\1", # 1. ordered
"${U}${b}\\1", ## Header
"${m}\\1", # code block
"${m}\\1${Z}", # code inline
"${m}\\1${Z}", # code tags
"${B}${U}\\1${Z}", # [link](url)
"${W}\\1${Z}", # *bold*
"${W}\\1${Z}", # _bold_
"${K}\\1${Z}"] # <Tags>
else:
colors=["${y}\\1", # * bullets
"${y}\\1", # 1. ordered
"${U}${Y}\\1", ## Header
"${c}\\1", # code block
"${c}\\1${Z}", # code inline
"${c}\\1${Z}", # code tags
"${B}${U}\\1${Z}", # [link](url)
"${W}\\1${Z}", # *bold*
"${W}\\1${Z}", # _bold_
"${K}\\1${Z}"] # <Tags>
for r in zip(rules,colors):
s=re.sub(r[0],r[1],s)
# Replace executable commands with $ only in the beginning
s=re.sub("\$[>!]","$",s,1)
s=re.sub("\$[>!]","",s)
c=bc.color_string(s)+bc.Z c=bc.color_string(s)+bc.Z
return c return c
def cut_line(s,i): def cut_line(s,i):
""" cut a color tagged string, and remove control chars """ """ cut a color tagged string, and remove control chars """
s=s[:i] s=s[:i]
@@ -533,11 +434,11 @@ def launch(reader,opts,offset):
s=reader.get_current_page()[offset[1]] s=reader.get_current_page()[offset[1]]
urls = re.findall('http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+', s) urls = re.findall('http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+', s)
images = re.findall('!\[[^]]+\]\([^\)]+\)', s) images = re.findall('!\[[^]]+\]\([^\)]+\)', s)
if s.find("$!")==-1 and s.find("$>")==-1 and len(urls)==0 and len(images)==0: if s.find("`")==-1 and len(urls)==0 and len(images)==0:
return return
run_command=re.match("(.*)\$!(.*)\$!(.*)",s) run_command=re.match("(.*)`(.*)`!(.*)",s)
show_command=re.match("(.*)\$>(.*)\$>(.*)",s) show_command=re.match("(.*)`(.*)`>(.*)",s)
if show_command != None: if show_command != None:
output = subprocess.check_output(show_command.group(2).strip(),shell=True).split("\n") output = subprocess.check_output(show_command.group(2).strip(),shell=True).split("\n")
while len(output[0].strip())==0: while len(output[0].strip())==0:
@@ -571,7 +472,7 @@ def launch(reader,opts,offset):
shell=True) shell=True)
return return
return return
bc=bc() bc=ansi.code()
getch=getch() getch=getch()
opts=setup_options() opts=setup_options()
browser(opts,opts.filename) browser(opts,opts.filename)

View File

@@ -1,137 +0,0 @@
#!/usr/bin/env python
import sys,os,re
from argparse import ArgumentParser
sys.path.append(os.path.dirname(os.path.realpath(__file__)))
import bc
__author__ = "Ville Rantanen <ville.q.rantanen@gmail.com>"
__version__ = "0.1"
''' Rules modified from mistune project '''
def setup_options():
''' Create command line options '''
usage='''
Color notation renderer in ANSI codes
Special syntaxes:
* Colors: insert string ${C}, where C is one of KRGBYMCWkrgbymcwSUZ
'''
parser=ArgumentParser(description=usage,
epilog=__author__)
parser.add_argument("-v","--version",action="version",version=__version__)
parser.add_argument("-D",action="store_true",dest="debug",default=False,
help="Debug mode")
parser.add_argument("--no-color","-n",action="store_false",dest="color",default=True,
help="Disable color.")
parser.add_argument("-z",action="store_true",dest="zero",default=False,
help="Reset coloring at the end of each line.")
parser.add_argument("filename",type=str,
help="File to show, - for stdin")
opts=parser.parse_args()
return opts
block_match={
'block_code': (re.compile(r'^( {4}[^*])(.*)$'),'${c}\\1\\2','${Z}${c}'),
'multiline_code' : (re.compile(r'^ *(`{3,}|~{3,}) *(\S*)'),'${c}\\1\\2','${Z}${c}'), # ```lang
'block_quote': (re.compile(r'^(>[ >]* )'),'${K}\\1${Z}','${Z}'),
'hrule': (re.compile(r'^ {0,3}[-*_]([-*_]){2,}$'),False,'${Z}'),
'heading' : (re.compile(r'^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)'),'${W}\\1 ${U}\\2','${W}${U}'),
'lheading' : (re.compile(r'^(=+|-+)$'),'${W}\\1','${W}',(-1,re.compile(r'^([^\n]+)'),'${W}\\1')),
'list_bullet':(re.compile(r'^( *)([*+-]|[\d\.]+)( +)'),'\\1${y}\\2${Z}\\3','${Z}'),
'list_loose': (None,False,'${Z}'),
'text': (re.compile(r'^[^\n]+'),False,'${Z}'),
'empty': (re.compile(r'^$'),False,'${Z}'),
}
blocks=['block_quote', 'multiline_code','hrule', 'heading','lheading','list_bullet', 'block_code', 'text', 'empty']
inline_match={
'bold1': (re.compile(r'(^| )(_[^_]+_)'), '${W}\\1\\2'), # _bold_
'bold2': (re.compile(r'(^| )(\*{1,2}[^\*]+\*{1,2})'), '${W}\\1\\2'), # **bold**
'code': (re.compile(r'([`]+[^`]+[`]+)'),'${c}\\1'), # `code`
'link': (re.compile(r'(\[[^\]]+\]\([^\)]+\))'),'${B}${U}\\1'), # [text](link)
'image': (re.compile(r'(!\[[^\]]+\]\([^\)]+\))'),'${r}\\1'), # ![text](image)
'underline': (re.compile(r'(^|\W)(__)([^_]+)(__)'), '\\1\\2${U}\\3${Z}\\4'), # __underline__
'strikethrough': (re.compile(r'(~~)([^~]+)(~~)'),'\\1${st}\\2${so}\\3'), # ~~strike~~
}
inlines=['bold1','bold2','code','image','link','underline','strikethrough']
bc=bc.ansi()
opts=setup_options()
if opts.filename=="-":
f=sys.stdin
else:
f=open(opts.filename,'r')
data=[]
# Read data
for row in f:
if not row:
continue
row=row.decode('utf-8').rstrip("\n\r ")
data.append([None,row])
block='text'
new_block='text'
multiline_block=False
# Parse styles
for i,line in enumerate(data):
row=line[1]
if line[0] is not None:
# Previous lines have set the style already
continue
for match in blocks:
if block_match[match][0].match(row):
new_block=match
if match.startswith('multiline'):
if multiline_block:
multiline_block=False
else:
multiline_block=match
break
if multiline_block:
new_block=multiline_block
# Lists must end with empty line
if new_block not in ('empty','list_bullet') and block.startswith('list_'):
new_block='list_loose'
if len(block_match[match])>3:
# Style sets block in previous or next lines
data[i+block_match[match][3][0]][0]=new_block
data[i+block_match[match][3][0]][1]=block_match[match][3][1].sub(
block_match[match][3][2], data[i+block_match[match][3][0]][1])
data[i][0]=new_block
if new_block!=block:
block=new_block
# Start inserting colors, and printing
for i,line in enumerate(data):
row=line[1]
block=line[0]
multiline_block=block.startswith('multiline')
if not multiline_block:
sys.stdout.write(bc.Z)
#print(multiline_block)
if block_match[block][1]:
row=block_match[block][0].sub(block_match[block][1],row)
if not (multiline_block or match=='block_code'):
for match in inlines:
if inline_match[match][0].search(row):
row=inline_match[match][0].sub(inline_match[match][1]+block_match[block][2],row)
if opts.color:
colored=bc.color_string(row)
else:
colored=bc.nocolor_string(row)
if opts.debug:
multistr="*" if multiline_block else " "
colored="{:<18}{:}:".format(data[i][0],multistr)+colored
sys.stdout.write(colored.encode('utf-8'))
if opts.zero:
sys.stdout.write(bc.Z)
sys.stdout.write("\n")

185
reporting/md_color.py Executable file
View File

@@ -0,0 +1,185 @@
#!/usr/bin/env python
import sys,os,re
from argparse import ArgumentParser
sys.path.append(os.path.dirname(os.path.realpath(__file__)))
import ansi
__author__ = "Ville Rantanen <ville.q.rantanen@gmail.com>"
__version__ = "0.2"
''' Rules modified from mistune project '''
def setup_options():
''' Create command line options '''
usage='''
Markdown syntax color in ansi codes.
Special syntaxes:
* Colors: insert string ${C}, where C is one of KRGBYMCWkrgbymcwSUZ
* Any ANSI control code: ${3A}, ${1;34;42m}, etc..
'''
parser=ArgumentParser(description=usage,
epilog=__author__)
parser.add_argument("-v","--version",action="version",version=__version__)
parser.add_argument("-D",action="store_true",dest="debug",default=False,
help="Debug mode")
parser.add_argument("--dc",action="store_true",dest="dark_colors",default=False,
help="Use dark colorscheme, better for white background terminals.")
parser.add_argument("--no-color","-n",action="store_false",dest="color",default=True,
help="Disable color.")
parser.add_argument("-z",action="store_true",dest="zero",default=False,
help="Reset coloring at the end of each line.")
parser.add_argument("filename",type=str,
help="File to show, - for stdin")
opts=parser.parse_args()
return opts
def parse(data):
data=[[None,row] for row in data]
block='text'
new_block='text'
multiline_block=False
# Parse styles
for i,line in enumerate(data):
row=line[1]
if line[0] is not None:
# Previous lines have set the style already
continue
for match in blocks:
if block_match[match]['re'].match(row):
new_block=match
if match.startswith('multiline'):
if multiline_block:
multiline_block=False
else:
multiline_block=match
break
if multiline_block:
new_block=multiline_block
# Lists must end with empty line
if new_block not in ('empty','list_bullet') and block.startswith('list_'):
new_block='list_loose'
if 'mod' in block_match[match]:
# Style sets block in previous or next lines
data[i+block_match[match]['mod']['pos']][0]=block_match[match]['mod']['name']
data[i][0]=new_block
if new_block!=block:
block=new_block
return data
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')
if multiline_block:
row=block_match[block][csc]+row
if block_match[block][cs]:
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'):
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)
if remove_colors:
colored=bc.nocolor_string(row)
else:
colored=bc.color_string(row)
if debug:
multistr="*" if multiline_block else " "
colored="{:<18}{:}:".format(data[i][0],multistr)+colored
colorized.append(colored)
return colorized
# re: regular expression, bc: subract value bright colors, bcc: continue with this color after inline
block_match={
'block_code': {'re':re.compile(r'^( {4}[^*])(.*)$'),
'bc' :'${Z}${c}\\1\\2', 'bcc':'${Z}${c}',
'dc' :'${Z}${m}\\1\\2', 'dcc':'${Z}${m}'}, # code
'multiline_code' : {'re':re.compile(r'^ *(`{3,}|~{3,}) *(\S*)'),
'bc' :'${Z}${c}\\1\\2', 'bcc':'${Z}${c}',
'dc' :'${Z}${m}\\1\\2', 'dcc':'${Z}${m}'}, # ```lang
'block_quote': {'re':re.compile(r'^(>[ >]* )'),
'bc':'${K}\\1${Z}','bcc':'${Z}',
'dc':'${Y}\\1${Z}','dcc':'${Z}'}, # > > quote
'hrule': {'re':re.compile(r'^ {0,3}[-*_]([-*_]){2,}$'),
'bc':False,'bcc':'${Z}',
'dc':False,'dcc':'${Z}'}, # ----
'heading' : {'re':re.compile(r'^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)'),
'bc':'${W}\\1 ${U}\\2','bcc':'${W}${U}',
'dc':'${B}\\1 ${U}\\2','dcc':'${B}${U}'}, # # heading
'lheading' : {'re':re.compile(r'^(=+|-+)$'),
'bc':'${W}\\1', 'bcc':'${W}',
'dc':'${B}\\1', 'dcc':'${B}',
'mod':{'pos':-1,'name':'lheading.mod'}}, # ======= under header
'lheading.mod' : {'re':re.compile(r'^([^\n]+)'),
'bc':'${W}\\1', 'bcc':'${W}',
'dc':'${B}\\1', 'dcc':'${B}'}, # over the ======= under header
'list_bullet': {'re':re.compile(r'^( *)([*+-]|[\d\.]+)( +)'),
'bc':'\\1${y}\\2${Z}\\3','bcc':'${Z}',
'dc':'\\1${r}\\2${Z}\\3','dcc':'${Z}'}, # * or 1.
'list_loose': {'re':None,
'bc':False,'bcc':'${Z}',
'dc':False,'dcc':'${Z}'},
'text': {'re':re.compile(r'^([^\n]+)'),
'bc':'${Z}\\1','bcc':'${Z}',
'dc':'${Z}\\1','dcc':'${Z}'},
'empty': {'re':re.compile(r'(^$)'),
'bc':'${Z}\\1','bcc':'${Z}',
'dc':'${Z}\\1','dcc':'${Z}'},
}
blocks=['block_quote', 'multiline_code','hrule', 'heading','lheading','list_bullet', 'block_code', 'text', 'empty']
inline_match={
'bold1': {'re':re.compile(r'(^| )(_[^_]+_)'),
'bc':'${W}\\1\\2','dc':'${W}\\1\\2'}, # _bold_
'bold2': {'re':re.compile(r'(^| )(\*{1,2}[^\*]+\*{1,2})'),
'bc':'${W}\\1\\2','dc':'${W}\\1\\2'}, # **bold**
'code': {'re':re.compile(r'([`]+[^`]+[`]+)'),
'bc':'${c}\\1','dc':'${m}\\1'}, # `code`
'code_special': {'re':re.compile(r'([`]+[^`]+[`]+)([!>])'),
'bc':'${c}\\1${g}\\2','dc':'${m}\\1${r}\\2'}, # `code`! or `code`> for markslider
'link': {'re':re.compile(r'(\[)([^\]]+)(\])(\([^\)]+\))'),
'bc':'${b}\\1${Z}\\2${b}\\3${U}\\4',
'dc':'${b}\\1${Z}\\2${b}\\3${U}\\4'}, # [text](link)
'image': {'re':re.compile(r'(!\[[^\]]+\]\([^\)]+\))'),
'bc':'${r}\\1','dc':'${g}\\1'}, # ![text](image)
'underline': {'re':re.compile(r'(^|\W)(__)([^_]+)(__)'),
'bc':'\\1\\2${U}\\3${Z}\\4','dc':'\\1\\2${U}\\3${Z}\\4'}, # __underline__
'strikethrough': {'re':re.compile(r'(~~)([^~]+)(~~)'),
'bc':'\\1${st}\\2${so}\\3','dc':'\\1${st}\\2${so}\\3'}, # ~~strike~~
}
inlines=['bold1','bold2','code_special','code','image','link','underline','strikethrough']
if __name__ == "__main__":
opts=setup_options()
if opts.filename=="-":
f=sys.stdin
else:
f=open(opts.filename,'r')
data=[]
# Read data
for row in f:
if not row:
continue
row=row.decode('utf-8').rstrip("\n\r ")
data.append(row)
data=parse(data)
colored=colorize(data,not opts.color,opts.dark_colors,opts.debug)
for c in colored:
sys.stdout.write(c.encode('utf-8'))
if opts.zero:
sys.stdout.write(bc.Z)
sys.stdout.write("\n")

212
reporting/srcframes2ans Executable file
View File

@@ -0,0 +1,212 @@
#!/usr/bin/env python
# coding=utf-8
#
# Copyright 2016 Ville Rantanen
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU Lesser 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
'''Color by notation.'''
__author__ = "Ville Rantanen <ville.q.rantanen@gmail.com>"
__version__ = "0.2"
NEWCHAR="====CHAR"
NEWCOLOR="====COLOR"
NEWIMAGE="====EOI"
ENDOFFILE="====EOF"
PAUSE="====PAUSE"
import sys,os,argparse,re,time
from argparse import ArgumentParser
class bc:
K="\033[1;30m"
R="\033[1;31m"
G="\033[1;32m"
Y="\033[1;33m"
B="\033[1;34m"
M="\033[1;35m"
C="\033[1;36m"
W="\033[1;37m"
k="\033[0;30m"
r="\033[0;31m"
g="\033[0;32m"
y="\033[0;33m"
b="\033[0;34m"
m="\033[0;35m"
c="\033[0;36m"
w="\033[0;37m"
nk="\033[30m"
nr="\033[31m"
ng="\033[32m"
ny="\033[33m"
nb="\033[34m"
nm="\033[35m"
nc="\033[36m"
nw="\033[37m"
bk="\033[40m"
br="\033[41m"
bg="\033[42m"
by="\033[43m"
bb="\033[44m"
bm="\033[45m"
bc="\033[46m"
bw="\033[47m"
S = '\033[1m'
U = '\033[4m'
Z = '\033[0m'
CLR = '\033[2J'
CLREND = '\033[K'
CLRSCR = CLR+"\033[0;0H"
color_keys="PQWERTYU01234567XCZV;asdfghj)!@#$%^&"
color_list=[K, R, G, Y, B, M, C, W, k, r, g, y, b, m, c, w,
S,CLRSCR,Z,U,bk,br,bg,by,bb,bm,bc,bw,nk,nr,ng,ny,nb,nm,nc,nw ]
def pos(self,y,x):
return "\033["+str(y)+";"+str(x)+"H"
def posprint(self, y,x,s):
sys.stdout.write( (self.pos(y,x) + str(s)).encode('utf-8') )
def clear(self):
sys.stdout.write( (self.CLR+self.pos(0,0)).encode('utf-8') )
def clear_to_end(self):
sys.stdout.write( self.CLREND.encode('utf-8') )
def color_char(self,s):
for i,c in enumerate(self.color_keys):
if c in s:
s=s.replace(c,self.color_list[i])
return s
return ""
def nocolor_string(self,s):
return ""
def setup_options():
''' Create command line options '''
usage='''
Color notation renderer in ANSI codes
Special syntaxes:
* Colors: insert string ${C}, where C is one of KRGBYMCWkrgbymcwSUZ
'''
parser=ArgumentParser(description=usage,
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog=__author__)
parser.add_argument("-v","--version",action="version",version=__version__)
parser.add_argument("--no-color","-n",action="store_false",dest="color",default=True,
help="Disable color.")
parser.add_argument("-z",action="store_true",dest="zero",default=False,
help="Reset coloring at the end of each line.")
parser.add_argument("-c",action="store_true",dest="clear",default=False,
help="Clear screen first")
parser.add_argument("filename",type=str,
help="File to show")
opts=parser.parse_args()
return opts
bc=bc()
opts=setup_options()
if opts.filename=='-':
f=sys.stdin
else:
f=open(opts.filename,'r')
if opts.clear:
bc.clear()
while True:
pause=0
gray=[]
gray.append([])
colors=[]
colorFrame=0
grayFrame=0
maxRow=0
for row in f:
if not row:
sys.exit(0)
row=row.decode('utf-8').rstrip("\n\r")
if row.startswith(NEWIMAGE):
break
if row.startswith(PAUSE):
try:
new_value=row[len(PAUSE):].strip()
pause=float(new_value)
except:
pause=0
continue
if row.startswith(NEWCOLOR):
colorFrame+=1
colors.append([])
continue
if colorFrame==0:
if row.startswith(NEWCHAR):
grayFrame+=1
gray.append([])
continue
gray[grayFrame].append(row)
maxRow=max(maxRow, len(row))
else:
colors[colorFrame-1].append(row)
if len(gray[0])==0:
sys.exit(0)
for i in range(len(gray[0])):
while maxRow>len(gray[0][i]):
gray[0][i]=gray[0][i]+" "
for i in range(len(gray[0])):
for frame in colors:
if len(frame)<i+1:
frame.append('')
while len(gray[0][i])>len(frame[i]):
frame[i]=frame[i]+" "
if len(gray)>1:
for layer in gray[1:]:
if len(layer)<i+1:
layer.append('')
while len(gray[0][i])>len(layer[i]):
layer[i]=layer[i]+" "
for i in range(len(gray[0])):
for c in range(len(gray[0][i])):
if opts.color:
for frame in colors:
try:
if frame[i][c]!=" ":
sys.stdout.write(bc.color_char(frame[i][c]).encode('utf-8'))
except IndexError:
pass
char=" "
for layer in gray:
if layer[i][c]==" ": continue
char=layer[i][c]
sys.stdout.write(char.encode('utf-8'))
if opts.color and opts.zero:
sys.stdout.write(bc.Z.encode('utf-8'))
sys.stdout.write("\n")
if pause>0:
time.sleep(pause)