# Converts Vim/Nvim documentation to HTML. # # USAGE: # 1. python3 scripts/gen_help_html.py runtime/doc/ ~/neovim.github.io/t/ # 3. cd ~/neovim.github.io/ && jekyll serve --host 0.0.0.0 # 2. Visit http://localhost:4000/t/help.txt.html # # Adapted from https://github.com/c4rlo/vimhelp/ # License: MIT # # Copyright (c) 2016 Carlo Teubner # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. import os import re import urllib.parse import datetime import sys from itertools import chain HEAD = """\
Nvim help pages{vers-note}. Updated automatically from the Nvim source.
""" VERSION_NOTE = ", current as of Nvim {version}" SITENAVI_LINKS = """ Quick reference · User manual · Reference manual · """ SITENAVI_LINKS_PLAIN = SITENAVI_LINKS.format(helptxt='help.txt.html') SITENAVI_LINKS_WEB = SITENAVI_LINKS.format(helptxt='/') SITENAVI_PLAIN = '' + SITENAVI_LINKS_PLAIN + '
' SITENAVI_WEB = '' + SITENAVI_LINKS_WEB + '
' SITENAVI_SEARCH = '| ' + SITENAVI_LINKS_WEB + \ ' | ' \
    ' | 
""" + (" " * 80) + """
""" FOOTER = '' FOOTER2 = """
'))
                last = ''
                continue
            if RE_HRULE.match(line):
                # out.extend(('', line, '\n'))
                last = 'h1'
                continue
            if inexample == 2:
                if RE_EG_END.match(line):
                    inexample = 0
                    if line[0] == '<':
                        line = line[1:]
                else:
                    out.extend(('', html_escape[line],
                                '\n'))
                    continue
            if RE_EG_START.match(line_tabs):
                inexample = 1
                line = line[0:-1]
            if RE_SECTION.match(line_tabs):
                m = RE_SECTION.match(line)
                out.extend((r'', m.group(0), r''))
                line = line[m.end():]
            lastpos = 0
            for match in RE_TAGWORD.finditer(line):
                pos = match.start()
                if pos > lastpos:
                    out.append(html_escape[line[lastpos:pos]])
                lastpos = match.end()
                header, graphic, pipeword, starword, command, opt, ctrl, \
                    special, title, note, url, word = match.groups()
                if pipeword is not None:
                    out.append(self.maplink(pipeword, filename, 'l'))
                elif starword is not None:
                    out.extend(('', html_escape[starword], ''))
                elif command is not None:
                    out.extend(('', html_escape[command],
                                ''))
                elif opt is not None:
                    out.append(self.maplink(opt, filename, 'o'))
                elif ctrl is not None:
                    out.append(self.maplink(ctrl, filename, 'k'))
                elif special is not None:
                    out.append(self.maplink(special, filename, 's'))
                elif title is not None:
                    out.extend(('', html_escape[title],
                                ''))
                elif note is not None:
                    out.extend(('', html_escape[note],
                                ''))
                elif header is not None:
                    out.extend(('', html_escape[header[:-1]],
                                ''))
                elif graphic is not None:
                    out.append(html_escape[graphic[:-2]])
                elif url is not None:
                    out.extend(('' +
                                html_escape[url], ''))
                elif word is not None:
                    out.append(self.maplink(word, filename))
            if lastpos < len(line):
                out.append(html_escape[line[lastpos:]])
            out.append('\n')
            if inexample == 1:
                inexample = 2
        header = []
        header.append(HEAD.format(encoding=encoding, filename=filename))
        header.append(HEAD_END)
        if self._is_web_version and is_help_txt:
            vers_note = VERSION_NOTE.replace('{version}', self._version) \
                if self._version else ''
            header.append(INTRO.replace('{vers-note}', vers_note))
        if self._is_web_version:
            header.append(SITENAVI_SEARCH)
            sitenavi_footer = SITENAVI_WEB
        else:
            header.append(SITENAVI_PLAIN)
            sitenavi_footer = SITENAVI_PLAIN
        header.append(TEXTSTART)
        return ''.join(chain(header, out, (FOOTER, sitenavi_footer, FOOTER2)))
class HtmlEscCache(dict):
    def __missing__(self, key):
        r = key.replace('&', '&') \
               .replace('<', '<') \
               .replace('>', '>')
        self[key] = r
        return r
html_escape = HtmlEscCache()
def slurp(filename):
    try:
        with open(filename, encoding='UTF-8') as f:
            return f.read(), 'UTF-8'
    except UnicodeError:
        # 'ISO-8859-1' ?
        with open(filename, encoding='latin-1') as f:
            return f.read(), 'latin-1'
def usage():
    return "usage: " + sys.argv[0] + " IN_DIR OUT_DIR [BASENAMES...]"
def main():
    if len(sys.argv) < 3:
        sys.exit(usage())
    in_dir = sys.argv[1]
    out_dir = sys.argv[2]
    basenames = sys.argv[3:]
    print("Processing tags...")
    h2h = VimH2H(slurp(os.path.join(in_dir, 'tags'))[0], is_web_version=False)
    if len(basenames) == 0:
        basenames = os.listdir(in_dir)
    for basename in basenames:
        if os.path.splitext(basename)[1] != '.txt' and basename != 'tags':
            print("Ignoring " + basename)
            continue
        print("Processing " + basename + "...")
        path = os.path.join(in_dir, basename)
        text, encoding = slurp(path)
        outpath = os.path.join(out_dir, basename + '.html')
        of = open(outpath, 'w')
        of.write(h2h.to_html(basename, text, encoding))
        of.close()
main()