# # # add_file "static/highlight.css" # content [45cedf6720b40c8e1cb9283d79e1929cb4e317c8] # # add_file "syntax.py" # content [1a4ead689403c0dc0b720dfc26705918af5690d7] # # patch "common.py" # from [19a25a6ea138661ce01454ec58c1ea20fcd884aa] # to [e2aff7e9041faa757e75fb6e705d525d24332e4c] # # patch "mtn.py" # from [d4b93790e5303b620758728ca041e30484950fdf] # to [ff9253965f0803b9121a160d9b6ec0b9630c03ee] # # patch "templates/base.html" # from [828ac669dcf846b15ebedc558c7da907079dd685] # to [6fb498c7263b78aa7fd8a3718da9da5b3570fe91] # # patch "viewmtn.py" # from [6f5bf7815c4b795ab7dc6f766050b00d46adcbed] # to [98c5cec0d0e729cd8e65577f45f323bc28162a02] # # set "syntax.py" # attr "mtn:execute" # value "true" # ============================================================ --- static/highlight.css 45cedf6720b40c8e1cb9283d79e1929cb4e317c8 +++ static/highlight.css 45cedf6720b40c8e1cb9283d79e1929cb4e317c8 @@ -0,0 +1,20 @@ +/* Style definition file generated by highlight 2.4.6, http://www.andre-simon.de/ */ + +/* Highlighting theme definition: */ + +body.hl { background-color:#ffffff; } +pre.hl { color:#000000; background-color:#ffffff; font-size:10pt; font-family:Courier;} +.num { color:#2928ff; } +.esc { color:#ff00ff; } +.str { color:#ff0000; } +.dstr { color:#818100; } +.slc { color:#838183; font-style:italic; } +.com { color:#838183; font-style:italic; } +.dir { color:#008200; } +.sym { color:#000000; } +.line { color:#555555; } +.kwa { color:#000000; font-weight:bold; } +.kwb { color:#830000; } +.kwc { color:#000000; font-weight:bold; } +.kwd { color:#010181; } + ============================================================ --- syntax.py 1a4ead689403c0dc0b720dfc26705918af5690d7 +++ syntax.py 1a4ead689403c0dc0b720dfc26705918af5690d7 @@ -0,0 +1,80 @@ +#!/usr/bin/env python2.4 + +from common import set_nonblocking, terminate_popen3 +from web import debug +import config +import popen2 +import select + +def highlight(lines, language='py'): + """A generator which will read lines from the given input stream, and yield them back + in syntax highlighted, HTML format. """ + + # trickier than this initially looks; the syntax highlighter might not necessarily + # have any more data for us, so it's necessary to use select() and write new data + # as it wants it, and read it back (buffer and yield lines) as possible. + + # this assumes the 'highlight' command, although shouldn't take much work to have this + # happy with other highlighters. + + fromchild_buf, tochild_buf = '', '' + in_pre = False + to_run = [config.highlight_command, '--syntax', language, '-c', '/dev/null', '--quiet'] + + process = popen2.Popen3(to_run, capturestderr=True) + map (set_nonblocking, [ process.fromchild, + process.tochild, + process.childerr ]) + while True: + r_fds = [process.fromchild] + w_fds = [] + if not process.tochild.closed: + w_fds.append(process.tochild) + r_stdin, r_stdout, r_stderr = select.select(r_fds, w_fds, [], None) + # debug ((r_stdin, r_stdout, r_stderr)) + if not r_stdin and not r_stdout and not r_stderr: + break + if process.fromchild in r_stdin: + data = process.fromchild.read() + if data == "": + break + fromchild_buf += data + + if process.tochild in r_stdout: + if tochild_buf == '': + try: + tochild_buf += lines.next() + except StopIteration: + tochild_buf = '' + if tochild_buf == '': + process.tochild.close() + else: + process.tochild.write(tochild_buf) + tochild_buf = '' + + if fromchild_buf != '': + while True: + idx = fromchild_buf.find('\n') + if idx == -1: + break + if in_pre and fromchild_buf.startswith(' 1: - branch_links = "branches " + branch_links = "branches " else: - branch_links = "branch " + branch_links = "branch " links = [] for branch in branches: - links.append(link(mt, "branch", branch)) + links.append(link(mt, "branch", branch)) return branch_links + ', '.join(links) def extract_cert_from_certs(certs, certname, as_list=False): rv = [] for cert in certs: - name, value = None, None - for k, v in cert: - if k == "name": name = v - elif k == "value": value = v - if name == None or value == None: continue - if name == certname: - if not as_list: - return value - else: - rv.append(value) + name, value = None, None + for k, v in cert: + if k == "name": name = v + elif k == "value": value = v + if name == None or value == None: continue + if name == certname: + if not as_list: + return value + else: + rv.append(value) return rv def determine_date(certs): dateval = extract_cert_from_certs(certs, "date") if dateval == None: - return None + return None else: - return parse_timecert(dateval) + return parse_timecert(dateval) def quicklog(value): hq = html_escape() rv = hq(value.strip().split('\n')[0]) if rv.startswith('*'): - rv = rv[1:].strip() + rv = rv[1:].strip() return rv def ago_string(event, now): def plural(v, singular, plural): - if v == 1: - return "%d %s" % (v, singular) - else: - return "%d %s" % (v, plural) + if v == 1: + return "%d %s" % (v, singular) + else: + return "%d %s" % (v, plural) now = datetime.datetime.utcnow() ago = now - event if ago.days > 0: - rv = "%s, %s" % (plural(ago.days, "day", "days"), - plural(ago.seconds / 3600, "hour", "hours")) + rv = "%s, %s" % (plural(ago.days, "day", "days"), + plural(ago.seconds / 3600, "hour", "hours")) elif ago.seconds > 3600: hours = ago.seconds / 3600 minutes = (ago.seconds - (hours * 3600)) / 60 - rv = "%s, %s" % (plural(hours, "hour", "hours"), - plural(minutes, "minute", "minutes")) + rv = "%s, %s" % (plural(hours, "hour", "hours"), + plural(minutes, "minute", "minutes")) else: minutes = ago.seconds / 60 seconds = (ago.seconds - (minutes * 60)) rv = "%s, %s" % (plural(minutes, "minute", "minutes"), - plural(seconds, "second", "seconds")) + plural(seconds, "second", "seconds")) return rv def link(mt, link_type, link_to, description = None, no_quote = False): hq = html_escape() if not no_quote and description != None: description = hq(description) if link_type == "revision": - rv = '' % (urllib.quote(link_to)) - if description != None: rv += description - else: rv += hq(link_to[:8]) + ".." - rv += '' - if description == None: rv = '[' + rv + ']' + rv = '' % (urllib.quote(link_to)) + if description != None: rv += description + else: rv += hq(link_to[:8]) + ".." + rv += '' + if description == None: rv = '[' + rv + ']' elif link_type == "diff" or link_type == "download_diff": - link_to = map(urllib.quote, filter(lambda x: x != None, link_to)) - if link_type == "diff": - handler = "diff.psp" - else: - handler = "getdiff.py" - uri = '%s?id1=%s&id2=%s' % (handler, link_to[0], link_to[1]) - if len(link_to) == 3: - uri += '&fname=%s' % (link_to[2]) - rv = '' - if description != None: rv += description - else: rv += "diff" - rv += '' + link_to = map(urllib.quote, filter(lambda x: x != None, link_to)) + if link_type == "diff": + handler = "diff.psp" + else: + handler = "getdiff.py" + uri = '%s?id1=%s&id2=%s' % (handler, link_to[0], link_to[1]) + if len(link_to) == 3: + uri += '&fname=%s' % (link_to[2]) + rv = '' + if description != None: rv += description + else: rv += "diff" + rv += '' elif link_type == "download": - if type(link_to) == type([]): - rv = '' % (urllib.quote(link_to[0]), - urllib.quote(link_to[1])) - link_id = link_to[0] - else: - rv = '' % (urllib.quote(link_to)) - link_id = link_to - if description != None: rv += description + "" - else: rv = "[" + rv + hq(link_id[:8]) + ".." + "]" + if type(link_to) == type([]): + rv = '' % (urllib.quote(link_to[0]), + urllib.quote(link_to[1])) + link_id = link_to[0] + else: + rv = '' % (urllib.quote(link_to)) + link_id = link_to + if description != None: rv += description + "" + else: rv = "[" + rv + hq(link_id[:8]) + ".." + "]" elif link_type == "file": - revision_id, path = link_to - rv = '' % (urllib.quote(revision_id), - urllib.quote(path)) - if description != None: rv += description + "" - else: rv = "[" + rv + hq(path + '@' + revision_id[:8]) + ".." + "]" + revision_id, path = link_to + rv = '' % (urllib.quote(revision_id), + urllib.quote(path)) + if description != None: rv += description + "" + else: rv = "[" + rv + hq(path + '@' + revision_id[:8]) + ".." + "]" elif link_type == "fileinbranch": - branch, path = link_to - rv = '' % (urllib.quote(branch), - urllib.quote(path)) - if description != None: rv += description + "" - else: rv = "[" + rv + hq(path + '@' + branch) + "]" + branch, path = link_to + rv = '' % (urllib.quote(branch), + urllib.quote(path)) + if description != None: rv += description + "" + else: rv = "[" + rv + hq(path + '@' + branch) + "]" elif link_type == "branch": - rv = '' % (urllib.quote(link_to)) - if description != None: rv += description - else: rv += hq(link_to) - rv += '' + rv = '' % (urllib.quote(link_to)) + if description != None: rv += description + else: rv += hq(link_to) + rv += '' elif link_type == "tar": - rv = '' % (urllib.quote(link_to)) - if description != None: rv += description - else: rv = "tar of [" + rv + hq(link_to[:8]) + "..]" + "]" - rv += '' + rv = '' % (urllib.quote(link_to)) + if description != None: rv += description + else: rv = "tar of [" + rv + hq(link_to[:8]) + "..]" + "]" + rv += '' elif link_type == "headofbranch": - rv = '' % (urllib.quote(link_to)) - if description != None: rv += description - else: rv += "head of " + hq(link_to) - rv += '' + rv = '' % (urllib.quote(link_to)) + if description != None: rv += description + else: rv += "head of " + hq(link_to) + rv += '' elif link_type == "manifest": - if type(link_to) == type([]): - link_to, path = link_to - rv = '' % (urllib.quote(link_to), urllib.quote(path)) - else: - rv = '' % (urllib.quote(link_to)) - if description != None: rv += description - else: rv += hq(link_to[:8]) + ".." - rv += '' - if description == None: rv = '[' + rv + ']' + if type(link_to) == type([]): + link_to, path = link_to + rv = '' % (urllib.quote(link_to), urllib.quote(path)) + else: + rv = '' % (urllib.quote(link_to)) + if description != None: rv += description + else: rv += hq(link_to[:8]) + ".." + rv += '' + if description == None: rv = '[' + rv + ']' else: - rv = 'Unknown link type: %s' % (hq(link_type)) + rv = 'Unknown link type: %s' % (hq(link_type)) return '%s' % (hq(link_type+'Link'), rv) def html_escape(): @@ -167,9 +187,9 @@ def is_binary(str): nontext_chars = "\x01\x02\x03\x04\x05\x06\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1c\x1d\x1e\x1f" check = {} for char in nontext_chars: - check[char] = True - for i in str: - if check.has_key(i): return True + check[char] = True + for i in str: + if check.has_key(i): return True return False # hm, later on might make this be some javascript that does an call back to the server. @@ -179,61 +199,61 @@ def colourise_code(req, hq, path, conten mime_type = mimetypes.guess_type(path)[0] if mime_type == None: mime_type = 'text/plain' if mime_type == 'image/png' or mime_type == 'image/jpeg' or mime_type == 'image/gif': - display_as_image = True + display_as_image = True else: display_as_image = False # okay; can we guess a valid enscript filter to run this through? tsp = mime_type.split('/', 1) if filter == None and tsp[0] == 'text': - candidate = tsp[1] - if candidate.startswith('x-'): candidate = candidate[2:] - if candidate.endswith('src'): candidate = candidate[:-3] - if candidate.endswith('hdr'): candidate = candidate[:-3] - if candidate == 'c++': candidate = 'cpp' # ugly - if candidate in enscript_langs: filter = candidate + candidate = tsp[1] + if candidate.startswith('x-'): candidate = candidate[2:] + if candidate.endswith('src'): candidate = candidate[:-3] + if candidate.endswith('hdr'): candidate = candidate[:-3] + if candidate == 'c++': candidate = 'cpp' # ugly + if candidate in enscript_langs: filter = candidate if filter == None: - # heh, will at least work for lua files - last_dot = path.rfind('.') - if last_dot == -1: last_dot = 0 - candidate = path[last_dot:] - if candidate in enscript_langs: filter = candidate + # heh, will at least work for lua files + last_dot = path.rfind('.') + if last_dot == -1: last_dot = 0 + candidate = path[last_dot:] + if candidate in enscript_langs: filter = candidate # if no filter then let's check if it's binary or not; if not binary # we'll just treat it as text; otherwise display a warning and a download # link if filter == None and not is_binary(contents): - filter = 'text' + filter = 'text' req.write('''
'):
- in_contents = True
- start_code()
- elif line.startswith(''):
- in_contents = False
- stop_code()
- elif in_contents:
- req.write(line + '\r\n')
- if filter == "text": text()
- else: enscript()
+ def start_code():
+ req.write('')
+ def stop_code():
+ req.write('')
+ def text():
+ start_code()
+ req.write(hq(contents))
+ stop_code()
+ def enscript():
+ command = config.enscript_path + ' -o - --color --language=html'
+ command += ' --highlight=%s' % (pipes.quote(filter))
+ result = run_command(command, to_child=contents)
+ if result['exitcode'] != 0:
+ raise Exception('Error running enscript (%s) : "%s".' % (hq(command), hq(result['childerr'])))
+ in_contents = False
+ for line in result['fromchild'].split('\n'):
+ if line.startswith(''):
+ in_contents = True
+ start_code()
+ elif line.startswith(''):
+ in_contents = False
+ stop_code()
+ elif in_contents:
+ req.write(line + '\r\n')
+ if filter == "text": text()
+ else: enscript()
else:
- req.write('''This file seems to binary and not suitable for display in the browser. You must %s the file and use a suitable viewer.
''' % (link("download", [matching_file_id, path], "download"))) + req.write('''This file seems to binary and not suitable for display in the browser. You must %s the file and use a suitable viewer.
''' % (link("download", [matching_file_id, path], "download"))) req.write('''