def __init__(self, nesting_level=4, md_ext=_ext): # self.rndr = HtmlRenderer(nesting_level=nesting_level) self.rndr = CustomRenderer(nesting_level=nesting_level) self.tocrndr = HtmlTocRenderer(nesting_level=nesting_level) self.md = Markdown(self.rndr, extensions=md_ext) self.toc = Markdown(self.tocrndr, extensions=('fenced-code', 'autolink', 'underline'))
def __init__(self, markdown, renderer=None, url_prefix=None): self.raw = markdown self.renderer = renderer or MarkmentRenderer() self.renderer.url_prefix = url_prefix self.markdown = Markdown( self.renderer, extensions=self.extensions, ) self.rendered = self.compile() self.url_references = self.renderer.url_references
def convert(self, contents): markdown = Markdown(TutsPlusRenderer(), EXT_FENCED_CODE) contents = re.sub(r'(\w+_\w+_\w[\w_]*)', self.escape_underscore, contents) contents = re.sub(re.compile(r'(\A|^$\n)(^\w[^\n]*\n)(^\w[^\n]*$)+', re.MULTILINE), self.newline, contents) converted = markdown.render(contents) converted = re.sub(r'(<p>)?<!-- start img -->', '', converted) converted = re.sub(r'<!-- end img -->(</p>)?', '', converted) return converted
def render_document(data, toc=False): # Strip meta if any if data.startswith('---'): data = data[data.find('---', 3) + 3:] # Render Markdown document (removing user-inputted HTML) renderer = (HtmlTocRenderer if toc else PlumeRenderer)(flags=HTML_HARD_WRAP | HTML_SKIP_HTML | HTML_TOC) markdown = Markdown(renderer, extensions=EXT_AUTOLINK | EXT_FENCED_CODE | EXT_STRIKETHROUGH | EXT_SUPERSCRIPT | EXT_TABLES) return markdown.render(data)
def setup(self): self.r = Markdown(HtmlRenderer()).render tests_dir = path.dirname(__file__) for text_path in glob(path.join(tests_dir, self.suite, '*.text')): html_path = '%s.html' % path.splitext(text_path)[0] self._create_test(text_path, html_path)
class Markment(object): extensions = (EXT_FENCED_CODE | EXT_NO_INTRA_EMPHASIS | HTML_SMARTYPANTS | EXT_TABLES | EXT_AUTOLINK | EXT_SUPERSCRIPT | HTML_USE_XHTML) def __init__(self, markdown, renderer=None, url_prefix=None): self.raw = markdown self.renderer = renderer or MarkmentRenderer() self.renderer.url_prefix = url_prefix self.markdown = Markdown( self.renderer, extensions=self.extensions, ) self.rendered = self.compile() self.url_references = self.renderer.url_references def compile(self): return self.markdown.render(self.raw) def index(self): return deepcopy(self.renderer.markment_indexes)
def parse(text): chg = Renderer() chg.reset() md = Markdown(renderer=chg) md(text) return chg
def inspect(cls, raw): renderer = cls() markdown = renderer.preprocess(raw) extensions = EXT_FENCED_CODE | EXT_NO_INTRA_EMPHASIS md = Markdown(renderer, extensions=extensions) full = md(markdown) renderer.postprocess(full) return renderer
def description(job_id): # SELECT JOB FROM DATABASE job = select_job(job_id) # render descripton markdown to html render = HtmlRenderer() md = Markdown(render) job["description"] = Markup(md(job.get("description"))) return render_template("description.html", job=job)
def __init__(self): Gtk.Window.__init__(self, type=Gtk.WindowType.TOPLEVEL, title="MDLive Markdown Editor") self.version = "0.1.0" default_width = 1280 default_height = 720 self.set_default_size(default_width, default_height) self.set_position(Gtk.WindowPosition.MOUSE) self.box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) self.add(self.box) self.menu_bar = MenuBar(self) self.split_box = Gtk.HPaned() self.split_box.set_position(default_width / 2) self.editor = Gtk.TextView() self.editor.set_wrap_mode(Gtk.WrapMode.WORD_CHAR) self.editor_buffer = self.editor.get_buffer() self.editor_scroller = Gtk.ScrolledWindow() self.editor_scroller.add(self.editor) self.preview = WebKit.WebView() self.preview.open("file://" + self.installed_path() + "/assets/index.html") self.preview_scroller = Gtk.ScrolledWindow() self.preview_scroller.add(self.preview) self.split_box.add1(self.editor_scroller) self.split_box.add2(self.preview_scroller) self.box.pack_start(self.menu_bar, False, False, 0) self.box.pack_start(self.split_box, True, True, 0) self.renderer = Renderer() self.markdown = Markdown(self.renderer, extensions=misaka.EXT_FENCED_CODE | misaka.EXT_AUTOLINK | misaka.EXT_SPACE_HEADERS) self.editor_buffer.connect("end-user-action", self.on_buffer_end_user_action)
def preview(): from misaka import Markdown, HtmlRenderer if request.method == "POST": content = request.args.get('content') html = HtmlRenderer() markdown = Markdown(html) return Markup(markdown(content)) else: abort(404)
def read(request, slug): articles = get_list_or_404(Article, slug=slug, publie=True) article = articles[0] categories = [cat.nom for cat in article.categorie.all()] tiret = "-" categories = tiret.join(categories) # for some special posts, we use js code, so we use specific template retour = jump_special_view(request, locals()) if retour: return retour url_article = '{}'.format(getattr(article, 'urlGitHub')) response = get_article_from_local(url_article) extension = url_article.split('.')[1] if response != 'Error': if extension == 'md': rndr = HtmlRenderer() md = Markdown(rndr, extensions=('fenced-code', 'math')) article_markdown = md(response) return render( request, 'markdown.html', { 'article': article, 'categories': categories, 'article_markdown': article_markdown, 'url_github': url_article }) elif extension == 'ipynb': notebook = format_read(response, as_version=4) html_explorer = HTMLExporter() html_explorer.template_file = 'basic' (body, _) = html_explorer.from_notebook_node(notebook) return render( request, 'lire_ipynb.html', { 'article': article, 'ipynb': body, 'categories': categories, 'url_github': url_article }) else: article_markdown = ('Error reading this article!') return render( request, 'markdown.html', { 'article': article, 'categories': categories, 'article_markdown': article_markdown, 'url_github': url_article })
def convert_to_html(filename, input_encoding='UTF-8'): """ Convert a file with Markdown or reStructuredText markup to HTML. :param filename: The filename of the text file to convert (a string). :param encoding: The encoding of the text file (a string). :returns: A tuple of two strings: 1. The HTML to embed in the ``<head>``. 2. The HTML to embed in the ``<body>``. """ # Determine the filename extension. basename, extension = os.path.splitext(filename) extension = extension.lower() # Read the input file into a Unicode string. with codecs.open(filename, encoding=input_encoding) as handle: text = handle.read() # Convert the input file. timer = Timer() if extension in MARKDOWN_EXTENSIONS: logger.debug( "Filename extension of input file (%s) indicates Markdown.", extension) converter = Markdown(HtmlRenderer()) head = '' body = converter.render(text) elif extension in RESTRUCTUREDTEXT_EXTENSIONS: logger.debug( "Filename extension of input file (%s) indicates reStructuredText.", extension) parts = publish_parts(source=text, writer_name='html', settings_overrides=dict(doctitle_xform=False)) head = parts['stylesheet'] body = parts['html_body'] else: msg = "Input file not supported! (filename extension %s not recognized)" raise ValueError(msg % extension) logger.debug("Converted %s input text to %s HTML in %s.", format_size(len(text)), format_size(len(head) + len(body)), timer) return head, body
class GitMarkdown(): def __init__(self): self.renderer = HtmlRenderer() self.markdown = Markdown(self.renderer) def render_html(self, string): html_string = self.markdown.render(string) return html_string
def story(content_uri): """Return the text referenced by content_uri. If uri can not be resolved it is returned as is. Current allowed scheme is 'git'. The netloc 'yaj-dir' resolves to the local source tree. The buffer get processed by mako and rendered as markdown. """ fullpath = uri.resolve_to_path(content_uri) buf0 = fetch.read(fullpath) # markdown rndr = HtmlRenderer() md = Markdown(rndr) return md(buf0)
def preview(): if request.method == "POST": from misaka import Markdown, HtmlRenderer choice = request.values.get('choice') content = request.values.get('content') if choice == 'Default': return safe_clean(content) else: html = HtmlRenderer() markdown = Markdown(html) return Markup(markdown(content)) else: abort(404)
def safe_markdown(text): class HighlighterRenderer(HtmlRenderer): def blockcode(self, text, lang): lang = 'python' if not lang: return '\n<pre><code>{}</code></pre>\n'.format(text.strip()) lexer = get_lexer_by_name(lang, stripall=True) formatter = HtmlFormatter() return highlight(text, lexer, formatter) renderer = HighlighterRenderer() md = Markdown(renderer, extensions=('fenced-code', )) return Markup(md(safe_clean(text)))
def main(): md = Markdown( # skip-html - 跳过原文中的 HTML 代码 # hard-wrap - 每个 \n 都渲染为 <br> renderer=_Renderer(flags=('hard-wrap', 'skip-html')), # space-headers - 只将 # Title 转为 <header> # #Title 会保持原样 extensions=('disable-indented-code', 'autolink', 'space-headers')) print md(u'''some text next line next para''') # 空行中央有一个全角空格
def index(): """Present readme.md""" # Open readme.md file with open(os.path.dirname(app.root_path) + '/app/readme.md', 'r') as markdown_file: print('os.path.dirname(app.root_path)', os.path.dirname(app.root_path)) # Read the content of the file content = markdown_file.read() rndr = HtmlRenderer() md = Markdown(rndr) # Convert it to HTML return md(content)
def __init__(self, math_text_parser, settings, mongo_db=None, redis_db=None, *args, **kwargs): #settings = kwargs.pop('settings') #print settings self.cloud = kwargs.pop('cloud', False) if self.cloud: self.work_queue = kwargs.pop('work_queue', None) if not self.work_queue: raise ValueError(('Supplying the cloud argument' 'requires you to also supply the cloud upload queue object')) if not mongo_db: self.mongo_db = settings['db.mongo.conn'][settings['db.mongo.collection_name']] else: self.mongo_db = mongo_db if not redis_db: self.redis_db = settings['db.redis.conn'] else: self.redis_db = redis_db self.cache_route = settings['preview.img_cache_route'] self.cache_time = int(settings['preview.img_cache_time']) self.math_text_parser = math_text_parser self.htmlparser = HTMLParser() # keep all keys in lowercase! self.funcs = { 'img': self.handle_image_macro, 'image': self.handle_image_macro, 'audio': self.handle_audio_macro, 'math': self.handle_math_macro, 'multi': self.handle_multiple_choice_macro, 'multi-choice': self.handle_multiple_choice_macro, 'multiple-choice': self.handle_multiple_choice_macro } self.entities = { ' ': ' ', # space '"': '"', # quote "'": ''', # apostrophe ',': ',', # comma '=': '=', # equals '\\': '\' # backslash } # Secondary renderer for snippet rendering self.snippet_renderer = Markdown(renderer=HtmlRenderer()) self.post_process_blocks = list() self.answers = dict()
class MarkdownProcessor(Processor): class MisakaProcessor(HtmlRenderer): def block_code(self, text, lang): return self.highlight_code(lang, text) def highlight_code(self, language, code): return highlight(code, get_lexer_by_name(language), HtmlFormatter()) def __init__(self): self.md = Markdown(self.MisakaProcessor(), EXT_FENCED_CODE) def render(self, text): return self.md.render(text)
def test_list_custom_start(self): class ListCustomStartRenderer(HtmlRenderer): def list(self, text, is_ordered, is_block, prefix): if prefix: return '<ol start="{start}">\n{text}</ol>\n'.format( start=prefix, text=text) return super(ListCustomStartRenderer, self).list(text, is_ordered, is_block, prefix) text = ' 5. five\n 6. six\n 7. seven' rendered = Markdown(ListCustomStartRenderer())(text) ok(rendered).diff( '<ol start="5">\n<li>five</li>\n<li>six</li>\n<li>seven</li>\n</ol>\n' )
def get_text_from_markdown(markdown_text): renderer = HtmlRenderer() markdown = Markdown(renderer, extensions=('tables', 'autolink', 'strikethrough', 'quote', 'superscript', 'fenced-code')) html = markdown(markdown_text) parsed_html = fromstring(html) # remove quoted text [x.getparent().remove(x) for x in parsed_html.xpath('//blockquote')] # remove automatically added links for link in parsed_html.xpath('//a'): if link.text_content() == link.get('href'): link.getparent().remove(link) text = ''.join(parsed_html.text_content()).strip() return text
def safe_markdown(text): class HighlighterRenderer(HtmlRenderer): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) def blockcode(self, text, lang): if not lang: return '\n<pre><code>{}</code></pre>\n'.format(text.strip()) lexer = get_lexer_by_name(lang, stripall=True) formatter = HtmlFormatter(linenos=True) return highlight(text, lexer, formatter) renderer = HighlighterRenderer() md = Markdown(renderer, extensions=('fenced-code', )) return Markup(md(safe_clean(text)))
def post_content(slug): login = session.get("logged_in") post = db.session.query(Posts).filter(Posts.slug == slug).first() if not post: return abort(404) render = HtmlRenderer() md = Markdown(render) session['post_id'] = post.id user_id = session.get("user_id") username = session.get("username") post.content = Markup(md(post.content)) return render_template("post/post-content.html", login=login, post=post, user=username)
def create(): md = Markdown(HtmlRenderer()) form = PostForm() post = Post() if form.validate_on_submit(): post.title = form.title.data post.body = form.body.data post.body_html = md(post.body) post.outline = form.outline.data post.created = datetime.now() db.session.add(post) return redirect(url_for('main.admin')) try: db.session.commit() except ImportError: db.session.rollback return render_template('create_post.html', form=form)
def __init__(self): Gtk.Window.__init__(self, type=Gtk.WindowType.TOPLEVEL, title="MDLive Markdown Editor") self.version = "0.1.0" default_width = 1280 default_height = 720 self.set_default_size(default_width, default_height) self.set_position(Gtk.WindowPosition.MOUSE) self.box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) self.add(self.box) self.menu_bar = MenuBar(self) self.split_box = Gtk.HPaned() self.split_box.set_position(default_width / 2) self.editor = Gtk.TextView() self.editor.set_wrap_mode(Gtk.WrapMode.WORD_CHAR) self.editor_buffer = self.editor.get_buffer() self.editor_scroller = Gtk.ScrolledWindow() self.editor_scroller.add(self.editor) self.preview = WebKit.WebView() self.preview.open("file://" + self.installed_path() + "/assets/index.html") self.preview_scroller = Gtk.ScrolledWindow() self.preview_scroller.add(self.preview) self.split_box.add1(self.editor_scroller) self.split_box.add2(self.preview_scroller) self.box.pack_start(self.menu_bar, False, False, 0) self.box.pack_start(self.split_box, True, True, 0) self.renderer = Renderer() self.markdown = Markdown(self.renderer, extensions= misaka.EXT_FENCED_CODE | misaka.EXT_AUTOLINK | misaka.EXT_SPACE_HEADERS) self.editor_buffer.connect("end-user-action", self.on_buffer_end_user_action)
def setText(self, text): htmlrd = HighlighterRenderer() mdToHtml = Markdown(htmlrd, extensions=('fenced-code', 'tables', 'footnotes', 'autolink', 'highlight','strikethrough', 'underline', 'quote', 'superscript', 'math', 'no-intra-emphasis', 'space-headers', 'math-explicit')) html = mdToHtml(text) html = html.replace('<table>', '<table border="1">') #css head cssStyle = '<style type = "text/css">\n' #css body with open('./resource/typora.style', 'r') as file: typoraStyle = file.read() cssStyle = cssStyle + typoraStyle cssStyle = cssStyle + HtmlFormatter().get_style_defs('.highlight') #css end cssStyle = cssStyle + '</style>\n' self.setHtml(cssStyle + html)
def __init__(self, config: Config, som: dict, build_cache: dict = None): self.config = config self.som = som self.build_cache = build_cache md_renderer = HarrierHtmlRenderer() self.md = Markdown(md_renderer, extensions=MD_EXTENSIONS) template_dirs = [ str(self.config.get_tmp_dir()), str(self.config.theme_dir / 'templates') ] logger.debug('template directories: %s', ', '.join(template_dirs)) extensions = 'jinja2.ext.loopcontrols', MarkdownExtension self.env = Environment(loader=FileSystemLoader(template_dirs), extensions=extensions) self.env.filters.update( glob=page_glob, slugify=slugify, format=format_filter, tojson=json_filter, debug=debug_filter, markdown=self.md, paginate=paginate_filter, ) self.env.filters.update(self.config.extensions.template_filters) self.env.globals.update( url=resolve_url, resolve_url=resolve_url, inline_css=inline_css, shape=shape, width=width, height=height, ) self.env.globals.update(self.config.extensions.template_functions) self.env.tests.update(self.config.extensions.template_tests) self.checked_dirs = set() self.to_gen = [] self.to_copy = []
class MainWindow(Gtk.Window): def __init__(self): Gtk.Window.__init__(self, type=Gtk.WindowType.TOPLEVEL, title="MDLive Markdown Editor") self.version = "0.1.0" default_width = 1280 default_height = 720 self.set_default_size(default_width, default_height) self.set_position(Gtk.WindowPosition.MOUSE) self.box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) self.add(self.box) self.menu_bar = MenuBar(self) self.split_box = Gtk.HPaned() self.split_box.set_position(default_width / 2) self.editor = Gtk.TextView() self.editor.set_wrap_mode(Gtk.WrapMode.WORD_CHAR) self.editor_buffer = self.editor.get_buffer() self.editor_scroller = Gtk.ScrolledWindow() self.editor_scroller.add(self.editor) self.preview = WebKit.WebView() self.preview.open("file://" + self.installed_path() + "/assets/index.html") self.preview_scroller = Gtk.ScrolledWindow() self.preview_scroller.add(self.preview) self.split_box.add1(self.editor_scroller) self.split_box.add2(self.preview_scroller) self.box.pack_start(self.menu_bar, False, False, 0) self.box.pack_start(self.split_box, True, True, 0) self.renderer = Renderer() self.markdown = Markdown(self.renderer, extensions= misaka.EXT_FENCED_CODE | misaka.EXT_AUTOLINK | misaka.EXT_SPACE_HEADERS) self.editor_buffer.connect("end-user-action", self.on_buffer_end_user_action) def on_buffer_end_user_action(self, buffer): self.render_markdown() def render_markdown(self): start, end = self.editor_buffer.get_bounds() text = self.editor_buffer.get_text(start, end, True) results = self.markdown.render(text) escaped = houdini.escape_js(results) if escaped == None: escaped = houdini.escape_js("\n") self.preview.execute_script("window.App.setHtml('" + escaped + "')") def installed_path(self): root = __file__ if os.path.islink(root): root = os.path.realpath(root) return os.path.dirname(os.path.abspath(root))
def render_with(self, text, flags=0, extensions=0): return Markdown(HtmlRenderer(), extensions).render(text)
def markdown_process(text, obj): md = Markdown(EnhancedRenderer()) return md.render(text)
class MainWindow(Gtk.Window): def __init__(self): Gtk.Window.__init__(self, type=Gtk.WindowType.TOPLEVEL, title="MDLive Markdown Editor") self.version = "0.1.0" default_width = 1280 default_height = 720 self.set_default_size(default_width, default_height) self.set_position(Gtk.WindowPosition.MOUSE) self.box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) self.add(self.box) self.menu_bar = MenuBar(self) self.split_box = Gtk.HPaned() self.split_box.set_position(default_width / 2) self.editor = Gtk.TextView() self.editor.set_wrap_mode(Gtk.WrapMode.WORD_CHAR) self.editor_buffer = self.editor.get_buffer() self.editor_scroller = Gtk.ScrolledWindow() self.editor_scroller.add(self.editor) self.preview = WebKit.WebView() self.preview.open("file://" + self.installed_path() + "/assets/index.html") self.preview_scroller = Gtk.ScrolledWindow() self.preview_scroller.add(self.preview) self.split_box.add1(self.editor_scroller) self.split_box.add2(self.preview_scroller) self.box.pack_start(self.menu_bar, False, False, 0) self.box.pack_start(self.split_box, True, True, 0) self.renderer = Renderer() self.markdown = Markdown(self.renderer, extensions=misaka.EXT_FENCED_CODE | misaka.EXT_AUTOLINK | misaka.EXT_SPACE_HEADERS) self.editor_buffer.connect("end-user-action", self.on_buffer_end_user_action) def on_buffer_end_user_action(self, buffer): self.render_markdown() def render_markdown(self): start, end = self.editor_buffer.get_bounds() text = self.editor_buffer.get_text(start, end, True) results = self.markdown.render(text) escaped = houdini.escape_js(results) if escaped == None: escaped = houdini.escape_js("\n") self.preview.execute_script("window.App.setHtml('" + escaped + "')") def installed_path(self): root = __file__ if os.path.islink(root): root = os.path.realpath(root) return os.path.dirname(os.path.abspath(root))
def __init__(self): self.md = Markdown(self.MisakaProcessor(), EXT_FENCED_CODE)
def __init__(self): self.renderer = HtmlRenderer() self.markdown = Markdown(self.renderer)
def mdtohtml(text): renderer = BleepRenderer() mark = Markdown(renderer,extensions= md.EXT_FENCED_CODE|md.EXT_NO_INTRA_EMPHASIS) return mark.render(text)
class VimwikiHtmlRenderer(HtmlRenderer, LinkPreprocessor): def __call__(self, text, *args, **kwargs): text = self.preprocess(text) return super(VimwikiHtmlRenderer, self).__call__(text) def block_code(self, text, lang): if not lang: return u'\n<pre><code>%s</code></pre>\n' % \ mistune.escape(text.strip()) lexer = get_lexer_by_name(lang, stripall=True) formatter = CodeHtmlFormatter() return highlight(text, lexer, formatter) renderer = VimwikiHtmlRenderer() to_html = Markdown(renderer, extensions=EXT_NO_INTRA_EMPHASIS | EXT_TABLES | EXT_FENCED_CODE | EXT_AUTOLINK | EXT_STRIKETHROUGH | EXT_SUPERSCRIPT) input_file = renderer.preprocess(input_file) main_content = to_html(input_file) if renderer.percent_codes['no_html']: print(output_file_path + " not converted due to presence of " "'%nohtml' in the file.") else: if renderer.percent_codes['toc']: toc_renderer = VimwikiTocRenderer() to_toc = Markdown(toc_renderer, extensions=EXT_NO_INTRA_EMPHASIS | EXT_AUTOLINK) toc_content = to_toc(input_file) else: toc_content = None
def mkdir(path): isExists = os.path.exists(path) if not isExists: print path + 'success!' os.makedirs(path) return True else: print path + 'has been made!' return False #创建文件article目录 for key in txt: x = key[0][0:10].split('-') path = '../article/' + '/'.join(x) mkdir(path) f = open(key[1][1],'r') input = f.read() f.close() flags = m.HTML_HARD_WRAP exts = m.EXT_FENCED_CODE | m.EXT_AUTOLINK | m.EXT_NO_INTRA_EMPHASIS | m.EXT_SUPERSCRIPT | m.EXT_TABLES md = Markdown(ColorRenderer(flags), exts) html = md.render(input).encode('utf-8') abso = path + '/' + key[1][0].strip('.md') + '.html' f = open(abso,'aw') key[1][1] = abso print key[1][1] f.write(html) f.close() ###############################################################################
if not link.startswith(('http', 'https', '//')): link = try_md2html(link) return u'<a href="{0}">{0}</a>'.format(link) def link(self, link, title, content): if not link.startswith(('http', 'https', '//')): link = try_md2html(link) if title: return u'<a href="{0}">{1}</a>'.format(link, content) return u'<a href="{0}" title="{2}">{1}</a>'.format( link, content, title) render = GmlsHtmlRenderer() markdown = Markdown(render, extensions=(EXT_TABLES | EXT_FENCED_CODE | EXT_NO_INTRA_EMPHASIS | EXT_AUTOLINK)) @app.route('/', defaults={'path': './'}) # noqa @app.route('/<path:path>') def handle(path): if os.path.isdir(path): # 'directory' => 'directory/' if not path.endswith('/'): return redirect(url_for('handle', path=path + '/')) # collect entries in this directory lilist = [] readme = None for entry in os.listdir(path):
def inspect(cls, markdown): renderer = cls() extensions = EXT_FENCED_CODE | EXT_NO_INTRA_EMPHASIS md = Markdown(renderer, extensions=extensions) md.render(markdown) return renderer
class CustomHtmlRenderer(HtmlRenderer): def __new__(cls, flags=0, **kwargs): return HtmlRenderer.__new__(cls, flags) def __init__(self, math_text_parser, settings, mongo_db=None, redis_db=None, *args, **kwargs): #settings = kwargs.pop('settings') #print settings self.cloud = kwargs.pop('cloud', False) if self.cloud: self.work_queue = kwargs.pop('work_queue', None) if not self.work_queue: raise ValueError(('Supplying the cloud argument' 'requires you to also supply the cloud upload queue object')) if not mongo_db: self.mongo_db = settings['db.mongo.conn'][settings['db.mongo.collection_name']] else: self.mongo_db = mongo_db if not redis_db: self.redis_db = settings['db.redis.conn'] else: self.redis_db = redis_db self.cache_route = settings['preview.img_cache_route'] self.cache_time = int(settings['preview.img_cache_time']) self.math_text_parser = math_text_parser self.htmlparser = HTMLParser() # keep all keys in lowercase! self.funcs = { 'img': self.handle_image_macro, 'image': self.handle_image_macro, 'audio': self.handle_audio_macro, 'math': self.handle_math_macro, 'multi': self.handle_multiple_choice_macro, 'multi-choice': self.handle_multiple_choice_macro, 'multiple-choice': self.handle_multiple_choice_macro } self.entities = { ' ': ' ', # space '"': '"', # quote "'": ''', # apostrophe ',': ',', # comma '=': '=', # equals '\\': '\' # backslash } # Secondary renderer for snippet rendering self.snippet_renderer = Markdown(renderer=HtmlRenderer()) self.post_process_blocks = list() self.answers = dict() @property def _404_img(self): return ( 'https://a9e01ec7324d40fdae33-8c4723fa6cef88b6ec249366d018b063' '.ssl.cf1.rackcdn.com/notfound.png' ) def _normalize(self, text): return filters.force_utf8(' '.join(text.strip(' \t').split())) def get_answers(self): return self.answers def render_bb_macro(self, block_id='', bb_model='', bb_view='base', bb_model_args='', bb_view_args='', bb_escape=''): bb_model_req = "" bb_model_var = "" new_bb_model = "" if bb_model: bb_model_req = '"' + MACRO_MODELS_PATH + '/' + bb_model + '", ' bb_model_var = 'Model,' new_bb_model = 'model:new Model(' + bb_model_args + '),' else: bb_model_req = '"backbone", ' bb_model_var = 'Backbone,' new_bb_model = 'model:new Backbone.Model(' + bb_model_args + '),' bb_view_req = '"' + MACRO_VIEWS_PATH + '/' + bb_view + '"' if bb_view_args: bb_view_args = 'options: ' + bb_view_args + ',' macro_template = Template(( '<span id="m4ed-${block_id}"></span>' '<script>' 'require([${model_req}${view_req}],' 'function(${model_var}View){' 'new View({' '${new_model}' 'custom:{' '${view_options}' 'block_id:"#m4ed-${block_id}"' '}' '});' '});' '<${escape_string}/script>' )) return macro_template.substitute( block_id=block_id, model_req=bb_model_req, model_var=bb_model_var, view_req=bb_view_req, new_model=new_bb_model, view_options=bb_view_args, escape_string=bb_escape ) def handle_image_macro(self, m_args): """ format: [[img: id= url= alt= style= title= data ]] args: id = m4ed image reference OR url = external url when no id provided (no url arg present) alt = image alt text style = free style attributes title = image title data - rendered with sundown as is """ default = m_args.pop('default', None) if default: imgid = default data = '' else: data = m_args.pop('data', None) if data: data = self.snippet_renderer.render(data) imgid = m_args.pop('id', None) argstr = '' if 'title' in m_args: argstr += 'title="{title} "'.format(title=m_args.pop('title', '')) if 'style' in m_args: argstr += 'style="{style}"'.format(style=m_args.pop('style', '')) return '<img alt="{alt}" src="{src}" {argstr} />{data}'.format( alt=m_args.pop('alt', ''), src=self.imgid_to_imgurl(imgid) if imgid else \ m_args.pop('url', self._404_img), argstr=argstr, data=data ) def handle_math_macro(self, m_args, debug=DEBUG): if debug: print "m_args: ", m_args try: data = m_args.pop('data', None) if not data: data = m_args.pop('default', '') except AttributeError: return '' if DEBUG: print "data: ", data res = [] lines = self.htmlparser.unescape(data).split('\n') if DEBUG: print lines num_lines = len(lines) for i, line in enumerate(lines): line = self._normalize(line) if line == '' and i != num_lines: res.append('<br />') else: res.append(self.math_to_img(line)) return ''.join(res) def handle_multiple_choice_macro(self, m_args): if DEBUG: print "--> multiple choice macro" block_id = m_args.pop('block_id', None) if block_id is None: raise ValueError('block_id was undefined') # process the macro args btn_layouts = ('inline', 'fit') btn_classes = ('btn-primary', 'btn-info', 'btn-success', 'btn-warning', 'btn-danger', 'btn-inverse', '', 'btn-link') label_classes = ('label-info', 'label-info', 'label-success', 'label-warning', 'label-important', 'label-inverse', '', 'label-info') # layout != inline -> fit default_view = {'show_legend': True, 'show_prefix': True, 'show_content': False, 'layout': 'inline', 'legend_class': 'label-info', 'btn_class': 'btn-primary', 'btn_cols': 0, 'prefix_class': ''} bb_view_args = default_view default_view.update(m_args) # html_tag = '<span id="m4ed-{block_id}"></span>'.format(block_id=block_id) data = m_args.pop('data', '') multi_choice_args = [] temp_args = [] # Init the answer list self.answers[str(block_id)] = list() next_answer_id = 0 for line in data.split('\n'): is_hint = False is_correct = False is_multi_line = False line = line.lstrip() # self._normalize(line) line = line.split(' ', 1) try: #print repr(line[1]) line_starter = line[0] line_data = line[1].lstrip() # Correct answers end to an exclamation mark if line_starter.endswith('!'): line_starter = line_starter[:-1] + '.' is_correct = True elif line_starter.endswith(':') and next_answer_id != 0: is_hint = True if next_answer_id != 0: previous_prefix = multi_choice_args[next_answer_id - 1]['prefix'] if line_starter == previous_prefix: is_multi_line = True except IndexError: # When we fail to split the line continue # If it's a hint or similar, add it to args of the previous multiple choice prev_id = next_answer_id - 1 #temp_args.append({}) if is_hint and prev_id >= 0: try: temp_args[prev_id]['hint_text'] += '\n' + line_data except KeyError: temp_args[prev_id]['hint_text'] = line_data continue elif is_multi_line and prev_id >= 0: try: temp_args[prev_id]['question_text'] += '\n' + line_data except KeyError: temp_args[prev_id]['question_text'] = line_data continue else: try: prev = multi_choice_args[prev_id] temp = temp_args[prev_id] prev['html'] = self.snippet_renderer.render(temp['question_text']) prev['hint'] = self.snippet_renderer.render(temp['hint_text']) except (IndexError, KeyError): # In case we get here it means this is the first line # just pass and generate the next answer pass next_answer_id += 1 if is_correct: # If the answer parsed is marked as being correct, add it to # our correct answer collection self.answers[str(block_id)].append(str(next_answer_id)) # Add the question text to temporary list temp_args.append({'question_text': line_data, 'hint_text': ''}) multi_choice_args.append({ 'id': next_answer_id, 'prefix': line_starter, 'hint_class': 'success' if is_correct else 'error' }) # Special case for the last item in list prev_id = next_answer_id - 1 try: prev = multi_choice_args[prev_id] temp = temp_args[prev_id] except IndexError: return '' #print repr(temp['question_text']) prev['html'] = self.snippet_renderer.render(temp['question_text']) prev['hint'] = self.snippet_renderer.render(temp['hint_text']) bb_model_args = json.dumps({'choices': multi_choice_args}) bb_view_args = json.dumps(bb_view_args) # THIS MUST BE DONE WITH ALL MACROS THAT UTILIZE BB-MODELS! bb_escape = "" if m_args["root_level"] else "\\" html_block = "<m4ed-{block_id} />".format(block_id=block_id) script_block = self.render_bb_macro( block_id=block_id, bb_view='multi', bb_model_args=bb_model_args, bb_view_args=bb_view_args, bb_escape=bb_escape ) # THIS MUST BE DONE WITH ALL MACROS THAT UTILIZE BB-MODELS! if not m_args["root_level"]: script_block = script_block.replace('"', "\\\"") self.post_process_blocks.append(( html_block, script_block )) return html_block def handle_audio_macro(self, m_args, debug=DEBUG): if debug: print "--> in audio macro" block_id = m_args.pop('block_id', None) if block_id is None: raise ValueError('block_id was undefined') # If there was anything passed with keyword 'data' render it # using sundown # default = m_args.pop('default', None) # if default: # imgid = default # data = '' # else: # data = m_args.pop('data', None) # if data: # data = self.snippet_renderer.render(data) # imgid = m_args.pop('id', None) bb_model_args = json.dumps({'url': m_args.get('url', '')}) # THIS MUST BE DONE WITH ALL MACROS THAT UTILIZE BB-MODELS! bb_escape = "" if m_args["root_level"] else "\\" html_block = "<m4ed-{block_id} />".format(block_id=block_id) script_block = self.render_bb_macro( block_id=block_id, bb_view='audio', bb_model_args=bb_model_args, bb_escape=bb_escape ) # THIS MUST BE DONE WITH ALL MACROS THAT UTILIZE BB-MODELS! if not m_args["root_level"]: script_block = script_block.replace('"', "\\\"") self.post_process_blocks.append(( html_block, script_block )) return html_block def _find_all(self, text, sub): """Finds all occurrences of sub from text, return generators""" start = 0 while True: start = text.find(sub, start) if start == -1: return yield start start += len(sub) - 1 def preprocess(self, text, debug=DEBUG): if debug: #print 'markdown PRE ---->' _mark = time.time() starts = list(self._find_all(text, "[[")) ends = list(self._find_all(text, "]]")) if len(starts) == 0: # no macros to process, return original text return text # strip out escaped starts '\[[' # check needed for "[[macro]]\" as x-1 at the pos 0 is last char of string if starts[0] != 0: starts[:] = [x for x in starts if not text[x - 1] == '\\'] else: starts[1:] = [x for x in starts[1:] if not text[x - 1] == '\\'] # strip out escaped ends '\]]' ends[:] = [x for x in ends if not text[x - 1] == '\\'] stack = [] macros = [] root_levels = [] while ends: while (len(starts) > 0) and (starts[0] < ends[0]): stack.append(starts.pop(0)) if stack: root_levels.append(False) if len(stack) > 1 else root_levels.append(True) macro = ((stack.pop(), ends.pop(0) + 2)) macros.append(macro) else: # handles only the "]][[" situation ends.pop(0) # macros are in such order that innermost ones come first so we can # process them as they are. [[3. [[1.]] [[2.]]]] [[4.]] block_id = 0 while len(macros) > 0: m = macros.pop(0) macro = text[m[0] + 2:m[1] - 2] func = macro.split(":", 1) # func name = func[0], rest is func[1] # if no args, it's all in func[0] func[0] = func[0].lower() if func[0] not in self.funcs: continue f_args = {"root_level": root_levels.pop(0)} if len(func) > 1: func_data = func[1].split("\n", 1) func_args = self.parse_quotes(func_data[0]) func_args = func_args.strip().split(",") for arg in func_args: arg = arg.strip().split("=") if len(arg) == 2: #[[macro: arg=val, arg=val]] f_args[arg[0].strip().lower()] = arg[1].strip() else: #[[macro: single arg]] #[[macro: key=value, single arg -> default]] #[[macro: default=val, key=val, single arg <discard]] if not f_args.get('default'): # do not override default arg if specified by user f_args['default'] = arg[0].strip() f_args["data"] = func_data[1] if len(func_data) > 1 else "" f_args["block_id"] = f_args.get("name", block_id) ret = self.funcs[func[0]](f_args) else: ret = self.funcs[func[0]](f_args) block_id += 1 # change is the difference between original and macro returned data change = len(ret) - (m[1] - m[0]) if m[0] == 0: text = ret + text[m[1]:] else: text = text[:m[0]] + ret + text[m[1]:] # now we need to re-adjust indexes for x, i in enumerate(macros): start = i[0] end = i[1] # [[this macro]] [[processed macro]] = after >> no change # [[processed macro]] [[this macro]] = before >> change both # start += change, end += change # [[this [[processed macro]] macro]] = inside >> change end += change # [[processed [[this macro]] macro]] = impossible as inner macros # get always processed first if m[1] <= i[0]: start += change end += change elif i[0] < m[0] and i[1] > m[1]: end += change macros[x] = (start, end) if debug: print 'misaka preprocess /->', (time.time() - _mark) * 1000, 'ms' return text def parse_quotes(self, text): # Try to determine if the text is quoted first_quote = 0 while True: quot = text.find('"', first_quote) apos = text.find("'", first_quote) if quot == apos: # Neither one was found break elif quot == -1: # Quote not found q = "'" elif apos == -1: # Apostrophe not found q = '"' else: # Both found, see which one was first q = '"' if quot < apos else "'" # Probably always 1 but you never know... quote_offset = len(q) first_quote = text.find(q, first_quote) if first_quote < 0: break # Move the first_quote starting pos so we don't unnecessarily # start find() from the same position first_quote += quote_offset second_quote = text.find(q, first_quote) if second_quote < 0: break # Escape the quoted text so it doesn't mess up our parser later on. # The 'entities' dictionary defines what characters we want to escape. # Example: "\alpha = \beta, 23" => # \alpha = \beta, 23 escaped_text = quoteattr( text[first_quote:second_quote], entities=self.entities )[quote_offset:-quote_offset] # Combine the quoted text back together after escaping it text = ( text[:first_quote - quote_offset] + escaped_text + text[second_quote + quote_offset:] ) return text def postprocess(self, text, debug=DEBUG): """preprocess --> markdownrender --> [text] postprocess""" if debug: #print '------------------------- postprocessing -------------------------' _mark = time.time() self.post_process_blocks.reverse() for tag, block in self.post_process_blocks: text = text.replace(tag, block) #self.post_process_blocks = list() if debug: print 'misaka postprocess \\->', (time.time() - _mark) * 1000, 'ms\n' return text def imgid_to_imgurl(self, imgid): a = self.mongo_db.assets.find_one({'id': imgid}) if not a or not a.get('url'): return self._404_img return a['url'] def math_to_img(self, math, debug=DEBUG): redis_db = self.redis_db if debug: print math m = hashlib.md5() m.update(math) db_key = 'img:png:' + str(m.hexdigest()) html = '<img alt="math" src="{}" />'.format(self.cache_route + db_key) if self.cloud: print 'We should now save to cloud' else: try: if redis_db.exists(db_key): ttl = redis_db.ttl(db_key) if debug: print 'Cache hit! Serving the cached img and refreshing cache!' print 'The TTL remaining was', ttl, 'seconds' print ' => TTL now ', self.cache_time, 'seconds' # Refresh the cache expire timer redis_db.expire(db_key, self.cache_time) return html if debug: log.info('Cache miss! Generating a new img!') except ConnectionError: return '' _input = BytesIO(str('${0}$'.format(math))) output = BytesIO() self.math_to_image(_input.getvalue(), output, color='black', dpi=120, fontsize=10) if self.cloud: #self.work_queue.send('save:') print 'We should now save to cloud' else: redis_db.set(db_key, output.getvalue()) # Cache images for 1 minute(s) redis_db.expire(db_key, self.cache_time) return html def math_to_image(self, s, filename_or_obj, color='black', dpi=None, fontsize=10): """ This function is a thread safe modification of matplotlib's mathtext:math_to_image. The MathTextParser render's font caching mechanism makes it impossible to use with multiple threads. Thus we first have to acquire a lock from matplotlib RendererAgg and block other threads from entering render while it's in process. Given a math expression, renders it in a closely-clipped bounding box to an image file. *s* A math expression. The math portion should be enclosed in dollar signs. *filename_or_obj* A filepath or writable file-like object to write the image data to. *color* Text color *dpi* Override the output dpi, otherwise use the default associated with the output format. *fontsize* The font size, defaults to 10. """ try: s = unicode(s) except UnicodeDecodeError: s = unicode(filters.force_utf8(s).decode('utf-8')) RendererAgg.lock.acquire() try: self.math_text_parser.to_png(filename_or_obj, s, color=color, dpi=dpi, fontsize=fontsize) except (ParseFatalException, AttributeError): # Probably some invalid arguments supplied for math parser # We can most likely ignore them pass finally: RendererAgg.lock.release()
#---------------------------------import--------------------------------------- import sys import misaka as m from misaka import HtmlRenderer, Markdown from pygments import highlight from pygments.lexers import get_lexer_by_name from pygments.formatters import HtmlFormatter #------------------------------------------------------------------------------ class ColorRenderer(HtmlRenderer): def block_code(self, text, lang): if not lang: return '<pre><code>%s</code></pre>' % text.strip() lexer = get_lexer_by_name(lang, stripall = True) return highlight(text, lexer, HtmlFormatter()) if __name__ == '__main__': if len(sys.argv) > 1: with open(sys.argv[1], 'r') as fd: text = fd.read() else: text = sys.stdin.read() text = text.decode('utf-8') flags = m.HTML_HARD_WRAP exts = m.EXT_FENCED_CODE | m.EXT_AUTOLINK | m.EXT_NO_INTRA_EMPHASIS | m.EXT_SUPERSCRIPT | m.EXT_TABLES md = Markdown(ColorRenderer(flags), exts) print md.render(text).encode('utf-8') ###############################################################################
def setup(self): self.r = Markdown(HtmlRenderer()).render
def image(self, link, title, alt_text): """Don't allow images (they could be big). Use simple links intead. """ # Don't forget about escaping return '<a href="{0}">{0}</a>'.format(xhtml_escape(link)) def block_code(self, code, language): # Don't forget about escaping code = ignore_trailing_newlines(xhtml_escape(code)) if language: language = xhtml_escape(language) klass = ' class="language-{0}"'.format(language) else: klass = '' return '<pre><code{0}>{1}</code></pre>\n'.format(klass, code) # Don't touch HTML_ESCAPE flag! renderer = BnwRenderer(m.HTML_ESCAPE | m.HTML_SAFELINK) markdown_parser = Markdown( renderer, m.EXT_NO_INTRA_EMPHASIS | m.EXT_AUTOLINK | m.EXT_FENCED_CODE) class MarkdownFormat(object): def format(self, raw, secure=False): raw = _unicode(raw) formatted_text = ignore_trailing_newlines(markdown_parser.render(raw)) thumbs = get_thumbs(raw, secure) return formatted_text, thumbs
def render_with(self, flag, text): return Markdown(self.r[flag]).render(text)
def md1(value): rndr = HtmlRenderer() md = Markdown(rndr) return md.render(value)
class VimwikiHtmlRenderer(HtmlRenderer, LinkPreprocessor): # pass def block_code(self, text, lang): if not lang: return '\n<pre><code>%s</code></pre>\n' % \ h.escape_html(text.strip()) lexer = get_lexer_by_name(lang, stripall=True) formatter = CodeHtmlFormatter() return highlight(text, lexer, formatter) renderer = VimwikiHtmlRenderer(HTML_TOC | HTML_ESCAPE) to_html = Markdown(renderer, extensions= EXT_NO_INTRA_EMPHASIS | EXT_TABLES | EXT_FENCED_CODE | EXT_AUTOLINK | EXT_STRIKETHROUGH ) main_content = to_html.render(input_file) if renderer.percent_codes['no_html']: print(output_file_path + " not converted due to presence of " "'%nohtml' in the file.") else: if renderer.percent_codes['toc']: toc_renderer = VimwikiTocRenderer() to_toc = Markdown(toc_renderer, extensions = EXT_NO_INTRA_EMPHASIS | EXT_AUTOLINK) toc_content = to_toc.render(input_file) else: toc_content = None
return '<th%s>%s</th>\n' % (align, text) else: return '<td%s>%s</td>\n' % (align, text) def autolink(self, link, is_email): if is_email: return '<a href="mailto:%(link)s">%(link)s</a>' % {'link': link} else: return '<a href="%(link)s">%(link)s</a>' % {'link': link} def preprocess(self, text): return text.replace(' ', '_') md = Markdown(BleepRenderer(), EXT_FENCED_CODE | EXT_TABLES | EXT_AUTOLINK | EXT_STRIKETHROUGH | EXT_SUPERSCRIPT) print(md.render(''' Unordered - One - Two - Three And now ordered: 1. Three 2. Two 3. One