Commit fa68bfe57c4e3efdcb8d88fe603a1d8302ab95ed

Initial version
Author: xaizek
Author date (UTC): 2015-06-25 08:10
Committer name: xaizek
Committer date (UTC): 2016-01-12 19:11
Parent(s):
Signing key:
Tree: 4f87e65071fcc109b7985a796b1b0a542c339d31
File Lines added Lines deleted
.gitignore 2 0
vimh2h.py 199 0
vimhelp.css 49 0
File .gitignore added (mode: 100644) (index 0000000..3bb2efd)
1 .*.swp
2 *.pyc
File vimh2h.py added (mode: 100755) (index 0000000..08f1f3a)
1 #!/usr/bin/env python
2
3 # converts vim documentation to html
4
5 import re, urllib
6 from itertools import chain
7
8 RE_TAGLINE = re.compile(r'(\S+)\s+(\S+)')
9
10 PAT_WORDCHAR = '[!#-)+-{}~\xC0-\xFF]'
11
12 PAT_HEADER = r'(^.*~$)'
13 PAT_GRAPHIC = r'(^.* `$)'
14 PAT_PIPEWORD = r'(?<!\\)\|([#-)!+-~]+)\|'
15 PAT_STARWORD = r'\*([#-)!+-~]+)\*(?:(?=\s)|$)'
16 PAT_COMMAND = r'`([^` ]+)`'
17 PAT_OPTWORD = r"('(?:[a-z]{2,}|t_..)')"
18 PAT_CTRL = r'(CTRL-(?:W_)?(?:[\w\[\]^+-<>=@]|<[A-Za-z]+?>)?)'
19 PAT_SPECIAL = r'(<.*?>|\{.*?}|' \
20 r'\[(?:range|line|count|offset|\+?cmd|[-+]?num|\+\+opt|' \
21 r'arg|arguments|ident|addr|group)]|' \
22 r'(?<=\s)\[[-a-z^A-Z0-9_]{2,}])'
23 PAT_TITLE = r'(Vim version [0-9.a-z]+|VIM REFERENCE.*)'
24 PAT_NOTE = r'((?<!' + PAT_WORDCHAR + r')(?:note|NOTE|Notes?):?' \
25 r'(?!' + PAT_WORDCHAR + r'))'
26 PAT_URL = r'((?:https?|ftp)://[^\'"<> \t]+[a-zA-Z0-9/])'
27 PAT_WORD = r'((?<!' + PAT_WORDCHAR + r')' + PAT_WORDCHAR + r'+' \
28 r'(?!' + PAT_WORDCHAR + r'))'
29
30 RE_LINKWORD = re.compile(
31 PAT_OPTWORD + '|' +
32 PAT_CTRL + '|' +
33 PAT_SPECIAL)
34 RE_TAGWORD = re.compile(
35 PAT_HEADER + '|' +
36 PAT_GRAPHIC + '|' +
37 PAT_PIPEWORD + '|' +
38 PAT_STARWORD + '|' +
39 PAT_COMMAND + '|' +
40 PAT_OPTWORD + '|' +
41 PAT_CTRL + '|' +
42 PAT_SPECIAL + '|' +
43 PAT_TITLE + '|' +
44 PAT_NOTE + '|' +
45 PAT_URL + '|' +
46 PAT_WORD)
47 RE_NEWLINE = re.compile(r'[\r\n]')
48 RE_HRULE = re.compile(r'[-=]{3,}.*[-=]{3,3}$')
49 RE_EG_START = re.compile(r'(?:.* )?>$')
50 RE_EG_END = re.compile(r'\S')
51 RE_SECTION = re.compile(r'[-A-Z .][-A-Z0-9 .()]*(?=\s+\*)')
52 RE_STARTAG = re.compile(r'\s\*([^ \t|]+)\*(?:\s|$)')
53 RE_LOCAL_ADD = re.compile(r'LOCAL ADDITIONS:\s+\*local-additions\*$')
54
55 class Link(object):
56 __slots__ = 'link_pipe', 'link_plain'
57
58 def __init__(self, link_pipe, link_plain):
59 self.link_pipe = link_pipe
60 self.link_plain = link_plain
61
62 class VimH2H(object):
63 def __init__(self, tags, version=None):
64 self._urls = { }
65 self._version = version
66 for line in RE_NEWLINE.split(tags):
67 m = RE_TAGLINE.match(line)
68 if m:
69 tag, filename = m.group(1, 2)
70 self.do_add_tag(filename, tag)
71
72 def add_tags(self, filename, contents):
73 for match in RE_STARTAG.finditer(contents):
74 tag = match.group(1).replace('\\', '\\\\').replace('/', '\\/')
75 self.do_add_tag(str(filename), tag)
76
77 def do_add_tag(self, filename, tag):
78 part1 = '<a href="#' + \
79 urllib.quote_plus(tag) + '"'
80 part2 = '>' + html_escape[tag] + '</a>'
81 link_pipe = part1 + ' class="l"' + part2
82 classattr = ' class="d"'
83 m = RE_LINKWORD.match(tag)
84 if m:
85 opt, ctrl, special = m.groups()
86 if opt is not None: classattr = ' class="o"'
87 elif ctrl is not None: classattr = ' class="k"'
88 elif special is not None: classattr = ' class="s"'
89 link_plain = part1 + classattr + part2
90 self._urls[tag] = Link(link_pipe, link_plain)
91
92 def maplink(self, tag, css_class=None):
93 links = self._urls.get(tag)
94 if links is not None:
95 if css_class == 'l': return links.link_pipe
96 else: return links.link_plain
97 elif css_class is not None:
98 return '<span class="' + css_class + '">' + html_escape[tag] + \
99 '</span>'
100 else: return html_escape[tag]
101
102 def to_html(self, filename, contents, encoding, web_version=True):
103 out = [ ]
104
105 inexample = 0
106 filename = str(filename)
107 is_help_txt = (filename == 'help.txt')
108 for line in RE_NEWLINE.split(contents):
109 line = line.rstrip('\r\n')
110 line_tabs = line
111 line = line.expandtabs()
112 if RE_HRULE.match(line):
113 out.extend(('<span class="h">', line, '</span>\n'))
114 continue
115 if inexample == 2:
116 if RE_EG_END.match(line):
117 inexample = 0
118 if line[0] == '<': line = line[1:]
119 else:
120 out.extend(('<span class="e">', html_escape[line],
121 '</span>\n'))
122 continue
123 if RE_EG_START.match(line_tabs):
124 inexample = 1
125 line = line[0:-1]
126 if RE_SECTION.match(line_tabs):
127 m = RE_SECTION.match(line)
128 out.extend((r'<span class="c">', m.group(0), r'</span>'))
129 line = line[m.end():]
130 lastpos = 0
131 for match in RE_TAGWORD.finditer(line):
132 pos = match.start()
133 if pos > lastpos:
134 out.append(html_escape[line[lastpos:pos]])
135 lastpos = match.end()
136 header, graphic, pipeword, starword, command, opt, ctrl, \
137 special, title, note, url, word = match.groups()
138 if pipeword is not None:
139 out.append(self.maplink(pipeword, 'l'))
140 elif starword is not None:
141 out.extend(('<a name="', urllib.quote_plus(starword),
142 '" class="t">', html_escape[starword], '</a>'))
143 elif command is not None:
144 out.extend(('<span class="e">', html_escape[command],
145 '</span>'))
146 elif opt is not None:
147 out.append(self.maplink(opt, 'o'))
148 elif ctrl is not None:
149 out.append(self.maplink(ctrl, 'k'))
150 elif special is not None:
151 out.append(self.maplink(special, 's'))
152 elif title is not None:
153 out.extend(('<span class="i">', html_escape[title],
154 '</span>'))
155 elif note is not None:
156 out.extend(('<span class="n">', html_escape[note],
157 '</span>'))
158 elif header is not None:
159 out.extend(('<span class="h">', html_escape[header[:-1]],
160 '</span>'))
161 elif graphic is not None:
162 out.append(html_escape[graphic[:-2]])
163 elif url is not None:
164 out.extend(('<a class="u" href="', url, '">' +
165 html_escape[url], '</a>'))
166 elif word is not None:
167 out.append(self.maplink(word))
168 if lastpos < len(line):
169 out.append(html_escape[line[lastpos:]])
170 out.append('\n')
171 if inexample == 1: inexample = 2
172
173 header = []
174 return ''.join(chain(header, out))
175
176 class HtmlEscCache(dict):
177 def __missing__(self, key):
178 r = key.replace('&', '&amp;') \
179 .replace('<', '&lt;') \
180 .replace('>', '&gt;')
181 self[key] = r
182 return r
183
184 html_escape = HtmlEscCache()
185
186 import io
187 import os
188
189 in_file = io.FileIO('tags')
190 tags = in_file.read()
191 in_file.close()
192
193 hhh = VimH2H(tags)
194
195 in_file = io.FileIO('vifm.txt')
196 content = in_file.read()
197 in_file.close()
198
199 print hhh.to_html('vifm.txt', content, 'utf-8', False)
File vimhelp.css added (mode: 100644) (index 0000000..822c9ae)
1 body { font-family: georgia, palatino, serif }
2
3 pre { font-size: 11pt }
4
5 #d1 { position: relative; display: table; margin: 0 auto }
6 #d2 { position: absolute; top: inherit }
7
8 #sp { visibility: hidden; height: 1px; margin: 0 }
9
10 #footer { font-size: 85%; padding-top: 1em }
11
12 /* hidden links */
13 a.d:link, a.d:visited { color: rgb(0,0,0); text-decoration: none; }
14 a.d:active, a.d:hover { color: rgb(0,0,0); text-decoration: underline; }
15
16 /* standard links */
17 a.l:link { color: rgb(0,137,139); }
18 a.l:visited { color: rgb(0,100,100); }
19 a.l:active, a.l:hover { color: rgb(0,200,200); }
20
21 /* title */
22 .i { color: rgb(0, 137, 139); }
23
24 /* tag */
25 .t { color: rgb(250,0,250); }
26
27 /* header */
28 .h { color: rgb(164, 32, 246); }
29
30 /* keystroke */
31 .k { color: rgb(106, 89, 205); }
32
33 /* example */
34 .e { color: rgb(0, 0, 255); }
35
36 /* special (used for various) */
37 .s { color: rgb(106, 89, 205); }
38
39 /* note */
40 .n { color: blue; background-color: yellow; }
41
42 /* option */
43 .o { color: rgb(46, 139, 87); font-weight: bold; }
44
45 /* section */
46 .c { color: rgb(165, 42, 42); font-weight: bold; }
47
48 /* external url */
49 .u { color: rgb(250,0,250); }
Hints

Before first commit, do not forget to setup your git environment:
git config --global user.name "your_name_here"
git config --global user.email "your@email_here"

Clone this repository using HTTP(S):
git clone https://code.reversed.top/user/xaizek/vimdoc2html

Clone this repository using ssh (do not forget to upload a key first):
git clone ssh://rocketgit@code.reversed.top/user/xaizek/vimdoc2html

You are allowed to anonymously push to this repository.
This means that your pushed commits will automatically be transformed into a pull request:
... clone the repository ...
... make some changes and some commits ...
git push origin master