root/converter.py

Revision 340:d47095a15b60, 9.6 kB (checked in by Stefan Schwarzer <sschwarzer@sschwarzer.net>, 3 months ago)
Removed unused import statements.
Line 
1 # Copyright (C) 2007, Stefan Schwarzer
2 #
3 # Permission is hereby granted, free of charge, to any person
4 # obtaining a copy of this software and associated documentation files
5 # (the "Software"), to deal in the Software without restriction,
6 # including without limitation the rights to use, copy, modify, merge,
7 # publish, distribute, sublicense, and/or sell copies of the Software,
8 # and to permit persons to whom the Software is furnished to do so,
9 # subject to the following conditions:
10 #
11 # The above copyright notice and this permission notice shall be
12 # included in all copies or substantial portions of the Software.
13 #
14 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
18 # BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
19 # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 # SOFTWARE.
22
23 """
24 Convert data to HTML representations.
25 """
26
27 import cgi
28 import os
29 import urllib
30 import sys
31
32 # Websourcebrowser modules
33 import coding
34 import config
35 import dirtree
36 import pygmentsfinder
37 import session
38 import tools
39 import urlpath
40
41
42 def _dir_options_to_html(path, params):
43     """
44     Return the menu of options preceding the directory display.
45     """
46     html_parts = []
47     add_html = html_parts.append
48     # show horizontal menu of directory levels
49     add_html('<p class="Options">')
50     add_html('<a href="/" target="_top">Reset view</a>')
51     add_html('&nbsp;')
52     add_html('<a href="%s" target="_blank">Homepage</a>' %
53              cgi.escape(config.project_homepage))
54 #     add_html('&nbsp;')
55 #     add_html('<a href="/%s/help" target="%s">Help</a>' %
56 #              (config.SPECIAL_DIR, config.HELP_WINDOW_TARGET))
57     add_html('</p>')
58     add_html('<p class="Options">')
59     add_html('Directory levels: ')
60     dir_levels = params['dir_levels']
61     # 1 should always be there
62     level_options = [(1, "1")]
63     # `dir_levels - 1`
64     numeric_value = dir_levels - 1
65     numeric_value = max(numeric_value, 1)
66     value = str(numeric_value)
67     level_options.append((numeric_value, value))
68     # `dir_levels`
69     numeric_value = dir_levels
70     value = str(numeric_value)
71     level_options.append((numeric_value, value))
72     # `dir_levels + 1`
73     numeric_value = dir_levels + 1
74     numeric_value = min(numeric_value, sys.maxint)
75     value = str(numeric_value)
76     level_options.append((numeric_value, value))
77     # all
78     numeric_value = sys.maxint
79     value = "all"
80     level_options.append((numeric_value, value))
81     # sort offered dir levels
82     level_options.sort()
83     # remove duplicates
84     found_numeric_values = []
85     new_level_options = []
86     for numeric_value, value in level_options:
87         # check if we had this integer already; skip if yes
88         if numeric_value in found_numeric_values:
89             continue
90         # it doesn't make sense to have huge numeric values except the maximum
91         if numeric_value > 100 and numeric_value != sys.maxint:
92             continue
93         if numeric_value == sys.maxint:
94             value = "all"
95         found_numeric_values.append(numeric_value)
96         new_level_options.append((numeric_value, value))
97     # build menu
98     for numeric_value, value in new_level_options:
99         if numeric_value == dir_levels:
100             add_html(u'%s&nbsp;' % value)
101         else:
102             url = urlpath.to_url(config.root, path)
103             new_params = params.copy()
104             new_params['dir_levels'] = numeric_value
105             url = session.default_session.add_to_url(url, new_params)
106             add_html(u'<a href="%s">%s</a>&nbsp;' % (cgi.escape(url), value))
107     add_html('</p>')
108     return "\n".join(html_parts)
109
110 def dir_to_html(path, params):
111     """
112     Return HTML code unicode string for the directory `path`.
113     """
114     path = os.path.normpath(path)
115     start_level = dirtree.dir_level(path)
116     tree = dirtree.DirectoryTree(path)
117     tree.read(depth=params['dir_levels'])
118     if tree.items:
119         actual_dir_levels = max([dirtree.dir_level(item)
120                                  for item in tree.items]) \
121                             - start_level
122     else:
123         actual_dir_levels = 1
124     params['dir_levels'] = actual_dir_levels
125     html_parts = []
126     add_html = html_parts.append
127     add_html(_dir_options_to_html(path, params))
128     # show directory listing
129     add_html(u'<table>')
130     if path != config.root:
131         parent_url = urlpath.to_url(config.root, path) + "/.."
132         params['frames'] = "yes"
133         parent_url = session.default_session.add_to_url(parent_url, params)
134         add_html(u'<tr><td class="Options">'
135           u'<a href="%s" target="_top">up</a></td></tr>' % parent_url)
136     for item in tree.items:
137         # HTML for spacing
138         spacing = (u'<span class="Indent">' +
139                    # something like ">   " times ...
140                    (u'&gt;' + (config.dir_indent-1) * u'&nbsp;') * \
141                    # ... the nesting level
142                    (dirtree.dir_level(item) - start_level - 1) +
143                    u'</span>')
144         # HTML for link or plain text if the path isn't readable
145         link_text = cgi.escape(coding.decode(os.path.basename(item)))
146         if os.access(item, os.R_OK):
147             if os.path.isdir(item):
148                 anchor = tools.url_to_anchor(urlpath.to_url(config.root, item))
149                 # mask characters problematic for anchors
150                 params['anchor'] = anchor
151                 params['frames'] = "yes"
152                 params['dir_levels'] = \
153                   max(actual_dir_levels,
154                       dirtree.dir_level(item) - start_level + 1)
155                 url = urlpath.to_url(config.root, path)
156                 url = session.default_session.add_to_url(url, params)
157                 target = "_top"
158             else:
159                 # delete `anchor` and `dir_levels` items
160                 params.pop('anchor', None)
161                 params.pop('dir_levels', None)
162                 params['frames'] = "no"
163                 url = urlpath.to_url(config.root, item)
164                 url = session.default_session.add_to_url(url, params)
165                 target = config.SOURCE_WINDOW_TARGET
166             title = cgi.escape(coding.decode(
167                     urllib.unquote(urlpath.to_url(config.root, item))))
168             link = u'<a href="%s" title="%s" target="%s">%s</a>' % \
169                    (cgi.escape(url), title, target, link_text)
170             # add an anchor in order to jump to directories
171             if os.path.isdir(item):
172                 link = u'<a name="%s"></a>%s' % (anchor, link)
173         else:
174             # not really a link
175             link = link_text
176         # HTML for suffix
177         if os.path.isdir(item):
178             params.pop('anchor')
179             new_root_url = session.default_session.add_to_url(
180                            urlpath.to_url(config.root, item), params)
181             suffix = (u'&nbsp;/&nbsp;&nbsp;<small>'
182                       u'<a href="%s" target="_top">'
183                       u'set&nbsp;view</a></small>') % new_root_url
184         else:
185             suffix = ""
186         add_html(u'<tr><td>%s%s%s</td></tr>' % (spacing, link, suffix))
187     add_html(u'</table>')
188     return u"\n".join(html_parts)
189
190 def dumb_text_to_html(text):
191     """
192     Return an HTML representation of the `text`. The part "dumb"
193     in the name of the method means that the method does the
194     minimally necessary work.
195     """
196     return u"\n".join(('<pre>', cgi.escape(text), '</pre>'))
197
198 def text_to_html(text, path):
199     """
200     Convert the unicode string `text` to HTML and return the HTML
201     code, also as unicode string. Use the `path` of a text file to
202     guess the MIME type, which is used for coloring source code.
203     """
204     if not pygmentsfinder.found_pygments:
205         return dumb_text_to_html(text)
206     try:
207         # assume the link doesn't point to a link or at least has
208         #  a sensible name
209         if os.path.islink(path):
210             path = os.path.abspath(os.readlink(path))
211         lexer = pygmentsfinder.lexers.guess_lexer_for_filename(path, text)
212     except pygmentsfinder.lexers.ClassNotFound:
213         # files with many extensions are actually XML files, so
214         #  test explicitly for them
215         if text.lstrip().startswith(u'<?xml '):
216             lexer = pygmentsfinder.lexers.XmlLexer()
217         else:
218             lexer = pygmentsfinder.lexers.TextLexer()
219     formatter = pygmentsfinder.formatters.HtmlFormatter(
220                 linenos=config.line_numbers)
221     html = pygmentsfinder.pygments.highlight(text, lexer, formatter)
222     return html
223
224 def image_to_html(url):
225     """
226     Return HTML code (as unicode) for an image link for an image
227     which can be found under the absolute `url`.
228     """
229     image_source = "/%s/raw_data?url=%s" % (config.SPECIAL_DIR, url)
230     return u'<img src="%s" />' % image_source
231
232 def binary_to_html(data):
233     """
234     Return HTML code (as unicode) for supposed binary `data` in
235     form of a hex dump. The `data` must have been read in binary
236     mode.
237     """
238     # based on
239     #  http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/142812
240     filter_ = ''.join(
241       [(len(repr(chr(x)))==3) and chr(x) or '.' for x in range(256)])
242     length = 16
243     result = []
244     for i in xrange(0, len(data), length):
245         s = data[i:i+length]
246         hexa = ' '.join(["%02X" % ord(x) for x in s])
247         if len(s) > length // 2:
248             hexa = "%s %s" % (hexa[:23], hexa[23:])
249         printable = s.translate(filter_)
250         result.append("%08X    %-*s    |%s|\n" % (i, length*3, hexa,
251                                                   printable))
252     return dumb_text_to_html(''.join(result))
253
Note: See TracBrowser for help on using the browser.