markmin and languages autolinks, thanks Vladyslav

This commit is contained in:
mdipierro
2012-07-30 20:23:05 -05:00
parent bac7e433c6
commit 041e0637bc
3 changed files with 181 additions and 77 deletions
+1 -1
View File
@@ -1 +1 @@
Version 2.00.0 (2012-07-30 16:25:32) dev
Version 2.00.0 (2012-07-30 20:23:00) dev
+137 -48
View File
@@ -71,15 +71,22 @@ a list with tables in it:
-----------:blockquoteclass[blockquoteid]
This this a new paragraph
with a table. Table has header and footer:
with a table. Table has header, footer, sections, odd and even rows:
-------------------------------
**Title 1**|**Title 2**|**Title 3**
==============================
data 1 | data 2 | 2.00
data 4 |data5(long)| 23.00
|data 8 | 33.50
data 3 |data4(long)| 23.00
|data 5 | 33.50
==============================
Total: | 3 items | 58.50
New section|New data | 5.00
data 1 |data2(long)|100.45
|data 3 | 12.50
data 4 | data 5 | .33
data 6 |data7(long)| 8.01
|data 8 | 514
==============================
Total: | 9 items |698,79
------------------------------:tableclass1[tableid2]
## Multilevel
@@ -515,14 +522,8 @@ regex_num=re.compile(r"^\s*[+-]?((\d+(\.\d*)?)|\.\d+)([eE][+-]?[0-9]+)?\s*$")
regex_list=re.compile('^(?:(#{1,6}|\.+|\++|\-+)(\.)?\s+)?(.*)$')
regex_bq_headline=re.compile('^(?:(\.+|\++|\-+)(\.)?\s+)?(-{3}-*)$')
regex_tq=re.compile('^(-{3}-*)(?::(?P<c>[a-zA-Z][_a-zA-Z\-\d]*)(?:\[(?P<p>[a-zA-Z][_a-zA-Z\-\d]*)\])?)?$')
regex_qr = re.compile(r'(?<!["\w>/=])qr:(?P<k>\w+://[\w\d\-+?&%/:.]+)',re.M)
regex_embed = re.compile(r'(?<!["\w>/=])embed:(?P<k>\w+://[\w\d\-+_=?%&/:.]+)', re.M)
regex_iframe = re.compile(r'(?<!["\w>/=])iframe:(?P<k>\w+://[\w\d\-+=?%&/:.]+)', re.M)
regex_auto_image = re.compile(r'(?<!["\w>/=])(?P<k>\w+://[\w\d\-+_=%&/:.]+\.(jpeg|JPEG|jpg|JPG|gif|GIF|png|PNG)(\?[\w\d/\-+_=%&:.]+)?)',re.M)
regex_auto_video = re.compile(r'(?<!["\w>/=])(?P<k>\w+://[\w\d\-+_=%&/:.]+\.(mp4|MP4|mpeg|MPEG|mov|MOV|ogv|OGV)(\?[\w\d/\-+_=%&:.]+)?)',re.M)
regex_auto_audio = re.compile(r'(?<!["\w>/=])(?P<k>\w+://[\w\d\-+_=%&/:.]+\.(mp3|MP3|wav|WAV|ogg|OGG)(\?[\w\d/\-+_=%&:.]+)?)',re.M)
regex_proto = re.compile(r'(?<!["\w>/=])(?P<p>\w+):(?P<k>\w+://[\w\d\-+=?%&/:.]+)', re.M)
regex_auto = re.compile(r'(?<!["\w>/=])(?P<k>\w+://[\w\d\-+_=?%&/:.]+)',re.M)
regex_link=re.compile(r'('+LINK+r')|\[\[(?P<s>.+?)\]\]')
regex_link_level2=re.compile(r'^(?P<t>\S.*?)?(?:\s+\[(?P<a>.+?)\])?(?:\s+(?P<k>\S+))?(?:\s+(?P<p>popup))?\s*$')
regex_media_level2=re.compile(r'^(?P<t>\S.*?)?(?:\s+\[(?P<a>.+?)\])?(?:\s+(?P<k>\S+))?\s+(?P<p>img|IMG|left|right|center|video|audio)(?:\s+(?P<w>\d+px))?\s*$')
@@ -536,7 +537,48 @@ def markmin_escape(text):
""" insert \\ before markmin control characters: '`:*~[]{}@$ """
return regex_markmin_escape.sub(lambda m: '\\'+m.group(0).replace('\\','\\\\'), text)
def render(text,extra={},allowed={},sep='p',URL=None,environment=None,latex='google',auto=True,class_prefix='',id_prefix='markmin_'):
def autolinks(url):
"""
it automatically converts the url to link,
image, video or audio tag
"""
u_url=url.lower()
if u_url.endswith(('jpeg','gif','png')):
return '<img src="%s" controls />' % url
elif u_url.endswith(('mp4','mpeg','mov','ogv')):
return '<video src="%s" controls></video>' % url
elif u_url.endswith(('mp3','wav','ogg')):
return '<audio src="%s" controls></audio>' % url
return '<a href="%s">%s</a>' % (url,url)
def protolinks(proto, url):
"""
it converts url to html-string using appropriate proto-prefix:
Uses for construction "proto:url", e.g.:
"iframe:http://www.example.com/path" will call protolinks()
with parameters:
proto="iframe"
url="http://www.example.com/path"
"""
if proto in ('iframe','embed'): #== 'iframe':
return '<iframe src="%s" frameborder="0" allowfullscreen></iframe>'%url
#elif proto == 'embed': # NOTE: embed is a synonym to iframe now
# return '<a href="%s" class="%sembed">%s></a>'%(url,class_prefix,url)
elif proto == 'qr':
return '<img width="80px" src="http://qrcode.kaywa.com/img.php?s=8&amp;d=%s" alt="qr code" />'%url
return proto+':'+url
def render(text,
extra={},
allowed={},
sep='p',
URL=None,
environment=None,
latex='google',
autolinks=autolinks,
protolinks=protolinks,
class_prefix='',
id_prefix='markmin_'):
"""
Arguments:
- text is the text to be processed
@@ -546,8 +588,18 @@ def render(text,extra={},allowed={},sep='p',URL=None,environment=None,latex='goo
allowed = dict(code=('python','cpp','java'))
- sep can be 'p' to separate text in <p>...</p>
or can be 'br' to separate text using <br />
- auto is a True/False value (default is True) -
enables auto links processing for iframe,embed,qr,url,image,video,audio
- URL -
- environment is a dictionary of environment variables (can be accessed with @{variable}
- latex -
- autolinks is a function to convert auto urls to html-code (default is autolinks(url) )
- protolinks is a function to convert proto-urls (e.g."proto:url") to html-code
(default is protolinks(proto,url))
- class_prefix is a prefix for ALL classes in markmin text. E.g. if class_prefix='my_'
then for ``test``:cls class will be changed to "my_cls" (default value is '')
- id_prefix is prefix for ALL ids in markmin text (default value is 'markmin_'). E.g.:
-- [[id]] will be converted to <a name="markmin_id"></a>
-- [[link #id]] will be converted to <a href="#markmin_id">link</a>
-- ``test``:cls[id] will be converted to <code class="cls" id="markmin_id">test</code>
>>> render('this is\\n# a section\\n\\nparagraph')
'<p>this is</p><h1>a section</h1><p>paragraph</p>'
@@ -583,7 +635,7 @@ def render(text,extra={},allowed={},sep='p',URL=None,environment=None,latex='goo
'<ol><li>this</li><li>is</li><li>a list</li></ol><p>and this</p><ol><li>is</li><li>another</li></ol>'
>>> render("----\\na | b\\nc | d\\n----\\n")
'<table><tbody><tr><td>a</td><td>b</td></tr><tr><td>c</td><td>d</td></tr></tbody></table>'
'<table><tbody><tr class="first"><td>a</td><td>b</td></tr><tr class="even"><td>c</td><td>d</td></tr></tbody></table>'
>>> render("----\\nhello world\\n----\\n")
'<blockquote>hello world</blockquote>'
@@ -630,6 +682,15 @@ def render(text,extra={},allowed={},sep='p',URL=None,environment=None,latex='goo
>>> render("auto-image: (http://example.com/image.jpeg)")
'<p>auto-image: (<img src="http://example.com/image.jpeg" controls />)</p>'
>>> render("qr: (qr:http://example.com/image.jpeg)")
'<p>qr: (<img width="80px" src="http://qrcode.kaywa.com/img.php?s=8&amp;d=http://example.com/image.jpeg" alt="qr code" />)</p>'
>>> render("embed: (embed:http://example.com/page)")
'<p>embed: (<iframe src="http://example.com/page" frameborder="0" allowfullscreen></iframe>)</p>'
>>> render("iframe: (iframe:http://example.com/page)")
'<p>iframe: (<iframe src="http://example.com/page" frameborder="0" allowfullscreen></iframe>)</p>'
>>> render("title1: [[test message [simple \[test\] title] http://example.com ]] test")
'<p>title1: <a href="http://example.com" title="simple [test] title">test message</a> test</p>'
@@ -780,14 +841,11 @@ def render(text,extra={},allowed={},sep='p',URL=None,environment=None,latex='goo
text = regex_link.sub(mark_link, text)
text = escape(text)
if auto:
text = regex_iframe.sub('<iframe src="\g<k>" frameborder="0" allowfullscreen></iframe>',text)
text = regex_embed.sub('<a href="\g<k>" class="embed">\g<k></a>',text)
text = regex_qr.sub('<img width="80px" src="http://qrcode.kaywa.com/img.php?s=8&amp;d=\g<k>" alt="qr code" />',text)
text = regex_auto_image.sub('<img src="\g<k>" controls />', text)
text = regex_auto_video.sub('<video src="\g<k>" controls></video>', text)
text = regex_auto_audio.sub('<audio src="\g<k>" controls></audio>', text)
text = regex_auto.sub('<a href="\g<k>">\g<k></a>', text)
if protolinks:
text = regex_proto.sub(lambda m: protolinks(*m.group('p','k')), text)
if autolinks:
text = regex_auto.sub(lambda m: autolinks(m.group('k')), text)
#############################################################
# normalize spaces
@@ -904,6 +962,7 @@ def render(text,extra={},allowed={},sep='p',URL=None,environment=None,latex='goo
tout=[]
thead=[]
tbody=[]
rownum=0
t_id = ''
t_cls = ''
@@ -914,9 +973,10 @@ def render(text,extra={},allowed={},sep='p',URL=None,environment=None,latex='goo
if s.count('=')==len(s) and len(s)>3: # header or footer
if not thead: # if thead list is empty:
thead = tout
else: # if tbody list is empty:
else:
tbody.extend(tout)
tout = []
rownum=0
lineno+=1
continue
@@ -926,12 +986,17 @@ def render(text,extra={},allowed={},sep='p',URL=None,environment=None,latex='goo
t_id = m.group('p') or ''
break
tout.append('<tr>'+''.join(['<td%s>%s</td>'% \
(' class="num"'
if regex_num.match(f)
else '',
f.strip()
) for f in s.split('|')])+'</tr>')
if rownum % 2:
tr = '<tr class="even">'
else:
tr = '<tr class="first">' if rownum == 0 else '<tr>'
tout.append(tr+''.join(['<td%s>%s</td>'% \
(' class="num"'
if regex_num.match(f)
else '',
f.strip()
) for f in s.split('|')])+'</tr>')
rownum+=1
lineno+=1
t_cls = ' class="%s%s"'%(class_prefix, t_cls) if t_cls and t_cls != 'id' else ''
@@ -990,7 +1055,8 @@ def render(text,extra={},allowed={},sep='p',URL=None,environment=None,latex='goo
URL,
environment,
latex,
auto,
autolinks,
protolinks,
class_prefix,
id_prefix)
)
@@ -1107,7 +1173,7 @@ def render(text,extra={},allowed={},sep='p',URL=None,environment=None,latex='goo
style = ' style="float:%s"' % p
if p in ('video','audio'):
t = render(t, {}, {}, 'br', URL, environment, latex,
auto, class_prefix, id_prefix)
autolinks, protolinks, class_prefix, id_prefix)
return '<%(p)s controls="controls"%(title)s%(width)s><source src="%(k)s" />%(t)s</%(p)s>' \
% dict(p=p, title=title, width=width, k=k, t=t)
alt = ' alt="%s"'%escape(t).replace(META, DISABLED_META) if t else ''
@@ -1127,14 +1193,14 @@ def render(text,extra={},allowed={},sep='p',URL=None,environment=None,latex='goo
k = escape(k)
title = ' title="%s"' % a.replace(META, DISABLED_META) if a else ''
target = ' target="_blank"' if p == 'popup' else ''
t = render(t, {}, {}, 'br', URL, environment, latex, auto,
class_prefix, id_prefix) if t else k
t = render(t, {}, {}, 'br', URL, environment, latex, autolinks,
protolinks, class_prefix, id_prefix) if t else k
return '<a href="%(k)s"%(title)s%(target)s>%(t)s</a>' \
% dict(k=k, title=title, target=target, t=t)
return '<a name="%s">%s</a>' % (escape(id_prefix+t),
render(a, {},{},'br', URL,
environment, latex, auto,
class_prefix, id_prefix))
environment, latex, autolinks,
protolinks, class_prefix, id_prefix))
parts = text.split(LINK)
text = parts[0]
@@ -1172,13 +1238,13 @@ def render(text,extra={},allowed={},sep='p',URL=None,environment=None,latex='goo
return LATEX % code.replace('"','\"').replace('\n',' ')
elif b in html_colors:
return '<span style="color: %s">%s</span>' \
% (b, render(code,{},{},'br',URL,environment,latex,auto))
% (b, render(code,{},{},'br',URL,environment,latex,autolinks, protolinks))
elif b in ('c', 'color') and p:
c=p.split(':')
fg='color: %s;' % c[0] if c[0] else ''
bg='background-color: %s;' % c[1] if len(c)>1 and c[1] else ''
return '<span style="%s%s">%s</span>' \
% (fg, bg, render(code,{},{},'br', URL, environment, latex, auto))
% (fg, bg, render(code,{},{},'br', URL, environment, latex, autolinks, protolinks))
cls = ' class="%s%s"'%(class_prefix,b) if b and b != 'id' else ''
id = ' id="%s%s"'%(id_prefix,escape(p)) if p else ''
beg=(code[:1]=='\n')
@@ -1190,8 +1256,8 @@ def render(text,extra={},allowed={},sep='p',URL=None,environment=None,latex='goo
text = text.translate(ttab_out)
return text
def markmin2html(text, extra={}, allowed={}, sep='p', auto=True):
return render(text, extra, allowed, sep, auto=auto)
def markmin2html(text, extra={}, allowed={}, sep='p', autolinks=autolinks, protolinks=protolinks):
return render(text, extra, allowed, sep, autolinks=autolinks, protolinks=protolinks)
if __name__ == '__main__':
import sys
@@ -1214,15 +1280,18 @@ if __name__ == '__main__':
if sys.argv[1:2] == ['-h']:
style=dedent("""
<style>
blockquote { background-color: lime; }
thead { color: white; background-color: gray; text-align: center; }
tfoot { color: white; background-color: gray; }
.tableclass1 { background-color: yellow; }
blockquote { background-color: #FFFAAE; padding: 7px; }
table { border-collapse: collapse; }
thead td { border-bottom: 1px solid; }
tfoot td { border-top: 1px solid; }
.tableclass1 { background-color: lime; }
.tableclass1 thead { color: yellow; background-color: green; }
.tableclass1 tfoot { color: yellow; background-color: green; }
.tableclass1 .even td { background-color: #80FF7F; }
.tableclass1 .first td {border-top: 1px solid; }
td.num { text-align: right; }
pre { background-color: #E0E0E0; }
pre { background-color: #E0E0E0; padding: 5px; }
</style>""")[1:]
print html % dict(title="Markmin markup language", style=style, body=markmin2html(__doc__))
@@ -1236,9 +1305,29 @@ if __name__ == '__main__':
elif len(sys.argv) > 1:
fargv = open(sys.argv[1],'r')
try:
print html % dict(title=sys.argv[1], style='', body=markmin2html(fargv.read()))
markmin_text=fargv.read()
# embed css file from second parameter into html file
if len(sys.argv) > 2:
if sys.argv[2].startswith('@'):
markmin_style = '<link rel="stylesheet" href="'+sys.argv[2][1:]+'"/>'
else:
fargv2 = open(sys.argv[2],'r')
try:
markmin_style = "<style>\n" + fargv2.read() + "</style>"
finally:
fargv2.close()
else:
markmin_style = ""
print html % dict(title=sys.argv[1], style=markmin_style, body=markmin2html(markmin_text))
finally:
fargv.close()
else:
doctest.testmod()
else:
print "Usage: "+sys.argv[0]+" -h | -t | file.markmin [file.css|@path_to/css]"
print "where: -h - print __doc__"
print " -t - timeit __doc__ (for testing purpuse only)"
print " file.markmin [file.css] - process file.markmin + built in file.css (optional)"
print " file.markmin [@path_to/css] - process file.markmin + link path_to/css (optional)"
doctest.testmod()
+43 -28
View File
@@ -28,10 +28,10 @@ from string import maketrans
__all__ = ['translator', 'findT', 'update_all_languages']
# used as a default filter i translator.M()
# used as default filter in translator.M()
markmin = lambda s: render( regex_param.sub(
lambda m: '{' + markmin_escape(m.group('s')) + '}',
s ), sep='br', auto=False )
s ), sep='br', autolinks=None, id_prefix='' )
NUMBERS = (int,long,float)
@@ -377,7 +377,8 @@ class lazyT(object):
never to be called explicitly, returned by
translator.__call__() or translator.M()
"""
m = s = T = f = t = M = None
m = s = T = f = t = None
M = is_copy = False
def __init__(
self,
@@ -388,34 +389,35 @@ class lazyT(object):
ftag = None,
M = False
):
self.M = M
if isinstance(message, lazyT):
self.m = message.m
self.s = symbols or message.s
self.T = T or message.T
self.f = filter or message.f
self.t = ftag or message.t
self.s = message.s
self.T = message.T
self.f = message.f
self.t = message.t
self.M = message.M
self.is_copy = True
else:
self.m = message
self.s = symbols
self.T = T
self.f = filter
self.t = ftag
self.M = M
self.is_copy = False
def __repr__(self):
return "<lazyT %s>" % (repr(str(self.m)), )
return "<lazyT %s>" % (repr(Utf8(self.m)), )
def __str__(self):
return str(self.T.apply_filter(self.m, self.s, self.f, self.t) if self.M else
self.T.translate(self.m, self.s))
def __eq__(self, other):
return (self.T.apply_filter(self.m, self.s, self.f, self.t) if self.M else
self.T.translate(self.m, self.s)) == other
return str(self) == str(other)
def __ne__(self, other):
return (self.T.apply_filter(self.m, self.s, self.f, self.t) if self.M else
self.T.translate(self.m, self.s)) != other
return str(self) != str(other)
def __add__(self, other):
return '%s%s' % (self, other)
@@ -423,14 +425,17 @@ class lazyT(object):
def __radd__(self, other):
return '%s%s' % (other, self)
def __mul__(self, other):
return str(self) * other
def __cmp__(self,other):
return cmp(str(self),str(other))
return cmp(str(self), str(other))
def __hash__(self):
return hash(str(self))
def __getattr__(self, name):
return getattr(str(self),name)
return getattr(str(self), name)
def __getitem__(self, i):
return str(self)[i]
@@ -457,7 +462,8 @@ class lazyT(object):
return str(self)
def __mod__(self, symbols):
return lazyT(self.m,symbols,self.T,self.f,self.t,self.M)
if self.is_copy: return lazyT(self)
return lazyT(self.m, symbols, self.T, self.f, self.t, self.M)
class translator(object):
@@ -787,18 +793,21 @@ class translator(object):
"""
w,i = m.group('w','i')
c = w[0]
word = w[c=='\\':]
if c not in '!?':
return self.plural(word, symbols[int(i or 0)])
return self.plural(w, symbols[int(i or 0)])
elif c == '?':
part2 = w[max(1,w.find('?',1)+1):]
(p1, sep, p2) = w[1:].partition("?")
part1 = p1 if sep else ""
(part2, sep, part3) = (p2 if sep else p1).partition("?")
if not sep: part3 = part2
if i is None:
# ?[word]?number or ?number
num = part2
# ?[word]?number[?number] or ?number
if not part2: return m.group(0)
num = int(part2)
else:
# ?[word]?word2[number], ?word2[number] or ?word2[number]
num = symbols[int(i or 0)]
return w[1:abs(w.find('?',1))] if int(num) == 1 else part2
# ?[word]?word2[?word3][number]
num = int(symbols[int(i or 0)])
return part1 if num==1 else part3 if num==0 else part2
elif w.startswith('!!!'):
word = w[3:]
fun = upper_fun
@@ -815,16 +824,22 @@ class translator(object):
def sub_dict(m):
""" word(var), !word(var), !!word(var), !!!word(var)
word(num), !word(num), !!word(num), !!!word(num)
?word2(var), ?word1?word2(var), ?word1?word2?word0(var)
?word2(num), ?word1?word2(num), ?word1?word2?word0(num)
"""
w,n = m.group('w','n')
c = w[0]
word = w[c=='\\':]
n = int(n) if n.isdigit() else symbols[n]
if c not in '!?':
return self.plural(word, n)
return self.plural(w, n)
elif c == '?':
# ?[word]?word2(var or num), ?word2(var or num) or ?word2(var or num)
return w[1:abs(w.find('?',1))] if int(n) == 1 else w[max(1,w.find('?',1)+1):]
# ?[word1]?word2[?word0](var or num), ?[word1]?word2(var or num) or ?word2(var or num)
(p1, sep, p2) = w[1:].partition("?")
part1 = p1 if sep else ""
(part2, sep, part3) = (p2 if sep else p1).partition("?")
if not sep: part3 = part2
num = int(n)
return part1 if num==1 else part3 if num==0 else part2
elif w.startswith('!!!'):
word = w[3:]
fun = upper_fun