Exemple #1
0
    def run(self, view, wholefile=False, preview=False):
        ''' return full html and body html for view. '''
        self.settings = Settings('MarkdownPreview.sublime-settings',
                                 view.file_name())
        self.preview = preview
        self.view = view

        contents = self.get_contents(wholefile)

        body = self.convert_markdown(contents)

        html_template = self.settings.get('html_template')

        # use customized html template if given
        if self.settings.get('html_simple', False):
            html = body
        elif html_template and os.path.exists(html_template):
            head = u''
            head += self.get_meta()
            if not self.settings.get('skip_default_stylesheet'):
                head += self.get_stylesheet()
            head += self.get_javascript()
            head += self.get_highlight()
            head += self.get_mathjax()
            head += self.get_uml()
            head += self.get_title()

            html = load_utf8(html_template)
            html = html.replace('{{ HEAD }}', head, 1)
            html = html.replace('{{ BODY }}', body, 1)
        else:
            html = u'<!DOCTYPE html>'
            html += '<html><head><meta charset="utf-8">'
            html += '<html><head><meta name="viewport" content="width=device-width,initial-scale=1.0"/>'
            html += self.get_meta()
            html += self.get_stylesheet()
            html += self.get_javascript()
            html += self.get_highlight()
            html += self.get_mathjax()
            html += self.get_uml()
            html += self.get_title()
            html += '</head><body>'
            html += '<article class="markdown-body">'
            html += body
            html += '</article>'
            html += '</body>'
            html += '</html>'

        return html, body
    def run(self):
        ''' return full html and body html for view. '''
        self.settings = Settings('MarkdownPreview.sublime-settings',
                                 self.filename)

        contents = self.get_contents(self.filename)

        body = self.convert_markdown(contents)

        # add self.html_template, it can be assigned.
        if self.html_template is None:
            html_template = self.settings.get('html_template')
        else:
            html_template = self.html_template

        # use customized html template if given
        if self.settings.get('html_simple', False):
            html = body
        elif html_template and os.path.exists(html_template):
            head = u''
            head += self.get_meta()
            if not self.settings.get('skip_default_stylesheet'):
                head += self.get_stylesheet()
            head += self.get_javascript()
            head += self.get_highlight()
            head += self.get_mathjax()
            head += self.get_uml()
            head += self.get_title()

            html = load_utf8(html_template)
            html = html.replace('{{ HEAD }}', head, 1)
            html = html.replace('{{ BODY }}', body, 1)
        else:
            html = u'<!DOCTYPE html>'
            html += '<html><head><meta charset="utf-8">'
            html += self.get_meta()
            html += self.get_stylesheet()
            html += self.get_javascript()
            html += self.get_highlight()
            html += self.get_mathjax()
            html += self.get_title()
            html += '</head><body>'
            html += body
            html += '</body>'
            html += '</html>'

        return html, body
    def run(self, view, wholefile=False, preview=False):
        ''' return full html and body html for view. '''
        self.settings = Settings('MarkdownPreview.sublime-settings', view.file_name())
        self.preview = preview
        self.view = view

        contents = self.get_contents(wholefile)

        body = self.convert_markdown(contents)

        html_template = self.settings.get('html_template')

        # use customized html template if given
        if self.settings.get('html_simple', False):
            html = body
        elif html_template and os.path.exists(html_template):
            head = u''
            head += self.get_meta()
            if not self.settings.get('skip_default_stylesheet'):
                head += self.get_stylesheet()
            head += self.get_javascript()
            head += self.get_highlight()
            head += self.get_mathjax()
            head += self.get_uml()
            head += self.get_title()

            html = load_utf8(html_template)
            html = html.replace('{{ HEAD }}', head, 1)
            html = html.replace('{{ BODY }}', body, 1)
        else:
            html = u'<!DOCTYPE html>'
            html += '<html><head><meta charset="utf-8">'
            html += '<html><head><meta name="viewport" content="width=device-width,initial-scale=1.0"/>'
            html += self.get_meta()
            html += self.get_stylesheet()
            html += self.get_javascript()
            html += self.get_highlight()
            html += self.get_mathjax()
            html += self.get_uml()
            html += self.get_title()
            html += '</head><body>'
            html += '<article class="markdown-body">'
            html += body
            html += '</article>'
            html += '</body>'
            html += '</html>'

        return html, body
    def run(self, view, wholefile=False, preview=False):
        """ return full html and body html for view. """
        self.settings = Settings("MarkdownPreview.sublime-settings", view.file_name())
        self.preview = preview
        self.view = view

        contents = self.get_contents(wholefile)

        body = self.convert_markdown(contents)

        html_template = self.settings.get("html_template")

        # use customized html template if given
        if self.settings.get("html_simple", False):
            html = body
        elif html_template and os.path.exists(html_template):
            head = u""
            head += self.get_meta()
            if not self.settings.get("skip_default_stylesheet"):
                head += self.get_stylesheet()
            head += self.get_javascript()
            head += self.get_highlight()
            head += self.get_mathjax()
            head += self.get_uml()
            head += self.get_title()

            html = load_utf8(html_template)
            html = html.replace("{{ HEAD }}", head, 1)
            html = html.replace("{{ BODY }}", body, 1)
        else:
            html = u"<!DOCTYPE html>"
            html += '<html><head><meta charset="utf-8">'
            html += self.get_meta()
            html += self.get_stylesheet()
            html += self.get_javascript()
            html += self.get_highlight()
            html += self.get_mathjax()
            html += self.get_uml()
            html += self.get_title()
            html += "</head><body>"
            html += '<article class="markdown-body">'
            html += body
            html += "</article>"
            html += "</body>"
            html += "</html>"

        return html, body
    def run(self):
        ''' return full html and body html for view. '''
        self.settings = Settings('MarkdownPreview.sublime-settings', self.filename)

        contents = self.get_contents(self.filename)

        body = self.convert_markdown(contents)

        # add self.html_template, it can be assigned.
        if self.html_template is None:
            html_template = self.settings.get('html_template')
        else:
            html_template = self.html_template

        # use customized html template if given
        if self.settings.get('html_simple', False):
            html = body
        elif html_template and os.path.exists(html_template):
            head = u''
            head += self.get_meta()
            if not self.settings.get('skip_default_stylesheet'):
                head += self.get_stylesheet()
            head += self.get_javascript()
            head += self.get_highlight()
            head += self.get_mathjax()
            head += self.get_uml()
            head += self.get_title()

            html = load_utf8(html_template)
            html = html.replace('{{ HEAD }}', head, 1)
            html = html.replace('{{ BODY }}', body, 1)
        else:
            html = u'<!DOCTYPE html>'
            html += '<html><head><meta charset="utf-8">'
            html += self.get_meta()
            html += self.get_stylesheet()
            html += self.get_javascript()
            html += self.get_highlight()
            html += self.get_mathjax()
            html += self.get_title()
            html += '</head><body>'
            html += body
            html += '</body>'
            html += '</html>'

        return html, body
class Compiler(object):
    """ Do the markdown converting """

    default_css = "markdown.css"

    def isurl(self, css_name):
        match = re.match(r"https?://", css_name)
        if match:
            return True
        return False

    def get_font_css(self):
        fonts = ""
        css_names = ["fonts/migu-1c-regular.css"]
        for css_name in css_names:
            fonts = u"%s%s" % (fonts, load_resource(css_name))

        return u"<style>%s</style>" % fonts

    def get_default_css(self):
        """ locate the correct CSS with the 'css' setting """
        css_name = self.settings.get("css", "default")

        if self.isurl(css_name):
            # link to remote URL
            return u"<link href='%s' rel='stylesheet' type='text/css'>" % css_name
        elif os.path.isfile(os.path.expanduser(css_name)):
            # use custom CSS file
            return u"<style>%s</style>" % load_utf8(os.path.expanduser(css_name))
        elif css_name == "default":
            # use parser CSS file
            return u"<style>%s</style>" % load_resource(self.default_css)

        return ""

    def get_override_css(self):
        """ handls allow_css_overrides setting. """

        if self.settings.get("allow_css_overrides"):
            filename = self.view.file_name()
            filetypes = self.settings.get("markdown_filetypes")

            if filename and filetypes:
                for filetype in filetypes:
                    if filename.endswith(filetype):
                        css_filename = filename.rpartition(filetype)[0] + ".css"
                        if os.path.isfile(css_filename):
                            return u"<style>%s</style>" % load_utf8(css_filename)
        return ""

    def get_stylesheet(self):
        """ return the correct CSS file based on parser and settings """
        return self.get_font_css() + self.get_default_css() + self.get_override_css()

    def get_javascript(self):
        js_files = self.settings.get("js")
        scripts = ""

        if js_files is not None:
            # Ensure string values become a list.
            if isinstance(js_files, str) or isinstance(js_files, unicode_str):
                js_files = [js_files]
            # Only load scripts if we have a list.
            if isinstance(js_files, list):
                for js_file in js_files:
                    if os.path.isabs(js_file):
                        # Load the script inline to avoid cross-origin.
                        scripts += u"<script>%s</script>" % load_utf8(js_file)
                    else:
                        scripts += u"<script type='text/javascript' src='%s'></script>" % js_file
        return scripts

    def get_mathjax(self):
        """ return the MathJax script if enabled """

        if self.settings.get("enable_mathjax") is True:
            return load_resource("mathjax.html")
        return ""

    def get_uml(self):
        """ return the uml scripts if enabled """

        if self.settings.get("enable_uml") is True:
            flow = load_resource("flowchart-min.js")
            return load_resource("uml.html").replace("{{ flowchart }}", flow, 1)
        return ""

    def get_highlight(self):
        return ""

    def get_contents(self, wholefile=False):
        """ Get contents or selection from view and optionally strip the YAML front matter """
        region = sublime.Region(0, self.view.size())
        contents = self.view.substr(region)
        if not wholefile:
            # use selection if any
            selection = self.view.substr(self.view.sel()[0])
            if selection.strip() != "":
                contents = selection

        # Remove yaml front matter
        if self.settings.get("strip_yaml_front_matter") and contents.startswith("---"):
            frontmatter, contents = self.preprocessor_yaml_frontmatter(contents)
            self.settings.apply_frontmatter(frontmatter)

        references = self.settings.get("builtin").get("references", [])
        for ref in references:
            contents += get_references(ref)

        contents = self.parser_specific_preprocess(contents)

        return contents

    def parser_specific_preprocess(self, text):
        return text

    def preprocessor_yaml_frontmatter(self, text):
        """ Get frontmatter from string """
        frontmatter = {}

        if text.startswith("---"):
            m = re.search(r"^(---(.*?)---[ \t]*\r?\n)", text, re.DOTALL)
            if m:
                try:
                    frontmatter = yaml.load(m.group(2))
                except:
                    print(traceback.format_exc())
                text = text[m.end(1) :]

        return frontmatter, text

    def parser_specific_postprocess(self, text):
        return text

    def postprocessor_pathconverter(self, html, image_convert, file_convert, absolute=False):

        RE_TAG_HTML = r"""(?xus)
        (?:
            (?P<comments>(\r?\n?\s*)<!--[\s\S]*?-->(\s*)(?=\r?\n)|<!--[\s\S]*?-->)|
            (?P<open><(?P<tag>(?:%s)))
            (?P<attr>(?:\s+[\w\-:]+(?:\s*=\s*(?:"[^"]*"|'[^']*'))?)*)
            (?P<close>\s*(?:\/?)>)
        )
        """

        RE_TAG_LINK_ATTR = re.compile(
            r"""(?xus)
            (?P<attr>
                (?:
                    (?P<name>\s+(?:href|src)\s*=\s*)
                    (?P<path>"[^"]*"|'[^']*')
                )
            )
            """
        )

        RE_SOURCES = re.compile(
            RE_TAG_HTML
            % (
                (r"img" if image_convert else "")
                + (r"|" if image_convert and file_convert else "")
                + (r"script|a|link" if file_convert else "")
            )
        )

        def repl(m, base_path, rel_path=None):
            if m.group("comments"):
                tag = m.group("comments")
            else:
                tag = m.group("open")
                if rel_path is None:
                    tag += RE_TAG_LINK_ATTR.sub(lambda m2: repl_absolute(m2, base_path), m.group("attr"))
                else:
                    tag += RE_TAG_LINK_ATTR.sub(lambda m2: repl_relative(m2, base_path, rel_path), m.group("attr"))
                tag += m.group("close")
            return tag

        basepath = self.settings.get("builtin").get("basepath")
        if basepath is None:
            basepath = ""

        if absolute:
            if basepath:
                return RE_SOURCES.sub(lambda m: repl(m, basepath), html)
        else:
            if self.preview:
                relativepath = getTempMarkdownPreviewPath(self.view)
            else:
                relativepath = self.settings.get("builtin").get("destination")
                if not relativepath:
                    mdfile = self.view.file_name()
                    if mdfile is not None and os.path.exists(mdfile):
                        relativepath = os.path.splitext(mdfile)[0] + ".html"

            if relativepath:
                relativepath = os.path.dirname(relativepath)

            if basepath and relativepath:
                return RE_SOURCES.sub(lambda m: repl(m, basepath, relativepath), html)
        return html

    def postprocessor_base64(self, html):
        """ convert resources (currently images only) to base64 """

        file_types = {(".png",): "image/png", (".jpg", ".jpeg"): "image/jpeg", (".gif",): "image/gif"}

        exclusion_list = tuple(["https://", "http://", "#"] + ["data:%s;base64," % ft for ft in file_types.values()])

        RE_WIN_DRIVE = re.compile(r"(^[A-Za-z]{1}:(?:\\|/))")
        RE_TAG_HTML = re.compile(
            r"""(?xus)
            (?:
                (?P<comments>(\r?\n?\s*)<!--[\s\S]*?-->(\s*)(?=\r?\n)|<!--[\s\S]*?-->)|
                (?P<open><(?P<tag>img))
                (?P<attr>(?:\s+[\w\-:]+(?:\s*=\s*(?:"[^"]*"|'[^']*'))?)*)
                (?P<close>\s*(?:\/?)>)
            )
            """
        )
        RE_TAG_LINK_ATTR = re.compile(
            r"""(?xus)
            (?P<attr>
                (?:
                    (?P<name>\s+src\s*=\s*)
                    (?P<path>"[^"]*"|'[^']*')
                )
            )
            """
        )

        def b64(m):
            import base64

            src = url2pathname(m.group("path")[1:-1])
            data = m.group(0)
            base_path = self.settings.get("builtin").get("basepath")
            if base_path is None:
                base_path = ""

            # Format the link
            absolute = False
            if src.startswith("file://"):
                src = src.replace("file://", "", 1)
                if sublime.platform() == "windows" and not src.startswith("//"):
                    src = src.lstrip("/")
                absolute = True
            elif sublime.platform() == "windows" and RE_WIN_DRIVE.match(src) is not None:
                absolute = True

            # Make sure we are working with an absolute path
            if not src.startswith(exclusion_list):
                if absolute:
                    src = os.path.normpath(src)
                else:
                    src = os.path.normpath(os.path.join(base_path, src))

                if os.path.exists(src):
                    ext = os.path.splitext(src)[1].lower()
                    for b64_ext in file_types:
                        if ext in b64_ext:
                            try:
                                with open(src, "rb") as f:
                                    data = ' src="data:%s;base64,%s"' % (
                                        file_types[b64_ext],
                                        base64.b64encode(f.read()).decode("ascii"),
                                    )
                            except Exception:
                                pass
                            break
            return data

        def repl(m):
            if m.group("comments"):
                tag = m.group("comments")
            else:
                tag = m.group("open")
                tag += RE_TAG_LINK_ATTR.sub(lambda m2: b64(m2), m.group("attr"))
                tag += m.group("close")
            return tag

        return RE_TAG_HTML.sub(repl, html)

    def postprocessor_simple(self, html):
        """ Strip out ids and classes for a simplified HTML output """

        def repl(m):
            if m.group("comments"):
                tag = ""
            else:
                tag = m.group("open")
                tag += RE_TAG_BAD_ATTR.sub("", m.group("attr"))
                tag += m.group("close")
            return tag

        # Strip out id, class, on<word>, and style attributes for a simple html output
        RE_TAG_HTML = re.compile(
            r"""(?x)
            (?:
                (?P<comments>(\r?\n?\s*)<!--[\s\S]*?-->(\s*)(?=\r?\n)|<!--[\s\S]*?-->)|
                (?P<open><[\w\:\.\-]+)
                (?P<attr>(?:\s+[\w\-:]+(?:\s*=\s*(?:"[^"]*"|'[^']*'))?)*)
                (?P<close>\s*(?:\/?)>)
            )
            """,
            re.DOTALL | re.UNICODE,
        )

        RE_TAG_BAD_ATTR = re.compile(
            r"""(?x)
            (?P<attr>
                (?:
                    \s+(?:id|class|style|on[\w]+)
                    (?:\s*=\s*(?:"[^"]*"|'[^']*'))
                )*
            )
            """,
            re.DOTALL | re.UNICODE,
        )

        return RE_TAG_HTML.sub(repl, html)

    def convert_markdown(self, markdown_text):
        """ convert input markdown to HTML, with github or builtin parser """

        markdown_html = self.parser_specific_convert(markdown_text)

        image_convert = self.settings.get("image_path_conversion", "absolute")
        file_convert = self.settings.get("file_path_conversions", "absolute")

        markdown_html = self.parser_specific_postprocess(markdown_html)

        if "absolute" in (image_convert, file_convert):
            markdown_html = self.postprocessor_pathconverter(markdown_html, image_convert, file_convert, True)

        if "relative" in (image_convert, file_convert):
            markdown_html = self.postprocessor_pathconverter(markdown_html, image_convert, file_convert, False)

        if image_convert == "base64":
            markdown_html = self.postprocessor_base64(markdown_html)

        if self.settings.get("html_simple", False):
            markdown_html = self.postprocessor_simple(markdown_html)

        return markdown_html

    def get_title(self):
        if self.meta_title is not None:
            title = self.meta_title
        else:
            title = self.view.name()
        if not title:
            fn = self.view.file_name()
            title = "untitled" if not fn else os.path.splitext(os.path.basename(fn))[0]
        return "<title>%s</title>" % cgi.escape(title)

    def get_meta(self):
        self.meta_title = None
        meta = []
        for k, v in self.settings.get("meta", {}).items():
            if k == "title":
                if isinstance(v, list):
                    if len(v) == 0:
                        v = ""
                    else:
                        v = v[0]
                self.meta_title = unicode_str(v)
                continue
            if isinstance(v, list):
                v = ",".join(v)
            if v is not None:
                meta.append('<meta name="%s" content="%s">' % (cgi.escape(k, True), cgi.escape(v, True)))
        return "\n".join(meta)

    def run(self, view, wholefile=False, preview=False):
        """ return full html and body html for view. """
        self.settings = Settings("MarkdownPreview.sublime-settings", view.file_name())
        self.preview = preview
        self.view = view

        contents = self.get_contents(wholefile)

        body = self.convert_markdown(contents)

        html_template = self.settings.get("html_template")

        # use customized html template if given
        if self.settings.get("html_simple", False):
            html = body
        elif html_template and os.path.exists(html_template):
            head = u""
            head += self.get_meta()
            if not self.settings.get("skip_default_stylesheet"):
                head += self.get_stylesheet()
            head += self.get_javascript()
            head += self.get_highlight()
            head += self.get_mathjax()
            head += self.get_uml()
            head += self.get_title()

            html = load_utf8(html_template)
            html = html.replace("{{ HEAD }}", head, 1)
            html = html.replace("{{ BODY }}", body, 1)
        else:
            html = u"<!DOCTYPE html>"
            html += '<html><head><meta charset="utf-8">'
            html += self.get_meta()
            html += self.get_stylesheet()
            html += self.get_javascript()
            html += self.get_highlight()
            html += self.get_mathjax()
            html += self.get_uml()
            html += self.get_title()
            html += "</head><body>"
            html += '<article class="markdown-body">'
            html += body
            html += "</article>"
            html += "</body>"
            html += "</html>"

        return html, body
class Compiler(object):
    ''' Do the markdown converting '''
    default_css = "markdown.css"
    filename = "../first.md"
    html_template = None

    def __init__(self, file_name, html_template=None):
        self.filename = file_name

    def isurl(self, css_name):
        match = re.match(r'https?://', css_name)
        if match:
            return True
        return False

    def get_default_css(self):
        ''' locate the correct CSS with the 'css' setting '''
        css_name = self.settings.get('css', 'default')

        if self.isurl(css_name):
            # link to remote URL
            return u"<link href='%s' rel='stylesheet' type='text/css'>" % css_name
        elif os.path.isfile(os.path.expanduser(css_name)):
            # use custom CSS file
            return u"<style>%s</style>" % load_utf8(
                os.path.expanduser(css_name))
        elif css_name == 'default':
            # use parser CSS file
            return u"<style>%s</style>" % load_resource(self.default_css)

        return ''

    def get_override_css(self):
        ''' handls allow_css_overrides setting. '''

        if self.settings.get('allow_css_overrides'):
            filetypes = self.settings.get('markdown_filetypes')

            if self.filename and filetypes:
                for filetype in filetypes:
                    if self.filename.endswith(filetype):
                        css_filename = self.filename.rpartition(
                            filetype)[0] + '.css'
                        if (os.path.isfile(css_filename)):
                            return u"<style>%s</style>" % load_utf8(
                                css_filename)
        return ''

    def get_stylesheet(self):
        ''' return the correct CSS file based on parser and settings '''
        return self.get_default_css() + self.get_override_css()

    def get_javascript(self):
        js_files = self.settings.get('js')
        scripts = ''

        if js_files is not None:
            # Ensure string values become a list.
            if isinstance(js_files, str) or isinstance(js_files, unicode_str):
                js_files = [js_files]
            # Only load scripts if we have a list.
            if isinstance(js_files, list):
                for js_file in js_files:
                    if os.path.isabs(js_file):
                        # Load the script inline to avoid cross-origin.
                        scripts += u"<script>%s</script>" % load_utf8(js_file)
                    else:
                        scripts += u"<script type='text/javascript' src='%s'></script>" % js_file
        return scripts

    def get_mathjax(self):
        ''' return the MathJax script if enabled '''

        if self.settings.get('enable_mathjax') is True:
            return load_resource('mathjax.html')
        return ''

    def get_uml(self):
        ''' return the uml scripts if enabled '''

        if self.settings.get('enable_uml') is True:
            flow = load_resource('flowchart-min.js')
            return load_resource('uml.html').replace('{{ flowchart }}', flow,
                                                     1)
        return ''

    def get_highlight(self):
        return ''

    def get_contents(self, filename):
        ''' Get contents or selection from view and optionally strip the YAML front matter '''
        # TODO: 获取文件内容,从这里开始
        contents = load_resource(filename)

        # Remove yaml front matter
        if self.settings.get(
                'strip_yaml_front_matter') and contents.startswith('---'):
            frontmatter, contents = self.preprocessor_yaml_frontmatter(
                contents)
            self.settings.apply_frontmatter(frontmatter)

        references = self.settings.get('builtin').get('references', [])
        for ref in references:
            contents += get_references(ref)

        contents = self.parser_specific_preprocess(contents)

        return contents

    def parser_specific_preprocess(self, text):
        return text

    def preprocessor_yaml_frontmatter(self, text):
        """ Get frontmatter from string """
        frontmatter = {}

        if text.startswith("---"):
            m = re.search(r'^(---(.*?)---\r?\n)', text, re.DOTALL)
            if m:
                try:
                    frontmatter = yaml.load(m.group(2))
                except:
                    print(traceback.format_exc())
                text = text[m.end(1):]

        return frontmatter, text

    def parser_specific_postprocess(self, text):
        return text

    def postprocessor_absolute(self, html, image_convert, file_convert):
        ''' fix relative paths in images, scripts, and links for the internal parser '''
        def tag_fix(m):
            tag = m.group('tag')
            src = m.group('src')
            if self.filename:
                # TODO: delete paltform = windows
                if (not src.startswith(ABS_EXCLUDE)
                        and not (RE_WIN_DRIVE.match(src) is not None)):
                    # Don't explicitly add file:// prefix,
                    # But don't remove them either
                    abs_path = u'%s/%s' % (os.path.dirname(self.filename), src)
                    # Don't replace just the first instance,
                    # but explicitly place it where it was before
                    # to ensure a file name 'img' dosen't replace
                    # the tag name etc.
                    if os.path.exists(abs_path):
                        tag = m.group('begin') + abs_path + m.group('end')
            return tag

        # Compile the appropriate regex to find images and/or files
        RE_WIN_DRIVE = re.compile(r"(^[A-Za-z]{1}:(?:\\|/))")
        RE_SOURCES = re.compile(
            r"""(?P<tag>(?P<begin><(?:%s%s%s)[^>]+(?:src%s)=["'])(?P<src>[^"']+)(?P<end>[^>]*>))"""
            % (r"img" if image_convert else "",
               r"|" if image_convert and file_convert else "", r"script|a"
               if file_convert else "", r"|href" if file_convert else ""))
        return RE_SOURCES.sub(tag_fix, html)

    def postprocessor_pathconverter(self,
                                    html,
                                    image_convert,
                                    file_convert,
                                    absolute=False):

        RE_TAG_HTML = r'''(?xus)
        (?:
            (?P<comments>(\r?\n?\s*)<!--[\s\S]*?-->(\s*)(?=\r?\n)|<!--[\s\S]*?-->)|
            (?P<open><(?P<tag>(?:%s)))
            (?P<attr>(?:\s+[\w\-:]+(?:\s*=\s*(?:"[^"]*"|'[^']*'))?)*)
            (?P<close>\s*(?:\/?)>)
        )
        '''

        RE_TAG_LINK_ATTR = re.compile(r'''(?xus)
            (?P<attr>
                (?:
                    (?P<name>\s+(?:href|src)\s*=\s*)
                    (?P<path>"[^"]*"|'[^']*')
                )
            )
            ''')

        RE_SOURCES = re.compile(
            RE_TAG_HTML % ((r"img" if image_convert else "") +
                           (r"|" if image_convert and file_convert else "") +
                           (r"script|a|link" if file_convert else "")))

        def repl(m, base_path, rel_path=None):
            if m.group('comments'):
                tag = m.group('comments')
            else:
                tag = m.group('open')
                if rel_path is None:
                    tag += RE_TAG_LINK_ATTR.sub(
                        lambda m2: repl_absolute(m2, base_path),
                        m.group('attr'))
                else:
                    tag += RE_TAG_LINK_ATTR.sub(
                        lambda m2: repl_relative(m2, base_path, rel_path),
                        m.group('attr'))
                tag += m.group('close')
            return tag

        basepath = self.settings.get('builtin').get("basepath")
        if basepath is None:
            basepath = ""

        if absolute:
            if basepath:
                return RE_SOURCES.sub(lambda m: repl(m, basepath), html)
        else:
            if self.preview:
                relativepath = getTempMarkdownPreviewPath(self.view)
            else:
                relativepath = self.settings.get('builtin').get("destination")
                if not relativepath:
                    mdfile = self.view.file_name()
                    if mdfile is not None and os.path.exists(mdfile):
                        relativepath = os.path.splitext(mdfile)[0] + '.html'

            if relativepath:
                relativepath = os.path.dirname(relativepath)

            if basepath and relativepath:
                return RE_SOURCES.sub(
                    lambda m: repl(m, basepath, relativepath), html)
        return html

    def postprocessor_base64(self, html):
        ''' convert resources (currently images only) to base64 '''

        file_types = {
            ".png": "image/png",
            ".jpg": "image/jpeg",
            ".jpeg": "image/jpeg",
            ".gif": "image/gif"
        }

        exclusion_list = tuple(
            ['https://', 'http://', '#'] +
            ["data:%s;base64," % ft for ft in file_types.values()])

        def b64(m):
            import base64
            src = m.group('src')
            data = m.group('tag')
            base_path = self.settings.get("basepath")
            if base_path is None:
                base_path = ""

            # Format the link
            absolute = False
            if src.startswith('file://'):
                src = src.replace('file://', '', 1)
                # if sublime.platform() == "windows" and not src.startswith('//'):
                #     src = src.lstrip("/")
                absolute = True
            # elif sublime.platform() == "windows" and RE_WIN_DRIVE.match(src) is not None:
            #     absolute = True

            # Make sure we are working with an absolute path
            if not src.startswith(exclusion_list):
                if absolute:
                    src = os.path.normpath(src)
                else:
                    src = os.path.normpath(os.path.join(base_path, src))

                if os.path.exists(src):
                    ext = os.path.splitext(src)[1].lower()
                    if ext in file_types:
                        try:
                            with open(src, "rb") as f:
                                data = m.group(
                                    'begin') + "data:%s;base64,%s" % (
                                        file_types[ext],
                                        base64.b64encode(f.read()).decode(
                                            'ascii')) + m.group('end')
                        except Exception:
                            pass
            return data

        RE_WIN_DRIVE = re.compile(r"(^[A-Za-z]{1}:(?:\\|/))")
        RE_SOURCES = re.compile(
            r"""(?P<tag>(?P<begin><(?:img)[^>]+(?:src)=["'])(?P<src>[^"']+)(?P<end>[^>]*>))"""
        )
        return RE_SOURCES.sub(b64, html)

    def postprocessor_simple(self, html):
        ''' Strip out ids and classes for a simplified HTML output '''
        def strip_html(m):
            tag = m.group('open')
            if m.group('attr1'):
                tag += m.group('attr1')
            if m.group('attr2'):
                tag += m.group('attr2')
            if m.group('attr3'):
                tag += m.group('attr3')
            if m.group('attr4'):
                tag += m.group('attr4')
            if m.group('attr5'):
                tag += m.group('attr5')
            if m.group('attr6'):
                tag += m.group('attr6')
            tag += m.group('close')
            return tag

        # Strip out id, class and style attributes for a simple html output
        # Since we are stripping out two attributes, we need to set up the groups in such
        # a way so we can retrieve the data we don't want to throw away
        # up to these worst case scenarios:
        #
        # <tag attr=""... (id|class|style)=""... attr=""... (id|class|style)=""... attr=""... (id|class|style)=""...>
        # <tag (id|class|style)=""... attr=""... (id|class|style)=""... attr=""... (id|class|style)=""... attr=""...>
        STRIP_HTML = re.compile(
            r'''
                (?P<open><[\w\:\.\-]+)                                                      # Tag open
                (?:
                    (?P<attr1>(?:\s+(?!id|class|style)[\w\-:]+(?:\s*=\s*(?:"[^"]*"|'[^']*'))?)*)  # Attributes to keep
                  | (?P<target1>\s+(?:id|class|style)(?:\s*=\s*(?:"[^"]*"|'[^']*'))*)             # Attributes to delte
                )
                (?:
                    (?P<attr2>(?:\s+(?!id|class|style)[\w\-:]+(?:\s*=\s*(?:"[^"]*"|'[^']*'))?)*)  # Attributes to keep
                  | (?P<target2>\s+(?:id|class|style)(?:\s*=\s*(?:"[^"]*"|'[^']*'))*)             # Attributes to delte
                )?
                (?:
                    (?P<attr3>(?:\s+(?!id|class|style)[\w\-:]+(?:\s*=\s*(?:"[^"]*"|'[^']*'))?)*)  # Attributes to keep
                  | (?P<target3>\s+(?:id|class|style)(?:\s*=\s*(?:"[^"]*"|'[^']*'))*)             # Attributes to delte
                )?
                (?:
                    (?P<attr4>(?:\s+(?!id|class|style)[\w\-:]+(?:\s*=\s*(?:"[^"]*"|'[^']*'))?)*)  # Attributes to keep
                  | (?P<target4>\s+(?:id|class|style)(?:\s*=\s*(?:"[^"]*"|'[^']*'))*)             # Attributes to delte
                )?
                (?:
                    (?P<attr5>(?:\s+(?!id|class|style)[\w\-:]+(?:\s*=\s*(?:"[^"]*"|'[^']*'))?)*)  # Attributes to keep
                  | (?P<target5>\s+(?:id|class|style)(?:\s*=\s*(?:"[^"]*"|'[^']*'))*)             # Attributes to delte
                )?
                (?:
                    (?P<attr6>(?:\s+(?!id|class|style)[\w\-:]+(?:\s*=\s*(?:"[^"]*"|'[^']*'))?)*)  # Attributes to keep
                  | (?P<target6>\s+(?:id|class|style)(?:\s*=\s*(?:"[^"]*"|'[^']*'))*)             # Attributes to delte
                )?
                (?P<close>\s*(?:\/?)>)                                                      # Tag end
            ''', re.MULTILINE | re.DOTALL | re.VERBOSE)
        return STRIP_HTML.sub(strip_html, html)

    def convert_markdown(self, markdown_text):
        ''' convert input markdown to HTML, with github or builtin parser '''

        markdown_html = self.parser_specific_convert(markdown_text)

        image_convert = self.settings.get("image_path_conversion", "absolute")
        file_convert = self.settings.get("file_path_conversions", "absolute")

        markdown_html = self.parser_specific_postprocess(markdown_html)

        if "absolute" in (image_convert, file_convert):
            markdown_html = self.postprocessor_pathconverter(
                markdown_html, image_convert, file_convert, True)

        if "relative" in (image_convert, file_convert):
            markdown_html = self.postprocessor_pathconverter(
                markdown_html, image_convert, file_convert, False)

        if image_convert == "base64":
            markdown_html = self.postprocessor_base64(markdown_html)

        if self.settings.get("html_simple", False):
            markdown_html = self.postprocessor_simple(markdown_html)

        return markdown_html

    def get_title(self):
        if self.meta_title is not None:
            title = self.meta_title
        else:
            title = self.filename

        # TODO: I changed here
        if not title:
            fn = self.filename
            title = 'untitled' if not fn else os.path.splitext(
                os.path.basename(fn))[0]
        return '<title>%s</title>' % cgi.escape(title)

    def get_meta(self):
        self.meta_title = None
        meta = []
        for k, v in self.settings.get("meta", {}).items():
            if k == "title":
                if isinstance(v, list):
                    if len(v) == 0:
                        v = ""
                    else:
                        v = v[0]
                self.meta_title = unicode_str(v)
                continue
            if isinstance(v, list):
                v = ','.join(v)
            if v is not None:
                meta.append('<meta name="%s" content="%s">' %
                            (cgi.escape(k, True), cgi.escape(v, True)))
        return '\n'.join(meta)


# 主程序入口

    def run(self):
        ''' return full html and body html for view. '''
        self.settings = Settings('MarkdownPreview.sublime-settings',
                                 self.filename)

        contents = self.get_contents(self.filename)

        body = self.convert_markdown(contents)

        # add self.html_template, it can be assigned.
        if self.html_template is None:
            html_template = self.settings.get('html_template')
        else:
            html_template = self.html_template

        # use customized html template if given
        if self.settings.get('html_simple', False):
            html = body
        elif html_template and os.path.exists(html_template):
            head = u''
            head += self.get_meta()
            if not self.settings.get('skip_default_stylesheet'):
                head += self.get_stylesheet()
            head += self.get_javascript()
            head += self.get_highlight()
            head += self.get_mathjax()
            head += self.get_uml()
            head += self.get_title()

            html = load_utf8(html_template)
            html = html.replace('{{ HEAD }}', head, 1)
            html = html.replace('{{ BODY }}', body, 1)
        else:
            html = u'<!DOCTYPE html>'
            html += '<html><head><meta charset="utf-8">'
            html += self.get_meta()
            html += self.get_stylesheet()
            html += self.get_javascript()
            html += self.get_highlight()
            html += self.get_mathjax()
            html += self.get_title()
            html += '</head><body>'
            html += body
            html += '</body>'
            html += '</html>'

        return html, body
class Compiler(object):
    ''' Do the markdown converting '''
    default_css = "markdown.css"

    def isurl(self, css_name):
        match = re.match(r'https?://', css_name)
        if match:
            return True
        return False

    def get_default_css(self):
        ''' locate the correct CSS with the 'css' setting '''
        css_name = self.settings.get('css', 'default')

        if self.isurl(css_name):
            # link to remote URL
            return u"<link href='%s' rel='stylesheet' type='text/css'>" % css_name
        elif os.path.isfile(os.path.expanduser(css_name)):
            # use custom CSS file
            return u"<style>%s</style>" % load_utf8(
                os.path.expanduser(css_name))
        elif css_name == 'default':
            # use parser CSS file
            return u"<style>%s</style>" % load_resource(self.default_css)

        return ''

    def get_override_css(self):
        ''' handls allow_css_overrides setting. '''

        if self.settings.get('allow_css_overrides'):
            filename = self.view.file_name()
            filetypes = self.settings.get('markdown_filetypes')

            if filename and filetypes:
                for filetype in filetypes:
                    if filename.endswith(filetype):
                        css_filename = filename.rpartition(
                            filetype)[0] + '.css'
                        if (os.path.isfile(css_filename)):
                            return u"<style>%s</style>" % load_utf8(
                                css_filename)
        return ''

    def get_stylesheet(self):
        ''' return the correct CSS file based on parser and settings '''
        return self.get_default_css() + self.get_override_css()

    def get_javascript(self):
        js_files = self.settings.get('js')
        scripts = ''

        if js_files is not None:
            # Ensure string values become a list.
            if isinstance(js_files, str) or isinstance(js_files, unicode_str):
                js_files = [js_files]
            # Only load scripts if we have a list.
            if isinstance(js_files, list):
                for js_file in js_files:
                    if os.path.isabs(js_file):
                        # Load the script inline to avoid cross-origin.
                        scripts += u"<script>%s</script>" % load_utf8(js_file)
                    else:
                        scripts += u"<script type='text/javascript' src='%s'></script>" % js_file
        return scripts

    def get_mathjax(self):
        ''' return the MathJax script if enabled '''

        if self.settings.get('enable_mathjax') is True:
            return load_resource('mathjax.html')
        return ''

    def get_uml(self):
        ''' return the uml scripts if enabled '''

        if self.settings.get('enable_uml') is True:
            flow = load_resource('flowchart-min.js')
            return load_resource('uml.html').replace('{{ flowchart }}', flow,
                                                     1)
        return ''

    def get_highlight(self):
        return ''

    def get_contents(self, wholefile=False):
        ''' Get contents or selection from view and optionally strip the YAML front matter '''
        region = sublime.Region(0, self.view.size())
        contents = self.view.substr(region)
        if not wholefile:
            # use selection if any
            selection = self.view.substr(self.view.sel()[0])
            if selection.strip() != '':
                contents = selection

        # Remove yaml front matter
        if self.settings.get(
                'strip_yaml_front_matter') and contents.startswith('---'):
            frontmatter, contents = self.preprocessor_yaml_frontmatter(
                contents)
            self.settings.apply_frontmatter(frontmatter)

        references = self.settings.get('builtin').get('references', [])
        for ref in references:
            contents += get_references(ref)

        contents = self.parser_specific_preprocess(contents)

        return contents

    def parser_specific_preprocess(self, text):
        return text

    def preprocessor_yaml_frontmatter(self, text):
        """ Get frontmatter from string """
        frontmatter = {}

        if text.startswith("---"):
            m = re.search(r'^(---(.*?)---[ \t]*\r?\n)', text, re.DOTALL)
            if m:
                try:
                    frontmatter = yaml.load(m.group(2))
                except:
                    print(traceback.format_exc())
                text = text[m.end(1):]

        return frontmatter, text

    def parser_specific_postprocess(self, text):
        return text

    def postprocessor_pathconverter(self,
                                    html,
                                    image_convert,
                                    file_convert,
                                    absolute=False):

        RE_TAG_HTML = r'''(?xus)
        (?:
            (?P<comments>(\r?\n?\s*)<!--[\s\S]*?-->(\s*)(?=\r?\n)|<!--[\s\S]*?-->)|
            (?P<open><(?P<tag>(?:%s)))
            (?P<attr>(?:\s+[\w\-:]+(?:\s*=\s*(?:"[^"]*"|'[^']*'))?)*)
            (?P<close>\s*(?:\/?)>)
        )
        '''

        RE_TAG_LINK_ATTR = re.compile(r'''(?xus)
            (?P<attr>
                (?:
                    (?P<name>\s+(?:href|src)\s*=\s*)
                    (?P<path>"[^"]*"|'[^']*')
                )
            )
            ''')

        RE_SOURCES = re.compile(
            RE_TAG_HTML % ((r"img" if image_convert else "") +
                           (r"|" if image_convert and file_convert else "") +
                           (r"script|a|link" if file_convert else "")))

        def repl(m, base_path, rel_path=None):
            if m.group('comments'):
                tag = m.group('comments')
            else:
                tag = m.group('open')
                if rel_path is None:
                    tag += RE_TAG_LINK_ATTR.sub(
                        lambda m2: repl_absolute(m2, base_path),
                        m.group('attr'))
                else:
                    tag += RE_TAG_LINK_ATTR.sub(
                        lambda m2: repl_relative(m2, base_path, rel_path),
                        m.group('attr'))
                tag += m.group('close')
            return tag

        basepath = self.settings.get('builtin').get("basepath")
        if basepath is None:
            basepath = ""

        if absolute:
            if basepath:
                return RE_SOURCES.sub(lambda m: repl(m, basepath), html)
        else:
            if self.preview:
                relativepath = getTempMarkdownPreviewPath(self.view)
            else:
                relativepath = self.settings.get('builtin').get("destination")
                if not relativepath:
                    mdfile = self.view.file_name()
                    if mdfile is not None and os.path.exists(mdfile):
                        relativepath = os.path.splitext(mdfile)[0] + '.html'

            if relativepath:
                relativepath = os.path.dirname(relativepath)

            if basepath and relativepath:
                return RE_SOURCES.sub(
                    lambda m: repl(m, basepath, relativepath), html)
        return html

    def postprocessor_base64(self, html):
        ''' convert resources (currently images only) to base64 '''

        file_types = {
            (".png", ): "image/png",
            (".jpg", ".jpeg"): "image/jpeg",
            (".gif", ): "image/gif"
        }

        exclusion_list = tuple(
            ['https://', 'http://', '#'] +
            ["data:%s;base64," % ft for ft in file_types.values()])

        RE_WIN_DRIVE = re.compile(r"(^[A-Za-z]{1}:(?:\\|/))")
        RE_TAG_HTML = re.compile(r'''(?xus)
            (?:
                (?P<comments>(\r?\n?\s*)<!--[\s\S]*?-->(\s*)(?=\r?\n)|<!--[\s\S]*?-->)|
                (?P<open><(?P<tag>img))
                (?P<attr>(?:\s+[\w\-:]+(?:\s*=\s*(?:"[^"]*"|'[^']*'))?)*)
                (?P<close>\s*(?:\/?)>)
            )
            ''')
        RE_TAG_LINK_ATTR = re.compile(r'''(?xus)
            (?P<attr>
                (?:
                    (?P<name>\s+src\s*=\s*)
                    (?P<path>"[^"]*"|'[^']*')
                )
            )
            ''')

        def b64(m):
            import base64
            src = url2pathname(m.group('path')[1:-1])
            data = m.group(0)
            base_path = self.settings.get('builtin').get("basepath")
            if base_path is None:
                base_path = ""

            # Format the link
            absolute = False
            if src.startswith('file://'):
                src = src.replace('file://', '', 1)
                if sublime.platform(
                ) == "windows" and not src.startswith('//'):
                    src = src.lstrip("/")
                absolute = True
            elif sublime.platform() == "windows" and RE_WIN_DRIVE.match(
                    src) is not None:
                absolute = True

            # Make sure we are working with an absolute path
            if not src.startswith(exclusion_list):
                if absolute:
                    src = os.path.normpath(src)
                else:
                    src = os.path.normpath(os.path.join(base_path, src))

                if os.path.exists(src):
                    ext = os.path.splitext(src)[1].lower()
                    for b64_ext in file_types:
                        if ext in b64_ext:
                            try:
                                with open(src, "rb") as f:
                                    data = " src=\"data:%s;base64,%s\"" % (
                                        file_types[b64_ext],
                                        base64.b64encode(
                                            f.read()).decode('ascii'))
                            except Exception:
                                pass
                            break
            return data

        def repl(m):
            if m.group('comments'):
                tag = m.group('comments')
            else:
                tag = m.group('open')
                tag += RE_TAG_LINK_ATTR.sub(lambda m2: b64(m2),
                                            m.group('attr'))
                tag += m.group('close')
            return tag

        return RE_TAG_HTML.sub(repl, html)

    def postprocessor_simple(self, html):
        ''' Strip out ids and classes for a simplified HTML output '''
        def repl(m):
            if m.group('comments'):
                tag = ''
            else:
                tag = m.group('open')
                tag += RE_TAG_BAD_ATTR.sub('', m.group('attr'))
                tag += m.group('close')
            return tag

        # Strip out id, class, on<word>, and style attributes for a simple html output
        RE_TAG_HTML = re.compile(
            r'''(?x)
            (?:
                (?P<comments>(\r?\n?\s*)<!--[\s\S]*?-->(\s*)(?=\r?\n)|<!--[\s\S]*?-->)|
                (?P<open><[\w\:\.\-]+)
                (?P<attr>(?:\s+[\w\-:]+(?:\s*=\s*(?:"[^"]*"|'[^']*'))?)*)
                (?P<close>\s*(?:\/?)>)
            )
            ''', re.DOTALL | re.UNICODE)

        RE_TAG_BAD_ATTR = re.compile(
            r'''(?x)
            (?P<attr>
                (?:
                    \s+(?:id|class|style|on[\w]+)
                    (?:\s*=\s*(?:"[^"]*"|'[^']*'))
                )*
            )
            ''', re.DOTALL | re.UNICODE)

        return RE_TAG_HTML.sub(repl, html)

    def convert_markdown(self, markdown_text):
        ''' convert input markdown to HTML, with github or builtin parser '''

        markdown_html = self.parser_specific_convert(markdown_text)

        image_convert = self.settings.get("image_path_conversion", "absolute")
        file_convert = self.settings.get("file_path_conversions", "absolute")

        markdown_html = self.parser_specific_postprocess(markdown_html)

        if "absolute" in (image_convert, file_convert):
            markdown_html = self.postprocessor_pathconverter(
                markdown_html, image_convert, file_convert, True)

        if "relative" in (image_convert, file_convert):
            markdown_html = self.postprocessor_pathconverter(
                markdown_html, image_convert, file_convert, False)

        if image_convert == "base64":
            markdown_html = self.postprocessor_base64(markdown_html)

        if self.settings.get("html_simple", False):
            markdown_html = self.postprocessor_simple(markdown_html)

        return markdown_html

    def get_title(self):
        if self.meta_title is not None:
            title = self.meta_title
        else:
            title = self.view.name()
        if not title:
            fn = self.view.file_name()
            title = 'untitled' if not fn else os.path.splitext(
                os.path.basename(fn))[0]
        return '<title>%s</title>' % cgi.escape(title)

    def get_meta(self):
        self.meta_title = None
        meta = []
        for k, v in self.settings.get("meta", {}).items():
            if k == "title":
                if isinstance(v, list):
                    if len(v) == 0:
                        v = ""
                    else:
                        v = v[0]
                self.meta_title = unicode_str(v)
                continue
            if isinstance(v, list):
                v = ','.join(v)
            if v is not None:
                meta.append('<meta name="%s" content="%s">' %
                            (cgi.escape(k, True), cgi.escape(v, True)))
        return '\n'.join(meta)

    def run(self, view, wholefile=False, preview=False):
        ''' return full html and body html for view. '''
        self.settings = Settings('MarkdownPreview.sublime-settings',
                                 view.file_name())
        self.preview = preview
        self.view = view

        contents = self.get_contents(wholefile)

        body = self.convert_markdown(contents)

        html_template = self.settings.get('html_template')

        # use customized html template if given
        if self.settings.get('html_simple', False):
            html = body
        elif html_template and os.path.exists(html_template):
            head = u''
            head += self.get_meta()
            if not self.settings.get('skip_default_stylesheet'):
                head += self.get_stylesheet()
            head += self.get_javascript()
            head += self.get_highlight()
            head += self.get_mathjax()
            head += self.get_uml()
            head += self.get_title()

            html = load_utf8(html_template)
            html = html.replace('{{ HEAD }}', head, 1)
            html = html.replace('{{ BODY }}', body, 1)
        else:
            html = u'<!DOCTYPE html>'
            html += '<html><head><meta charset="utf-8">'
            html += self.get_meta()
            html += self.get_stylesheet()
            html += self.get_javascript()
            html += self.get_highlight()
            html += self.get_mathjax()
            html += self.get_uml()
            html += self.get_title()
            html += '</head><body>'
            html += '<article class="markdown-body">'
            html += body
            html += '</article>'
            html += '</body>'
            html += '</html>'

        return html, body
class Compiler(object):
    ''' Do the markdown converting '''
    default_css = "markdown.css"

    def isurl(self, css_name):
        match = re.match(r'https?://', css_name)
        if match:
            return True
        return False

    def get_default_css(self):
        ''' locate the correct CSS with the 'css' setting '''
        css_name = self.settings.get('css', 'default')

        if self.isurl(css_name):
            # link to remote URL
            return u"<link href='%s' rel='stylesheet' type='text/css'>" % css_name
        elif os.path.isfile(os.path.expanduser(css_name)):
            # use custom CSS file
            return u"<style>%s</style>" % load_utf8(os.path.expanduser(css_name))
        elif css_name == 'default':
            # use parser CSS file
            return u"<style>%s</style>" % load_resource(self.default_css)

        return ''

    def get_override_css(self):
        ''' handls allow_css_overrides setting. '''

        if self.settings.get('allow_css_overrides'):
            filename = self.view.file_name()
            filetypes = self.settings.get('markdown_filetypes')

            if filename and filetypes:
                for filetype in filetypes:
                    if filename.endswith(filetype):
                        css_filename = filename.rpartition(filetype)[0] + '.css'
                        if (os.path.isfile(css_filename)):
                            return u"<style>%s</style>" % load_utf8(css_filename)
        return ''

    def get_stylesheet(self):
        ''' return the correct CSS file based on parser and settings '''
        return self.get_default_css() + self.get_override_css()

    def get_javascript(self):
        js_files = self.settings.get('js')
        scripts = ''

        if js_files is not None:
            # Ensure string values become a list.
            if isinstance(js_files, str) or isinstance(js_files, unicode_str):
                js_files = [js_files]
            # Only load scripts if we have a list.
            if isinstance(js_files, list):
                for js_file in js_files:
                    if os.path.isabs(js_file):
                        # Load the script inline to avoid cross-origin.
                        scripts += u"<script>%s</script>" % load_utf8(js_file)
                    else:
                        scripts += u"<script type='text/javascript' src='%s'></script>" % js_file
        return scripts

    def get_mathjax(self):
        ''' return the MathJax script if enabled '''

        if self.settings.get('enable_mathjax') is True:
            return load_resource('mathjax.html')
        return ''

    def get_highlight(self):
        return ''

    def get_contents(self, wholefile=False):
        ''' Get contents or selection from view and optionally strip the YAML front matter '''
        region = sublime.Region(0, self.view.size())
        contents = self.view.substr(region)
        if not wholefile:
            # use selection if any
            selection = self.view.substr(self.view.sel()[0])
            if selection.strip() != '':
                contents = selection

        # Remove yaml front matter
        if self.settings.get('strip_yaml_front_matter') and contents.startswith('---'):
            frontmatter, contents = self.preprocessor_yaml_frontmatter(contents)
            self.settings.apply_frontmatter(frontmatter)

        references = self.settings.get('builtin').get('references', [])
        for ref in references:
            contents += get_references(ref)

        contents = self.parser_specific_preprocess(contents)

        return contents

    def parser_specific_preprocess(self, text):
        return text

    def preprocessor_yaml_frontmatter(self, text):
        """ Get frontmatter from string """
        frontmatter = {}

        if text.startswith("---"):
            m = re.search(r'^(---(.*?)---\r?\n)', text, re.DOTALL)
            if m:
                try:
                    frontmatter = yaml.load(m.group(2))
                except:
                    print(traceback.format_exc())
                text = text[m.end(1):]

        return frontmatter, text

    def parser_specific_postprocess(self, text):
        return text

    def postprocessor_absolute(self, html, image_convert, file_convert):
        ''' fix relative paths in images, scripts, and links for the internal parser '''
        def tag_fix(m):
            tag = m.group('tag')
            src = m.group('src')
            filename = self.view.file_name()
            if filename:
                if (
                    not src.startswith(ABS_EXCLUDE) and
                    not (sublime.platform() == "windows" and RE_WIN_DRIVE.match(src) is not None)
                ):
                    # Don't explicitly add file:// prefix,
                    # But don't remove them either
                    abs_path = u'%s/%s' % (os.path.dirname(filename), src)
                    # Don't replace just the first instance,
                    # but explicitly place it where it was before
                    # to ensure a file name 'img' dosen't replace
                    # the tag name etc.
                    if os.path.exists(abs_path):
                        tag = m.group('begin') + abs_path + m.group('end')
            return tag
        # Compile the appropriate regex to find images and/or files
        RE_WIN_DRIVE = re.compile(r"(^[A-Za-z]{1}:(?:\\|/))")
        RE_SOURCES = re.compile(
            r"""(?P<tag>(?P<begin><(?:%s%s%s)[^>]+(?:src%s)=["'])(?P<src>[^"']+)(?P<end>[^>]*>))""" % (
                r"img" if image_convert else "",
                r"|" if image_convert and file_convert else "",
                r"script|a" if file_convert else "",
                r"|href" if file_convert else ""
            )
        )
        return RE_SOURCES.sub(tag_fix, html)

    def postprocessor_base64(self, html):
        ''' convert resources (currently images only) to base64 '''

        file_types = {
            ".png": "image/png",
            ".jpg": "image/jpeg",
            ".jpeg": "image/jpeg",
            ".gif": "image/gif"
        }

        exclusion_list = tuple(
            ['https://', 'http://', '#'] +
            ["data:%s;base64," % ft for ft in file_types.values()]
        )

        def b64(m):
            import base64
            src = m.group('src')
            data = m.group('tag')
            base_path = self.settings.get("basepath")
            if base_path is None:
                base_path = ""

            # Format the link
            absolute = False
            if src.startswith('file://'):
                src = src.replace('file://', '', 1)
                if sublime.platform() == "windows" and not src.startswith('//'):
                    src = src.lstrip("/")
                absolute = True
            elif sublime.platform() == "windows" and RE_WIN_DRIVE.match(src) is not None:
                absolute = True

            # Make sure we are working with an absolute path
            if not src.startswith(exclusion_list):
                if absolute:
                    src = os.path.normpath(src)
                else:
                    src = os.path.normpath(os.path.join(base_path, src))

                if os.path.exists(src):
                    ext = os.path.splitext(src)[1].lower()
                    if ext in file_types:
                        try:
                            with open(src, "rb") as f:
                                data = m.group('begin') + "data:%s;base64,%s" % (
                                    file_types[ext],
                                    base64.b64encode(f.read()).decode('ascii')
                                ) + m.group('end')
                        except Exception:
                            pass
            return data
        RE_WIN_DRIVE = re.compile(r"(^[A-Za-z]{1}:(?:\\|/))")
        RE_SOURCES = re.compile(r"""(?P<tag>(?P<begin><(?:img)[^>]+(?:src)=["'])(?P<src>[^"']+)(?P<end>[^>]*>))""")
        return RE_SOURCES.sub(b64, html)

    def postprocessor_simple(self, html):
        ''' Strip out ids and classes for a simplified HTML output '''
        def strip_html(m):
            tag = m.group('open')
            if m.group('attr1'):
                tag += m.group('attr1')
            if m.group('attr2'):
                tag += m.group('attr2')
            if m.group('attr3'):
                tag += m.group('attr3')
            if m.group('attr4'):
                tag += m.group('attr4')
            if m.group('attr5'):
                tag += m.group('attr5')
            if m.group('attr6'):
                tag += m.group('attr6')
            tag += m.group('close')
            return tag

        # Strip out id, class and style attributes for a simple html output
        # Since we are stripping out two attributes, we need to set up the groups in such
        # a way so we can retrieve the data we don't want to throw away
        # up to these worst case scenarios:
        #
        # <tag attr=""... (id|class|style)=""... attr=""... (id|class|style)=""... attr=""... (id|class|style)=""...>
        # <tag (id|class|style)=""... attr=""... (id|class|style)=""... attr=""... (id|class|style)=""... attr=""...>
        STRIP_HTML = re.compile(
            r'''
                (?P<open><[\w\:\.\-]+)                                                      # Tag open
                (?:
                    (?P<attr1>(?:\s+(?!id|class|style)[\w\-:]+(?:\s*=\s*(?:"[^"]*"|'[^']*'))?)*)  # Attributes to keep
                  | (?P<target1>\s+(?:id|class|style)(?:\s*=\s*(?:"[^"]*"|'[^']*'))*)             # Attributes to delte
                )
                (?:
                    (?P<attr2>(?:\s+(?!id|class|style)[\w\-:]+(?:\s*=\s*(?:"[^"]*"|'[^']*'))?)*)  # Attributes to keep
                  | (?P<target2>\s+(?:id|class|style)(?:\s*=\s*(?:"[^"]*"|'[^']*'))*)             # Attributes to delte
                )?
                (?:
                    (?P<attr3>(?:\s+(?!id|class|style)[\w\-:]+(?:\s*=\s*(?:"[^"]*"|'[^']*'))?)*)  # Attributes to keep
                  | (?P<target3>\s+(?:id|class|style)(?:\s*=\s*(?:"[^"]*"|'[^']*'))*)             # Attributes to delte
                )?
                (?:
                    (?P<attr4>(?:\s+(?!id|class|style)[\w\-:]+(?:\s*=\s*(?:"[^"]*"|'[^']*'))?)*)  # Attributes to keep
                  | (?P<target4>\s+(?:id|class|style)(?:\s*=\s*(?:"[^"]*"|'[^']*'))*)             # Attributes to delte
                )?
                (?:
                    (?P<attr5>(?:\s+(?!id|class|style)[\w\-:]+(?:\s*=\s*(?:"[^"]*"|'[^']*'))?)*)  # Attributes to keep
                  | (?P<target5>\s+(?:id|class|style)(?:\s*=\s*(?:"[^"]*"|'[^']*'))*)             # Attributes to delte
                )?
                (?:
                    (?P<attr6>(?:\s+(?!id|class|style)[\w\-:]+(?:\s*=\s*(?:"[^"]*"|'[^']*'))?)*)  # Attributes to keep
                  | (?P<target6>\s+(?:id|class|style)(?:\s*=\s*(?:"[^"]*"|'[^']*'))*)             # Attributes to delte
                )?
                (?P<close>\s*(?:\/?)>)                                                      # Tag end
            ''',
            re.MULTILINE | re.DOTALL | re.VERBOSE
        )
        return STRIP_HTML.sub(strip_html, html)

    def convert_markdown(self, markdown_text):
        ''' convert input markdown to HTML, with github or builtin parser '''

        markdown_html = self.parser_specific_convert(markdown_text)

        image_convert = self.settings.get("image_path_conversion", "absolute")
        file_convert = self.settings.get("file_path_conversions", "absolute")

        markdown_html = self.parser_specific_postprocess(markdown_html)

        if "absolute" in (image_convert, file_convert):
            markdown_html = self.postprocessor_absolute(markdown_html, image_convert, file_convert)

        if image_convert == "base64":
            markdown_html = self.postprocessor_base64(markdown_html)

        if self.settings.get("html_simple", False):
            markdown_html = self.postprocessor_simple(markdown_html)

        return markdown_html

    def get_title(self):
        if self.meta_title is not None:
            title = self.meta_title
        else:
            title = self.view.name()
        if not title:
            fn = self.view.file_name()
            title = 'untitled' if not fn else os.path.splitext(os.path.basename(fn))[0]
        return '<title>%s</title>' % cgi.escape(title)

    def get_meta(self):
        self.meta_title = None
        meta = []
        for k, v in self.settings.get("meta", {}).items():
            if k == "title":
                if isinstance(v, list):
                    if len(v) == 0:
                        v = ""
                    else:
                        v = v[0]
                self.meta_title = unicode_str(v)
                continue
            if isinstance(v, list):
                v = ','.join(v)
            if v is not None:
                meta.append(
                    '<meta name="%s" content="%s">' % (cgi.escape(k, True), cgi.escape(v, True))
                )
        return '\n'.join(meta)

    def run(self, view, wholefile=False):
        ''' return full html and body html for view. '''
        self.settings = Settings('MarkdownPreview.sublime-settings', view.file_name())
        self.view = view

        contents = self.get_contents(wholefile)

        body = self.convert_markdown(contents)

        html_template = self.settings.get('html_template')

        # use customized html template if given
        if self.settings.get('html_simple', False):
            html = body
        elif html_template and os.path.exists(html_template):
            head = u''
            head += self.get_meta()
            if not self.settings.get('skip_default_stylesheet'):
                head += self.get_stylesheet()
            head += self.get_javascript()
            head += self.get_highlight()
            head += self.get_mathjax()
            head += self.get_title()

            html = load_utf8(html_template)
            html = html.replace('{{ HEAD }}', head, 1)
            html = html.replace('{{ BODY }}', body, 1)
        else:
            html = u'<!DOCTYPE html>'
            html += '<html><head><meta charset="utf-8">'
            html += self.get_meta()
            html += self.get_stylesheet()
            html += self.get_javascript()
            html += self.get_highlight()
            html += self.get_mathjax()
            html += self.get_title()
            html += '</head><body>'
            html += '<article class="markdown-body">'
            html += body
            html += '</article>'
            html += '</body>'
            html += '</html>'

        return html, body