def processRange(offset, count, context): if context: context = getContext(offset) else: context = None # Offset is a 1-based line number. start = offset - 1 # If count is -1, fetch all lines. end = start + count if count > -1 else None lines = file.newLines(highlighted=True)[start:end] if tabify: lines = [htmlutils.tabify(line, tabwidth, indenttabsmode) for line in lines] return { "lines": lines, "context": context }
def processRange(offset, count, context): if context: context = getContext(offset) else: context = None # Offset is a 1-based line number. start = offset - 1 # If count is -1, fetch all lines. end = start + count if count > -1 else None lines = file.newLines(highlighted=True)[start:end] if tabify: lines = [ htmlutils.tabify(line, tabwidth, indenttabsmode) for line in lines ] return {"lines": lines, "context": context}
def renderFile(db, target, user, review, file, first_file=False, options={}, conflicts=False, add_resources=True): if add_resources: addResources(db, user, review, options.get("compact", False), options.get("tabify"), target) if options.get("count_chunks"): deleted = 0 inserted = 0 if file.wasRemoved(): file.loadOldLines(False) deleted = file.oldCount() else: for macro_chunk in file.macro_chunks: for chunk in macro_chunk.chunks: deleted += chunk.delete_count inserted += chunk.insert_count chunksText = "-%d/+%d lines" % (deleted, inserted) else: chunksText = "" compact = options.get("compact", False) file_table_class = "file sourcefont" compact = options.get("compact", False) if options.get("show"): file_table_class += " show" if options.get("expand"): file_table_class += " expanded" compact = False if first_file: file_table_class += " first" file_id = "f%d" % file.id customFileId = options.get("file_id") if customFileId: file_id = customFileId(file_id) target.script(type="text/javascript").text("calculateTabWidth();") table = target.table(file_table_class, width='100%', cellspacing=0, cellpadding=0, id=file_id, critic_file_id=file.id, critic_parent_index=options.get("parent_index")) if not compact: columns = table.colgroup() columns.col('edge').empty() columns.col('linenr').empty() columns.col('line').empty() columns.col('middle').empty() columns.col('middle').empty() columns.col('line').empty() columns.col('linenr').empty() columns.col('edge').empty() row = table.thead().tr() header_left = options.get("header_left") header_right = options.get("header_right") if header_left: header_left(db, row.td('left', colspan=4, align='left'), file) else: cell = row.td('left', colspan=4, align='left') commit = options.get("commit") if commit: review_arg = "&review=%d" % review.id if review else "" repository_arg = "&repository=%d" % file.repository.id if not review else "" cell.a("showtree root", href="showtree?sha1=%s&path=/%s%s" % (commit.sha1, review_arg, repository_arg)).text("root") cell.span("slash").text('/') components = file.path.split("/") for index, component in enumerate(components[:-1]): cell.a("showtree", href="showtree?sha1=%s&path=%s%s%s" % (commit.sha1, "/".join(components[:index + 1]), review_arg, repository_arg)).text(component) cell.span("slash").text('/') cell.a("showtree", href="showfile?sha1=%s&path=%s%s%s" % (commit.sha1, "/".join(components), review_arg, repository_arg)).text(components[-1]) else: cell.text(file.path) if not compact: cell.comment("sha1: %s to %s" % (file.old_sha1, file.new_sha1)) if header_right: header_right(db, row.td('right', colspan=4, align='right'), file) else: row.td('right', colspan=4, align='right').text(chunksText) next_old_offset = 1 next_new_offset = 1 display_type = options.get("display_type", "both") deleted_file = False added_file = False if not file.isBinaryChanges(): if file.old_sha1 == 40 * '0': display_type = "new" if file.getLanguage() is None: limit = configuration.limits.MAXIMUM_ADDED_LINES_UNRECOGNIZED else: limit = configuration.limits.MAXIMUM_ADDED_LINES_RECOGNIZED count = file.newCount() if count > limit and len(file.macro_chunks) == 1 and len(file.macro_chunks[0].lines) == count: added_file = True elif file.new_sha1 == 40 * '0': display_type = "old" deleted_file = not options.get("include_deleted", False) def baseLineId(file, line, index): if line.type == diff.Line.DELETED: return "f%do%dn0" % (file.id, line.old_offset) elif line.type == diff.Line.INSERTED: return "f%do0n%d" % (file.id, line.new_offset) else: return "f%do%dn%d" % (file.id, line.old_offset, line.new_offset) def baseLineCellId(file, version, line): if line: return "f%d%s%d" % (file.id, version, line) else: return None customLineId = options.get("line_id") if customLineId: lineId = lambda file, line, index: customLineId(baseLineId(file, line, index)) else: lineId = baseLineId customLineCellId = options.get("line_cell_id") if customLineCellId: lineCellId = lambda file, version, line: customLineCellId(baseLineCellId(file, version, line)) else: lineCellId = baseLineCellId def lineType(line, index): type = line.type if type == diff.Line.DELETED: return "deleted" elif type == diff.Line.INSERTED: return "inserted" elif type == diff.Line.MODIFIED: return "modified whitespace" if line.is_whitespace else "modified" elif type == diff.Line.REPLACED: return "replaced" else: return "context" support_expand = options.get("support_expand", True) style = options.get("style", "horizontal") collapse_simple_hunks = user.getPreference(db, 'commit.diff.collapseSimpleHunks') content_before = options.get("content_before") if content_before: content = table.tbody('content') row = content.tr('content') row.td(colspan=2).text() content_before(db, row.td(colspan=4)) row.td(colspan=2).text() if added_file or deleted_file: table.tbody('spacer').tr('spacer').td(colspan=8).text() verb = "added" if added_file else "deleted" side = "new" if added_file else "old" if added_file: count = file.newCount() else: count = file.oldCount() tbody = table.tbody('deleted') row = tbody.tr('deleted') row.td(colspan=2).text() row.td(colspan=4).h2().text("File was %s." % verb) row.td(colspan=2).text() row = tbody.tr('deleted') row.td(colspan=2).text() row.td(colspan=4).button(onclick="fetchFile(%d, '%s', event.currentTarget.parentNode.parentNode.parentNode);" % (file.id, side)).text("Fetch %d %s Lines" % (count, verb.capitalize())) row.td(colspan=2).text() table.tbody('spacer').tr('spacer').td(colspan=8).text() elif file.isBinaryChanges(): table.tbody('spacer').tr('spacer').td(colspan=8).text() binary = table.tbody('binary') if file.wasAdded(): title = "Binary file added." elif file.wasRemoved(): title = "Binary file removed." else: title = "Binary file modified." row = binary.tr('binary') row.td(colspan=2).text() row.td(colspan=4).h2().text(title) row.td(colspan=2).text() row = binary.tr('download') row.td(colspan=2).text() cell = row.td(colspan=4) def linkToFile(target, file, sha1): is_image = False try: base, extension = file.path.rsplit(".") if configuration.mimetypes.MIMETYPES.get(extension, "").startswith("image/"): is_image = True except: pass url = "download/%s?sha1=%s&repository=%d" % (file.path, sha1, file.repository.id) link = target.a(href=url) if is_image: link.img(src=url) else: link.text(sha1) if file.wasAdded(): linkToFile(cell, file, file.new_sha1) elif file.wasRemoved(): linkToFile(cell, file, file.old_sha1) else: linkToFile(cell, file, file.old_sha1) cell.innerHTML(" → ") linkToFile(cell, file, file.new_sha1) row.td(colspan=2).text() table.tbody('spacer').tr('spacer').td(colspan=8).text() else: if options.get("tabify"): tabwidth = file.getTabWidth() indenttabsmode = file.getIndentTabsMode() tabify = lambda line: htmlutils.tabify(line, tabwidth, indenttabsmode) else: tabify = lambda line: line code_contexts = CodeContexts(db, file.new_sha1, file.macro_chunks[0].lines[0].new_offset, file.macro_chunks[-1].lines[-1].new_offset) blocks = [("[%d,%d]" % (macro_chunk.lines[0].new_offset, macro_chunk.lines[-1].new_offset)) for macro_chunk in file.macro_chunks] target.script(type="text/javascript").text("blocks[%d] = [%s];" % (file.id, ",".join(blocks))) for index, macro_chunk in enumerate(file.macro_chunks): first_line = macro_chunk.lines[0] last_line = macro_chunk.lines[-1] spacer = table.tbody('spacer') if support_expand and next_old_offset < first_line.old_offset and next_new_offset < first_line.new_offset: row = spacer.tr('expand').td(colspan='8') expandHTML(db, file, next_old_offset, next_new_offset, first_line.old_offset - next_old_offset, row) code_context = code_contexts.find(first_line.new_offset) if code_context: spacer.tr('context').td(colspan='8').text(code_context) spacer.tr('spacer').td(colspan='8').text() lines = table.tbody('lines') local_display_type = display_type for line in macro_chunk.lines: if line.type != diff.Line.INSERTED: match = re_tailws.match(line.old_value) if match: line.old_value = match.group(1) + "<i class='tailws'>" + match.group(2) + "</i>" + match.group(3) if line.type != diff.Line.DELETED: match = re_tailws.match(line.new_value) if match: line.new_value = match.group(1) + "<i class='tailws'>" + match.group(2) + "</i>" + match.group(3) if line.old_value: line.old_value = line.old_value.replace("\r", "<i class='cr'></i>") if line.new_value: line.new_value = line.new_value.replace("\r", "<i class='cr'></i>") if collapse_simple_hunks: if local_display_type == "both": deleted = False inserted = False for line in macro_chunk.lines: if line.type == diff.Line.MODIFIED or line.type == diff.Line.REPLACED: break elif line.type == diff.Line.DELETED: if inserted: break deleted = True elif line.type == diff.Line.INSERTED: if deleted: break inserted = True else: if deleted: local_display_type = "old" if inserted: local_display_type = "new" if compact: def packSyntaxHighlighting(line): return re_tag.sub(lambda m: "<%s%s>" % (m.group(1), m.group(2)), line) items = [] for line in macro_chunk.lines: if line.type == diff.Line.MODIFIED and line.is_whitespace: line_type = diff.Line.WHITESPACE elif conflicts and line.type == diff.Line.DELETED and line.isConflictMarker(): line_type = diff.Line.CONFLICT else: line_type = line.type data = [str(line_type)] if line.type != diff.Line.INSERTED: data.append(jsify(packSyntaxHighlighting(tabify(line.old_value)), json=True)) if line.type != diff.Line.DELETED: data.append(jsify(packSyntaxHighlighting(tabify(line.new_value)), json=True)) items.append("[%s]" % ",".join(data)) data = "[%d,%d,%d,%d,%s]" % (file.id, 2 if local_display_type == "both" else 1, macro_chunk.lines[0].old_offset, macro_chunk.lines[0].new_offset, "[%s]" % ",".join(items)) lines.comment(data.replace("--", "-\u002d")) elif style == "vertical" or local_display_type != "both": linesIterator = iter(macro_chunk.lines) line = linesIterator.next() def lineHTML(what, file, line, is_whitespace, target): line_class = what if is_whitespace and line.type == diff.Line.MODIFIED: line_class = "modified" if what == "deleted": linenr = line.old_offset else: linenr = line.new_offset row = target.tr("line " + line_class, id=lineId(file, line, 0)) row.td("edge").text() row.td("linenr old").text(linenr) if what == "deleted" or local_display_type == "old": code = line.old_value lineClass = "old" else: code = line.new_value lineClass = "new" if not code: code = " " row.td('line single ' + lineClass, colspan=4, id=lineCellId(file, lineClass[0], linenr)).innerHTML(tabify(code)) row.td('linenr new').text(linenr) row.td("edge").text() try: while line: while line.type == diff.Line.CONTEXT: lineHTML("context", file, line, False, lines) line = linesIterator.next() deleted = [] inserted = [] while line.is_whitespace: lineHTML("modified", file, line, True, lines) line = linesIterator.next() previous_type = diff.Line.DELETED try: while line.type >= previous_type and not line.is_whitespace: if line.type != diff.Line.INSERTED: deleted.append(line) if line.type != diff.Line.DELETED: inserted.append(line) previous_type = line.type line = None line = linesIterator.next() except StopIteration: line = None for deletedLine in deleted: lineHTML("deleted", file, deletedLine, False, lines) for insertedLine in inserted: lineHTML("inserted", file, insertedLine, False, lines) except StopIteration: pass elif style == "horizontal": for line in macro_chunk.lines: old_offset = None new_offset = None old_line = None new_line = None if line.type != diff.Line.INSERTED: old_offset = line.old_offset old_line = tabify(line.old_value) if line.type != diff.Line.DELETED: new_offset = line.new_offset new_line = tabify(line.new_value) if not old_line: old_line = " " if old_line is None: old_offset = None if not new_line: new_line = " " if new_line is None: new_offset = None line_type = lineType(line, 0) if conflicts and line.isConflictMarker(): line_type += " conflict" row = ("<tr class='line %s' id='%s'>" "<td class='edge'> </td>" "<td class='linenr old'>%s</td>" "<td class='line old'%s>%s</td>" "<td class='middle' colspan=2> </td>" "<td class='line new'%s>%s</td>" "<td class='linenr new'>%s</td>" "<td class='edge'> </td>" "</tr>\n") % (line_type, lineId(file, line, 0), str(old_offset) if old_offset else " ", " id='%s'" % lineCellId(file, "o", old_offset) if old_offset else "", old_line, " id='%s'" % lineCellId(file, "n", new_offset) if new_offset else "", new_line, str(new_offset) if new_offset else " ") lines.innerHTML(row) next_old_offset = last_line.old_offset + 1 next_new_offset = last_line.new_offset + 1 spacer = table.tbody('spacer') if support_expand and next_old_offset < file.oldCount() + 1 and next_new_offset < file.newCount() + 1: row = spacer.tr('expand').td(colspan='8') expandHTML(db, file, next_old_offset, next_new_offset, 1 + file.oldCount() - next_old_offset, row) spacer.tr('spacer').td(colspan='8').text() content_after = options.get("content_after") if content_after: content = table.tbody('content') row = content.tr('content') row.td(colspan=2).text() content_after(db, row.td(colspan=4), file=file) row.td(colspan=2).text() content.tr('spacer').td(colspan=8).text() row = table.tfoot().tr() cell = row.td('left', colspan=4) commit = options.get("commit") if commit: review_arg = "&review=%d" % review.id if review else "" repository_arg = "&repository=%d" % file.repository.id if not review else "" cell.a("showtree root", href="showtree?sha1=%s&path=/%s%s" % (commit.sha1, review_arg, repository_arg)).text("root") cell.span("slash").text('/') components = file.path.split("/") for index, component in enumerate(components[:-1]): cell.a("showtree", href="showtree?sha1=%s&path=%s%s%s" % (commit.sha1, "/".join(components[:index + 1]), review_arg, repository_arg)).text(component) cell.span("slash").text('/') cell.a("showtree", href="showfile?sha1=%s&path=%s%s%s" % (commit.sha1, "/".join(components), review_arg, repository_arg)).text(components[-1]) else: cell.text(file.path) row.td('right', colspan=4).text(chunksText)
def renderShowFile(req, db, user): cursor = db.cursor() sha1 = req.getParameter("sha1") path = req.getParameter("path") line = req.getParameter("line", None) review_id = req.getParameter("review", None, filter=int) default_tabify = "yes" if user.getPreference(db, "commit.diff.visualTabs") else "no" tabify = req.getParameter("tabify", default_tabify) == "yes" if line is None: first, last = None, None else: if "-" in line: first, last = map(int, line.split("-")) else: first = last = int(line) context = req.getParameter("context", user.getPreference(db, "commit.diff.contextLines"), int) first_with_context = max(1, first - context) last_with_context = last + context if user.getPreference(db, "commit.diff.compactMode"): default_compact = "yes" else: default_compact = "no" compact = req.getParameter("compact", default_compact) == "yes" if len(path) == 0 or path[-1:] == "/": raise page.utils.DisplayMessage( title="Invalid path parameter", body="<p>The path must be non-empty and must not end with a <code>/</code>.</p>", html=True) if path[0] == '/': full_path = path if path != "/": path = path[1:] else: full_path = "/" + path if not path: path = "/" if review_id is None: review = None repository_arg = req.getParameter("repository", "") if repository_arg: repository = gitutils.Repository.fromParameter(db, repository_arg) else: repository = gitutils.Repository.fromSHA1(db, sha1) else: review = dbutils.Review.fromId(db, review_id) repository = review.repository document = htmlutils.Document(req) html = document.html() head = html.head() body = html.body() if review: page.utils.generateHeader(body, db, user, lambda target: review_utils.renderDraftItems(db, user, review, target), extra_links=[("r/%d" % review.id, "Back to Review")]) else: page.utils.generateHeader(body, db, user) document.addExternalStylesheet("resource/showfile.css") document.addInternalStylesheet(htmlutils.stripStylesheet(user.getResource(db, "syntax.css")[1], compact)) commit = gitutils.Commit.fromSHA1(db, repository, sha1) file_sha1 = commit.getFileSHA1(full_path) file_id = dbutils.find_file(db, path=path) if file_sha1 is None: raise page.utils.DisplayMessage( title="File does not exist", body=("<p>There is no file named <code>%s</code> in the commit " "<a href='/showcommit?repository=%s&sha1=%s'>" "<code>%s</code></a>.</p>" % (htmlutils.htmlify(textutils.escape(full_path)), htmlutils.htmlify(repository.name), htmlutils.htmlify(sha1), htmlutils.htmlify(sha1[:8]))), html=True) file = diff.File(file_id, path, None, file_sha1, repository) # A new file ID might have been added to the database, so need to commit. db.commit() if file.canHighlight(): requestHighlights(repository, { file.new_sha1: (file.path, file.getLanguage()) }) file.loadNewLines(True, request_highlight=True) if review: document.addInternalScript(user.getJS()) document.addInternalScript(review.getJS()) document.addInternalScript("var changeset = { parent: { id: %(id)d, sha1: %(sha1)r }, child: { id: %(id)d, sha1: %(sha1)r } };" % { 'id': commit.getId(db), 'sha1': commit.sha1 }) document.addInternalScript("var files = { %(id)d: { new_sha1: %(sha1)r }, %(sha1)r: { id: %(id)d, side: 'n' } };" % { 'id': file_id, 'sha1': file_sha1 }) document.addExternalStylesheet("resource/review.css") document.addExternalScript("resource/review.js") cursor.execute("""SELECT DISTINCT commentchains.id FROM commentchains JOIN commentchainlines ON (commentchainlines.chain=commentchains.id) WHERE commentchains.review=%s AND commentchains.file=%s AND commentchainlines.sha1=%s AND ((commentchains.state!='draft' OR commentchains.uid=%s) AND commentchains.state!='empty') GROUP BY commentchains.id""", (review.id, file_id, file_sha1, user.id)) comment_chain_script = "" for (chain_id,) in cursor.fetchall(): chain = review_comment.CommentChain.fromId(db, chain_id, user, review=review) chain.loadComments(db, user) comment_chain_script += "commentChains.push(%s);\n" % chain.getJSConstructor(file_sha1) if comment_chain_script: document.addInternalScript(comment_chain_script) document.addExternalStylesheet("resource/comment.css") document.addExternalScript("resource/comment.js") document.addExternalScript("resource/showfile.js") if tabify: document.addExternalStylesheet("resource/tabify.css") document.addExternalScript("resource/tabify.js") tabwidth = file.getTabWidth() indenttabsmode = file.getIndentTabsMode() if user.getPreference(db, "commit.diff.highlightIllegalWhitespace"): document.addInternalStylesheet(user.getResource(db, "whitespace.css")[1], compact) if first is not None: document.addInternalScript("var firstSelectedLine = %d, lastSelectedLine = %d;" % (first, last)) target = body.div("main") if tabify: target.script(type="text/javascript").text("calculateTabWidth();") table = target.table('file show expanded paleyellow', align='center', cellspacing=0) columns = table.colgroup() columns.col('edge') columns.col('linenr') columns.col('line') columns.col('middle') columns.col('middle') columns.col('line') columns.col('linenr') columns.col('edge') thead = table.thead() cell = thead.tr().td('h1', colspan=8) h1 = cell.h1() def make_url(url_path, path): params = { "sha1": sha1, "path": path } if review is None: params["repository"] = str(repository.id) else: params["review"] = str(review.id) return "%s?%s" % (url_path, urllib.urlencode(params)) h1.a("root", href=make_url("showtree", "/")).text("root") h1.span().text('/') components = path.split("/") for index, component in enumerate(components[:-1]): h1.a(href=make_url("showtree", "/".join(components[:index + 1]))).text(component, escape=True) h1.span().text('/') if first is not None: h1.a(href=make_url("showfile", "/".join(components))).text(components[-1], escape=True) else: h1.text(components[-1], escape=True) h1.span("right").a(href=("/download/%s?repository=%s&sha1=%s" % (urllib.quote(path), repository.name, file_sha1)), download=urllib.quote(path)).text("[download]") h1.span("right").a(href=("/download/%s?repository=%s&sha1=%s" % (urllib.quote(path), repository.name, file_sha1))).text("[view]") table.tbody('spacer top').tr('spacer top').td(colspan=8).text() tbody = table.tbody("lines") yield document.render(stop=tbody, pretty=not compact) for linenr, line in enumerate(file.newLines(True)): linenr = linenr + 1 highlight_class = "" if first is not None: if not (first_with_context <= linenr <= last_with_context): continue if linenr == first: highlight_class += " first-selected" if linenr == last: highlight_class += " last-selected" if tabify: line = htmlutils.tabify(line, tabwidth, indenttabsmode) line = line.replace("\r", "<i class='cr'></i>") row = tbody.tr("line context single", id="f%do%dn%d" % (file.id, linenr, linenr)) row.td("edge").text() row.td("linenr old").text(linenr) row.td("line single whole%s" % highlight_class, id="f%dn%d" % (file.id, linenr), colspan=4).innerHTML(line) row.td("linenr new").text(linenr) row.td("edge").text() if linenr % 500: yield document.render(stop=tbody, pretty=not compact) table.tbody('spacer bottom').tr('spacer bottom').td(colspan=8).text() yield document.render(pretty=not compact)
def renderShowFile(req, db, user): cursor = db.cursor() sha1 = req.getParameter("sha1") path = req.getParameter("path") line = req.getParameter("line", None) review_id = req.getParameter("review", None, filter=int) default_tabify = "yes" if user.getPreference( db, "commit.diff.visualTabs") else "no" tabify = req.getParameter("tabify", default_tabify) == "yes" if line is None: first, last = None, None else: if "-" in line: first, last = map(int, line.split("-")) else: first = last = int(line) context = req.getParameter( "context", user.getPreference(db, "commit.diff.contextLines"), int) first_with_context = max(1, first - context) last_with_context = last + context if user.getPreference(db, "commit.diff.compactMode"): default_compact = "yes" else: default_compact = "no" compact = req.getParameter("compact", default_compact) == "yes" if len(path) == 0 or path[-1:] == "/": raise page.utils.DisplayMessage( title="Invalid path parameter", body= "<p>The path must be non-empty and must not end with a <code>/</code>.</p>", html=True) if path[0] == '/': full_path = path if path != "/": path = path[1:] else: full_path = "/" + path if not path: path = "/" if review_id is None: review = None repository_arg = req.getParameter("repository", "") if repository_arg: repository = gitutils.Repository.fromParameter(db, repository_arg) else: repository = gitutils.Repository.fromSHA1(db, sha1) else: review = dbutils.Review.fromId(db, review_id) repository = review.repository document = htmlutils.Document(req) html = document.html() head = html.head() body = html.body() if review: page.utils.generateHeader(body, db, user, lambda target: review_utils.renderDraftItems( db, user, review, target), extra_links=[("r/%d" % review.id, "Back to Review")]) else: page.utils.generateHeader(body, db, user) document.addExternalStylesheet("resource/showfile.css") document.addInternalStylesheet( htmlutils.stripStylesheet( user.getResource(db, "syntax.css")[1], compact)) commit = gitutils.Commit.fromSHA1(db, repository, sha1) file_sha1 = commit.getFileSHA1(full_path) file_id = dbutils.find_file(db, path=path) if file_sha1 is None: raise page.utils.DisplayMessage( title="File does not exist", body=("<p>There is no file named <code>%s</code> in the commit " "<a href='/showcommit?repository=%s&sha1=%s'>" "<code>%s</code></a>.</p>" % (htmlutils.htmlify(textutils.escape(full_path)), htmlutils.htmlify(repository.name), htmlutils.htmlify(sha1), htmlutils.htmlify(sha1[:8]))), html=True) file = diff.File(file_id, path, None, file_sha1, repository) # A new file ID might have been added to the database, so need to commit. db.commit() if file.canHighlight(): requestHighlights(repository, {file.new_sha1: (file.path, file.getLanguage())}) file.loadNewLines(True, request_highlight=True) if review: document.addInternalScript(user.getJS()) document.addInternalScript(review.getJS()) document.addInternalScript( "var changeset = { parent: { id: %(id)d, sha1: %(sha1)r }, child: { id: %(id)d, sha1: %(sha1)r } };" % { 'id': commit.getId(db), 'sha1': commit.sha1 }) document.addInternalScript( "var files = { %(id)d: { new_sha1: %(sha1)r }, %(sha1)r: { id: %(id)d, side: 'n' } };" % { 'id': file_id, 'sha1': file_sha1 }) document.addExternalStylesheet("resource/review.css") document.addExternalScript("resource/review.js") cursor.execute( """SELECT DISTINCT commentchains.id FROM commentchains JOIN commentchainlines ON (commentchainlines.chain=commentchains.id) WHERE commentchains.review=%s AND commentchains.file=%s AND commentchainlines.sha1=%s AND ((commentchains.state!='draft' OR commentchains.uid=%s) AND commentchains.state!='empty') GROUP BY commentchains.id""", (review.id, file_id, file_sha1, user.id)) comment_chain_script = "" for (chain_id, ) in cursor.fetchall(): chain = review_comment.CommentChain.fromId(db, chain_id, user, review=review) chain.loadComments(db, user) comment_chain_script += "commentChains.push(%s);\n" % chain.getJSConstructor( file_sha1) if comment_chain_script: document.addInternalScript(comment_chain_script) document.addExternalStylesheet("resource/comment.css") document.addExternalScript("resource/comment.js") document.addExternalScript("resource/showfile.js") if tabify: document.addExternalStylesheet("resource/tabify.css") document.addExternalScript("resource/tabify.js") tabwidth = file.getTabWidth() indenttabsmode = file.getIndentTabsMode() if user.getPreference(db, "commit.diff.highlightIllegalWhitespace"): document.addInternalStylesheet( user.getResource(db, "whitespace.css")[1], compact) if first is not None: document.addInternalScript( "var firstSelectedLine = %d, lastSelectedLine = %d;" % (first, last)) target = body.div("main") if tabify: target.script(type="text/javascript").text("calculateTabWidth();") table = target.table('file show expanded paleyellow', align='center', cellspacing=0) columns = table.colgroup() columns.col('edge') columns.col('linenr') columns.col('line') columns.col('middle') columns.col('middle') columns.col('line') columns.col('linenr') columns.col('edge') thead = table.thead() cell = thead.tr().td('h1', colspan=8) h1 = cell.h1() def make_url(url_path, path): params = {"sha1": sha1, "path": path} if review is None: params["repository"] = str(repository.id) else: params["review"] = str(review.id) return "%s?%s" % (url_path, urllib.urlencode(params)) h1.a("root", href=make_url("showtree", "/")).text("root") h1.span().text('/') components = path.split("/") for index, component in enumerate(components[:-1]): h1.a(href=make_url("showtree", "/".join(components[:index + 1]))).text( component, escape=True) h1.span().text('/') if first is not None: h1.a(href=make_url("showfile", "/".join(components))).text( components[-1], escape=True) else: h1.text(components[-1], escape=True) h1.span("right").a(href=("/download/%s?repository=%s&sha1=%s" % (urllib.quote(path), repository.name, file_sha1)), download=urllib.quote(path)).text("[download]") h1.span("right").a( href=("/download/%s?repository=%s&sha1=%s" % (urllib.quote(path), repository.name, file_sha1))).text("[view]") table.tbody('spacer top').tr('spacer top').td(colspan=8).text() tbody = table.tbody("lines") yield document.render(stop=tbody, pretty=not compact) for linenr, line in enumerate(file.newLines(True)): linenr = linenr + 1 highlight_class = "" if first is not None: if not (first_with_context <= linenr <= last_with_context): continue if linenr == first: highlight_class += " first-selected" if linenr == last: highlight_class += " last-selected" if tabify: line = htmlutils.tabify(line, tabwidth, indenttabsmode) line = line.replace("\r", "<i class='cr'></i>") row = tbody.tr("line context single", id="f%do%dn%d" % (file.id, linenr, linenr)) row.td("edge").text() row.td("linenr old").text(linenr) row.td("line single whole%s" % highlight_class, id="f%dn%d" % (file.id, linenr), colspan=4).innerHTML(line) row.td("linenr new").text(linenr) row.td("edge").text() if linenr % 500: yield document.render(stop=tbody, pretty=not compact) table.tbody('spacer bottom').tr('spacer bottom').td(colspan=8).text() yield document.render(pretty=not compact)