Пример #1
0
    def setup(self):
        class MyBlockRenderer(HtmlRenderer):
            def block_code(self, text, lang):
                return '<pre class="unique-%s">%s</pre>' % (lang, text)

            def block_quote(self, text):
                return '<blockquote cite="my">\n%s</blockquote>' % (text)

            def block_html(self, text):
                return 'This is html: %s' % (text)

            def header(self, text, level):
                return '<h%d class="custom">%s</h%d>' % (level, text, level)

            def hrule(self):
                return 'HR\n'

            def list(self, text, flags):
                return 'LIST\n%s' % (text)

            def list_item(self, text, flags):
                return '[LIST ITEM:%s]\n' % (text.strip())

            def footnotes(self, text):
                return '[FOOT: %s]' % (text)

            def footnote_def(self, text, num):
                return '[DEF: text=%s, num=%d' % (text, num)

        class MyTableRenderer(HtmlRenderer):
            def table(self, content):
                return '[TABLE content:%s]' % (content)

            def table_header(self, header):
                return '[HEADER: %s]\n' % (header)

            def table_body(self, body):
                return '[BODY: %s]' % (body)

            def table_row(self, text):
                return '[ROW:%s]' % text

            def table_cell(self, text, flag):
                return '<CELL>%s</CELL>' % text

        class MyParagraphRenderer(HtmlRenderer):
            def paragraph(self, text):
                return 'PARAGRAPH:%s\n' % text

        self.br = Markdown(MyBlockRenderer(), extensions=EXT_FENCED_CODE | EXT_FOOTNOTES)
        self.tr = Markdown(MyTableRenderer(), extensions=EXT_FENCED_CODE | EXT_TABLES)
        self.pr = Markdown(MyParagraphRenderer(), extensions=EXT_FENCED_CODE)
Пример #2
0
    def init_template(self):
        # Markdown renderer
        self.rndr = HtmlRenderer()
        self.md = Markdown(self.rndr)

        # Jinja templates
        self.jt = template = env.get_template("header.html")
        self.update_buffer()
Пример #3
0
    def load_posts(self):
        queue = []
        for root, dirs, files in os.walk(self.defaults['posts']):
            for f in files:
                if f.endswith('.md'):
                    queue.append(os.path.join(root, f))

        # process
        for p in queue:
            fm = frontmatter.load(p)
            # check if post or standalone
            standalone = bool(fm.get('standalone', False))
            if standalone:
                post = dict(
                    title=fm.get('title', 'Untitled'),
                    slug=slugify(unicode(fm.get('slug') or fm.get('title'))),
                    template=fm.get('template'),
                    is_standalone=True,
                    content=Markdown(HtmlRenderer()).render(fm.content))
                self.standalones.append((
                    p,
                    post,
                ))
                continue

            # is post, fill out meta data
            post = dict(
                meta=dict(category=fm.get('category', 'none')),
                title=fm.get('title', 'Untitled'),
                slug=slugify(unicode(fm.get('slug') or fm.get('title'))),
                author=fm.get('author',
                              self.site.get('site_author', 'Anonymous')),
                is_standalone=False,
                content=Markdown(HtmlRenderer()).render(fm.content))
            if 'date' in fm.keys():
                post['meta']['date'] = dateutil.parser.parse(fm['date'])
            else:
                post['meta']['date'] = datetime.now()
            post['link'] = os.path.join('posts', post['slug'] + '.html')
            self.posts.append((
                p,
                post,
            ))
Пример #4
0
    def setup(self):
        class MySpanRenderer(HtmlRenderer):
            def autolink(self, link, type):
                return '[AUTOLINK] link=%s, type=%d' % (link, type)

            def codespan(self, text):
                return '[CODESPAN] %s' % text

            def double_emphasis(self, text):
                return '[DOUBLE EMPHASIS] %s' % text

            def emphasis(self, text):
                return '[EMPHASIS] %s' % text

            def underline(self, text):
                return '[UNDERLINE] %s' % text

            def highlight(self, text):
                return '[HIGHLIGHT] %s' % text

            def quote(self, text):
                return '[QUOTE] %s' % text

            def image(self, link, title, alt):
                return '[IMG] link=%s, title=%s, alt=%s' % (link, title, alt)

            def linebreak(self):
                return '[LB]'

            def link(self, content, link, title):
                return 'link=%s, title=%s, cont=%s' % (link, title, content)

            def raw_html(self, text):
                return '[RAWHTML]%s' % text

            def triple_emphasis(self, text):
                return '[STRONG] %s' % text

            def strikethrough(self, text):
                return '[DEL] %s' % text

            def superscript(self, text):
                return '[SUP] %s' % text

            def footnote_ref(self, num):
                return '[FOOTNOTE_REF] num=%d' % num

        self.sr = Markdown(MySpanRenderer(),
                           extensions=EXT_AUTOLINK | EXT_UNDERLINE |
                           EXT_HIGHLIGHT | EXT_QUOTE | EXT_STRIKETHROUGH |
                           EXT_SUPERSCRIPT | EXT_FOOTNOTES)
Пример #5
0
class EditWindow(Gtk.Window):
    def __init__(self):
        Gtk.Window.__init__(self, title="")
        self.set_border_width(5)
        self.set_default_size(800, 600)

        # Vertical box. Contains menu and PaneView
        self.vbox = Gtk.VBox(False, 2)
        self.add(self.vbox)
        self.init_menu()

        # Markdown Editor
        self.tv1 = GtkSource.View.new()
        self.tv1.set_left_margin(5)
        self.tv1.set_right_margin(5)
        self.tv1.set_name("markdownContent")
        self.tv1.set_show_line_numbers(True)
        self.tv1.set_show_line_marks(True)
        self.tv1.set_insert_spaces_instead_of_tabs(True)
        self.tv1.set_right_margin_position(80)
        self.tv1.set_tab_width(4)
        self.tv1.set_auto_indent(True)
        # self.tv1.set_highlight_current_line(True) #FIXME: Ugly color

        # Textbuffer
        self.buffer = GtkSource.Buffer()
        self.buffer.connect("changed", self.on_button_clicked)
        self.buffer.set_highlight_syntax(True)

        # Set textview buffer
        self.tv1.set_buffer(self.buffer)

        # Dunno
        lm = GtkSource.LanguageManager.get_default()
        language = lm.get_language("markdown")
        self.buffer.set_language(language)
        self.tv1.connect("key-press-event", self.on_key_press)

        # WebKit
        self.wv = WebKit.WebView()
        self.wv.connect("navigation-policy-decision-requested", self.on_navigation)

        # Scrolled Window 1 (for markdown)
        sw1 = Gtk.ScrolledWindow()
        sw1.set_hexpand(False)
        sw1.set_vexpand(True)

        # Scrolled Window 2 (for webkit)
        sw2 = Gtk.ScrolledWindow()
        sw2.set_hexpand(False)
        sw2.set_vexpand(True)

        # Add textview and webkit
        sw1.add(self.tv1)
        sw2.add(self.wv)

        # PaneView, contains markdown editor and html view (webkit)
        hpaned = Gtk.HPaned()
        hpaned.pack1(sw1, True, True)
        hpaned.pack2(sw2, True, True)
        self.vbox.pack_start(hpaned, True, True, 0)

        # Init Jinja, markdown
        self.init_template()

        # Load editor gtk styles
        self.load_styles()

        # Set windows title
        self.set_win_title()

        self.current_filepath = None

    def load_file_dialog(self, widget):
        dialog = Gtk.FileChooserDialog(
            "Open file",
            self,
            Gtk.FileChooserAction.SAVE,
            (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_OPEN, Gtk.ResponseType.OK),
        )

        self.add_filters(dialog)
        response = dialog.run()

        if response == Gtk.ResponseType.OK:
            self.load_file(dialog.get_filename())
        elif response == Gtk.ResponseType.CANCEL:
            pass  # TODO? User cancelled

        dialog.destroy()

    def load_file(self, file_path=None):
        self.current_filename = "untitled"
        self.current_filepath = file_path

        if self.current_filepath:
            f = open(self.current_filepath, "r")
            self.buffer.set_text(f.read())
            f.close()
            self.current_filename = file_path.split("/")[-1]

        self.set_win_title(self.current_filename)
        self.update_buffer()

    def save_current_file(self, widget):
        fp = self.current_filepath
        if fp:
            f = open(fp, "w")
            f.write(self.get_buffer())
            f.close()

    def set_win_title(self, cztitle=None):
        title = "Markdown Editor"
        if cztitle:
            title = "{0} - {1}".format(title, cztitle)
        self.set_title(title)

    def init_menu(self):
        self.mb = Gtk.MenuBar()
        filemenu = Gtk.Menu()
        filem = Gtk.MenuItem("File")
        filem.set_submenu(filemenu)

        exit = Gtk.MenuItem("Exit")
        exit.connect("activate", Gtk.main_quit)
        save_as = Gtk.MenuItem("Save As...")
        save_as.connect("activate", self.save_as_dialog)

        load = Gtk.MenuItem("Open file...")
        load.connect("activate", self.load_file_dialog)

        action_save = Gtk.MenuItem("Save")
        action_save.connect("activate", self.save_current_file)

        filemenu.append(action_save)
        filemenu.append(load)
        filemenu.append(save_as)
        filemenu.append(exit)
        self.mb.append(filem)
        self.vbox.pack_start(self.mb, False, False, 0)

    def save_as_dialog(self, widget):
        dialog = Gtk.FileChooserDialog(
            "Save file",
            self,
            Gtk.FileChooserAction.SAVE,
            (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_SAVE, Gtk.ResponseType.OK),
        )

        self.add_filters(dialog)
        response = dialog.run()

        if response == Gtk.ResponseType.OK:
            fname = dialog.get_filename()
            f = open(fname, "w")
            f.write(self.get_buffer())
            f.close()
        elif response == Gtk.ResponseType.CANCEL:
            pass  # TODO? User cancelled

        dialog.destroy()

    def add_filters(self, dialog):
        filter_text = Gtk.FileFilter()

        filter_markdown = Gtk.FileFilter()
        filter_markdown.set_name("Markdown ")
        filter_markdown.add_mime_type("text/x-markdown")
        dialog.add_filter(filter_markdown)

        filter_text.set_name("Plain text")
        filter_text.add_mime_type("text/plain")
        dialog.add_filter(filter_text)

        filter_any = Gtk.FileFilter()
        filter_any.set_name("Any files")
        filter_any.add_pattern("*")
        dialog.add_filter(filter_any)

    def init_template(self):
        # Markdown renderer
        self.rndr = HtmlRenderer()
        self.md = Markdown(self.rndr)

        # Jinja templates
        self.jt = template = env.get_template("header.html")
        self.update_buffer()

    def load_styles(self):
        self.style_provider = Gtk.CssProvider()

        css = open("themes/gtk.css", "rb")
        css_data = css.read()
        css.close()
        self.style_provider.load_from_data(css_data)

        Gtk.StyleContext.add_provider_for_screen(
            Gdk.Screen.get_default(), self.style_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION
        )

    def on_key_press(self, widget, event):
        self.update_buffer()

    def on_button_clicked(self, widget):
        self.update_buffer()

    def get_buffer(self):
        contentBuffer = self.buffer
        text = contentBuffer.get_text(contentBuffer.get_start_iter(), contentBuffer.get_end_iter(), False).decode(
            "utf-8"
        )
        return text

    def update_buffer(self):
        # Fetch Text from buffer
        text = self.get_buffer()

        # Convert markdown text into html
        html_content = self.md.render(text)

        # Render template using Jinja
        rendered = self.jt.render(content=html_content)

        # Load page to WebView
        self.wv.load_string(rendered, "text/html", "utf-8", "/")

    def on_navigation(self, web_view, frame, request, nav_action, policy_decision, data=None):
        if request.get_uri() != "/":
            policy_decision.ignore()
Пример #6
0
class MarkdownSpanCustomRendererTest(TestCase):
    name = 'Markdown Span Custom Renderer'

    def setup(self):
        class MySpanRenderer(HtmlRenderer):
            def autolink(self, link, type):
                return '[AUTOLINK] link=%s, type=%d' % (link, type)

            def codespan(self, text):
                return '[CODESPAN] %s' % text

            def double_emphasis(self, text):
                return '[DOUBLE EMPHASIS] %s' % text

            def emphasis(self, text):
                return '[EMPHASIS] %s' % text

            def underline(self, text):
                return '[UNDERLINE] %s' % text

            def highlight(self, text):
                return '[HIGHLIGHT] %s' % text

            def quote(self, text):
                return '[QUOTE] %s' % text

            def image(self, link, title, alt):
                return '[IMG] link=%s, title=%s, alt=%s' % (link, title, alt)

            def linebreak(self):
                return '[LB]'

            def link(self, content, link, title):
                return 'link=%s, title=%s, cont=%s' % (link, title, content)

            def raw_html(self, text):
                return '[RAWHTML]%s' % text

            def triple_emphasis(self, text):
                return '[STRONG] %s' % text

            def strikethrough(self, text):
                return '[DEL] %s' % text

            def superscript(self, text):
                return '[SUP] %s' % text

            def footnote_ref(self, num):
                return '[FOOTNOTE_REF] num=%d' % num

        self.sr = Markdown(MySpanRenderer(),
                           extensions=EXT_AUTOLINK | EXT_UNDERLINE |
                           EXT_HIGHLIGHT | EXT_QUOTE | EXT_STRIKETHROUGH |
                           EXT_SUPERSCRIPT | EXT_FOOTNOTES)

    def test_autolink(self):
        text = self.sr.render('<https://github.com/>')
        ok(text).contains('[AUTOLINK] link=https://github.com/, type=0')

    def test_codespan(self):
        text = self.sr.render('code `print 1`')
        ok(text).contains('code [CODESPAN] print 1')

    def test_emphasis(self):
        text = self.sr.render('*emphasis*')
        ok(text).contains('[EMPHASIS] emphasis')

    def test_double_emphasis(self):
        text = self.sr.render('**emphasis**')
        ok(text).contains('[DOUBLE EMPHASIS] emphasis')

    def test_underline(self):
        text = self.sr.render('_line_')
        ok(text).contains('[UNDERLINE] line')

    def test_highlight(self):
        text = self.sr.render('==line==')
        ok(text).contains('[HIGHLIGHT] line')

    def test_quote(self):
        text = self.sr.render('"spanquote"')
        ok(text).contains('[QUOTE] spanquote')

    def test_image(self):
        text = self.sr.render('![alt-string](path)')
        ok(text).contains('[IMG] link=path, title=None, alt=alt-string')

    def test_linebreak(self):
        text = self.sr.render('test    \ntest\n')
        ok(text).contains('test[LB]test')

    def test_link(self):
        text = self.sr.render('[span link](https://github.com/ "github")')
        ok(text).contains('link=https://github.com/, title=github, cont=span link')

    def test_raw_html(self):
        text = self.sr.render('<raw>raw_html</raw>')
        ok(text).contains('[RAWHTML]<raw>raw_html[RAWHTML]</raw>')

    def test_triple_emphasis(self):
        text = self.sr.render('***triple emphasis***')
        ok(text).contains('[STRONG] triple emphasis')

    def test_strikethrough(self):
        text = self.sr.render('~~strikethrough~~')
        ok(text).contains('[DEL] strikethrough')

    def test_superscript(self):
        text = self.sr.render('^(superscript)')
        ok(text).contains('[SUP] superscript')

    def test_footnote_ref(self):
        text = self.sr.render('line1 [^1]\n\n [^1]: test1\n       test2\n')
        ok(text).contains('[FOOTNOTE_REF] num=1')
Пример #7
0
class MarkdownBlockCustomRendererTest(TestCase):
    name = 'Markdown Block Custom Renderer'

    def setup(self):
        class MyBlockRenderer(HtmlRenderer):
            def block_code(self, text, lang):
                return '<pre class="unique-%s">%s</pre>' % (lang, text)

            def block_quote(self, text):
                return '<blockquote cite="my">\n%s</blockquote>' % (text)

            def block_html(self, text):
                return 'This is html: %s' % (text)

            def header(self, text, level):
                return '<h%d class="custom">%s</h%d>' % (level, text, level)

            def hrule(self):
                return 'HR\n'

            def list(self, text, flags):
                return 'LIST\n%s' % (text)

            def list_item(self, text, flags):
                return '[LIST ITEM:%s]\n' % (text.strip())

            def footnotes(self, text):
                return '[FOOT: %s]' % (text)

            def footnote_def(self, text, num):
                return '[DEF: text=%s, num=%d' % (text, num)

        class MyTableRenderer(HtmlRenderer):
            def table(self, content):
                return '[TABLE content:%s]' % (content)

            def table_header(self, header):
                return '[HEADER: %s]\n' % (header)

            def table_body(self, body):
                return '[BODY: %s]' % (body)

            def table_row(self, text):
                return '[ROW:%s]' % text

            def table_cell(self, text, flag):
                return '<CELL>%s</CELL>' % text

        class MyParagraphRenderer(HtmlRenderer):
            def paragraph(self, text):
                return 'PARAGRAPH:%s\n' % text

        self.br = Markdown(MyBlockRenderer(), extensions=EXT_FENCED_CODE | EXT_FOOTNOTES)
        self.tr = Markdown(MyTableRenderer(), extensions=EXT_FENCED_CODE | EXT_TABLES)
        self.pr = Markdown(MyParagraphRenderer(), extensions=EXT_FENCED_CODE)

    def test_fenced_code(self):
        text = self.br.render('```python\ndef foo():\n   pass\n```')
        ok(text).contains('unique-python')

    def test_block_quotes(self):
        text = self.br.render(
            'A wise man once said:\n\n'
            ' > Isn\'t it wonderful just to be alive.\n')
        ok(text).diff('<p>A wise man once said:</p>\n'
                      '<blockquote cite="my">\n'
                      '<p>Isn&#39;t it wonderful just to be alive.</p>\n</blockquote>')

    def test_raw_block(self):
        text = self.br.render('<p>raw</p>\n')
        ok(text).diff('This is html: <p>raw</p>\n')

    def test_header(self):
        text = self.br.render('custom\n======\n')
        ok(text).diff('<h1 class="custom">custom</h1>')

    def test_hrule(self):
        text = self.br.render('* * *')
        ok(text).diff('HR\n')

    def test_list(self):
        text = self.br.render('* one\n* two')
        ok(text).diff('LIST\n[LIST ITEM:one]\n[LIST ITEM:two]\n')

    def test_footnotes(self):
        text = self.br.render('line1 [^1]\n\n [^1]: test1\n       test2\n')
        ok(text).contains('FOOT')
        ok(text).contains('DEF')

    def test_table(self):
        text = self.tr.render('name | age\n-----|----\nMike | 30')
        ok(text).diff('[TABLE content:[HEADER: [ROW:<CELL>name</CELL><CELL>age</CELL>]]\n'
                      '[BODY: [ROW:<CELL>Mike</CELL><CELL>30</CELL>]]]')

    def test_paragraph(self):
        text = self.pr.render('one\n\ntwo')
        ok(text).diff('PARAGRAPH:one\nPARAGRAPH:two\n')