On the 'issue-495-dev' branch, make what I think are some pretty
useful improvements to the syntax coloration and annotation codepaths. First, settle on the file contents as fetched via repos.openfile() as the canonical source of such. But also, allow any exceptions thrown while colorizing those file contents to trigger a second attempt without colorization enabled. This should allow for non-error-ful display of binary files which lack both an extension and VC content type hint (those are treated by default as text files). * lib/viewvc.py (markup_stream): Add docstring. Replace 'fp' parameter with 'file_lines' parameter. Add 'colorize' parameter. No longer try to munge 'blame_data' -- expect that callers have done that. Lose first_line tracking stuff, as fetching the first line of the file is no longer destructive. Always use 'file_lines' as the source of file contents; never the text attached to the 'blame-data'. (markup_or_annotate): Rework this to do more of the cheap work of annotating and markup up so that markup_stream() can be called more than once if necessary -- once to attempt colorization, and again without that feature if the first pass fails. git-svn-id: http://viewvc.tigris.org/svn/viewvc/branches/issue-495-dev@2698 8cb11bc2-c004-0410-86c3-e597b4017df7remotes/issue-495-dev
parent
094024a0ec
commit
a03cd82de5
142
lib/viewvc.py
142
lib/viewvc.py
|
@ -1564,32 +1564,29 @@ def markup_escaped_urls(s):
|
|||
return "<a href=\"%s\">%s</a>" % (unescaped_url, url)
|
||||
return re.sub(_re_rewrite_escaped_url, _url_repl, s)
|
||||
|
||||
def markup_stream(request, cfg, blame_data, fp, filename,
|
||||
mime_type, encoding):
|
||||
# Add diff_href items to each "line" in the blame_data (if provided).
|
||||
blame_source = []
|
||||
if blame_data:
|
||||
for i in blame_data:
|
||||
i.text = sapi.escape(i.text)
|
||||
i.diff_href = None
|
||||
if i.prev_rev:
|
||||
i.diff_href = request.get_url(view_func=view_diff,
|
||||
params={'r1': i.prev_rev,
|
||||
'r2': i.rev},
|
||||
escape=1, partial=1)
|
||||
blame_source.append(i)
|
||||
blame_data = blame_source
|
||||
|
||||
def markup_stream(request, cfg, blame_data, file_lines, filename,
|
||||
mime_type, encoding, colorize):
|
||||
"""Return the contents of a versioned file as a list of
|
||||
vclib.Annotation objects, each representing one line of the file's
|
||||
contents. Use BLAME_DATA as the annotation information for the file
|
||||
if provided. Use FILE_LINES as the lines of file content text
|
||||
themselves. MIME_TYPE is the MIME content type of the file;
|
||||
ENCODING is its character encoding. If COLORIZE is true, attempt to
|
||||
apply syntax coloration to the file contents, and use the
|
||||
HTML-marked-up results as the text in the return vclib.Annotation
|
||||
objects."""
|
||||
|
||||
# Nothing to mark up? So be it.
|
||||
if not file_lines:
|
||||
return []
|
||||
|
||||
# Determine if we should use Pygments to highlight our output.
|
||||
# Reasons not to include a) being told not to by the configuration,
|
||||
# b) not being able to import the Pygments modules, and c) Pygments
|
||||
# not having a lexer for our file's format.
|
||||
#
|
||||
# We might have to eat a line of text from our file pointer in order
|
||||
# make this happen.
|
||||
first_line = None
|
||||
pygments_lexer = None
|
||||
if cfg.options.enable_syntax_coloration and highlight:
|
||||
if colorize:
|
||||
if not encoding:
|
||||
encoding = 'guess'
|
||||
if cfg.options.detect_encoding:
|
||||
|
@ -1621,46 +1618,28 @@ def markup_stream(request, cfg, blame_data, fp, filename,
|
|||
|
||||
# Still no lexer? If we've reason to believe this is a text
|
||||
# file, try to guess the lexer based on the file's content.
|
||||
if not pygments_lexer and is_text(mime_type):
|
||||
if not pygments_lexer and is_text(mime_type) and file_lines:
|
||||
try:
|
||||
first_line = fp.readline()
|
||||
pygments_lexer = guess_lexer(first_line)
|
||||
pygments_lexer = guess_lexer(file_lines[0])
|
||||
except ClassNotFound:
|
||||
pygments_lexer = None
|
||||
|
||||
# If we aren't going to be highlighting anything, just return the
|
||||
# BLAME_SOURCE. If there's no blame_source, we'll generate a fake
|
||||
# one from the file contents we fetch with PATH and REV.
|
||||
# If we aren't highlighting, just return an amalgamation of the
|
||||
# BLAME_DATA (if any) and the FILE_LINES.
|
||||
if not pygments_lexer:
|
||||
if blame_source:
|
||||
class BlameSourceTabsizeWrapper:
|
||||
def __init__(self, blame_source, tabsize):
|
||||
self.blame_source = blame_source
|
||||
self.tabsize = cfg.options.tabsize
|
||||
def __getitem__(self, idx):
|
||||
item = self.blame_source.__getitem__(idx)
|
||||
item.text = item.text.expandtabs(self.tabsize)
|
||||
item.text = markup_escaped_urls(item.text)
|
||||
return item
|
||||
return BlameSourceTabsizeWrapper(blame_source, cfg.options.tabsize)
|
||||
else:
|
||||
lines = []
|
||||
line_no = 0
|
||||
while 1:
|
||||
if first_line is not None:
|
||||
line = first_line
|
||||
first_line = None
|
||||
else:
|
||||
line = fp.readline()
|
||||
if not line:
|
||||
break
|
||||
line_no = line_no + 1
|
||||
line = sapi.escape(line.expandtabs(cfg.options.tabsize))
|
||||
line = markup_escaped_urls(line)
|
||||
item = vclib.Annotation(line, line_no, None, None, None, None)
|
||||
item.diff_href = None
|
||||
lines.append(item)
|
||||
return lines
|
||||
lines = []
|
||||
for i in range(len(file_lines)):
|
||||
line = file_lines[i]
|
||||
line = sapi.escape(line.expandtabs(cfg.options.tabsize))
|
||||
line = markup_escaped_urls(line)
|
||||
if blame_data:
|
||||
blame_item = blame_data[i]
|
||||
blame_item.text = line
|
||||
else:
|
||||
blame_item = vclib.Annotation(line, i + 1, None, None, None, None)
|
||||
blame_item.diff_href = None
|
||||
lines.append(blame_item)
|
||||
return lines
|
||||
|
||||
# If we get here, we're highlighting something.
|
||||
class PygmentsSink:
|
||||
|
@ -1683,8 +1662,9 @@ def markup_stream(request, cfg, blame_data, fp, filename,
|
|||
item.diff_href = None
|
||||
self.blame_data.append(item)
|
||||
self.line_no = self.line_no + 1
|
||||
ps = PygmentsSink(blame_source)
|
||||
highlight((first_line or '') + fp.read(), pygments_lexer,
|
||||
|
||||
ps = PygmentsSink(blame_data)
|
||||
highlight(''.join(file_lines), pygments_lexer,
|
||||
HtmlFormatter(nowrap=True,
|
||||
classprefix="pygments-",
|
||||
encoding='utf-8'), ps)
|
||||
|
@ -1790,27 +1770,63 @@ def markup_or_annotate(request, is_annotate):
|
|||
|
||||
# Not a viewable image.
|
||||
else:
|
||||
blame_source = None
|
||||
blame_data = None
|
||||
|
||||
# If this was an annotation request, try to annotate this file.
|
||||
# If something goes wrong, that's okay -- we'll gracefully revert
|
||||
# to a plain markup display.
|
||||
if is_annotate:
|
||||
# Try to annotate this file, but don't croak if we fail.
|
||||
try:
|
||||
blame_source, revision = request.repos.annotate(path, rev)
|
||||
annotation = 'annotated'
|
||||
blame_source, revision = request.repos.annotate(path, rev, False)
|
||||
if check_freshness(request, None, revision, weak=1):
|
||||
return
|
||||
# Create BLAME_DATA list from BLAME_SOURCE, adding diff_href
|
||||
# items to each relevant "line".
|
||||
blame_data = []
|
||||
for item in blame_source:
|
||||
item.diff_href = None
|
||||
if item.prev_rev:
|
||||
item.diff_href = request.get_url(view_func=view_diff,
|
||||
params={'r1': item.prev_rev,
|
||||
'r2': item.rev},
|
||||
escape=1, partial=1)
|
||||
blame_data.append(item)
|
||||
annotation = 'annotated'
|
||||
except vclib.NonTextualFileContents:
|
||||
annotation = 'binary'
|
||||
except:
|
||||
annotation = 'error'
|
||||
|
||||
# Grab the file contents.
|
||||
fp, revision = request.repos.openfile(path, rev, {'cvs_oldkeywords' : 1})
|
||||
if check_freshness(request, None, revision, weak=1):
|
||||
fp.close()
|
||||
return
|
||||
lines = markup_stream(request, cfg, blame_source, fp,
|
||||
path[-1], mime_type, encoding)
|
||||
file_lines = fp.readlines()
|
||||
fp.close()
|
||||
|
||||
# Do we have a differing number of file content lines and
|
||||
# annotation items? That's no good. Call it an error and don't
|
||||
# bother attempting the annotation display.
|
||||
if blame_data and (len(file_lines) != len(blame_data)):
|
||||
annotation = 'error'
|
||||
blame_data = None
|
||||
|
||||
# Try to markup the file contents/annotation. If we get an error
|
||||
# and we were colorizing the stream, try once more without the
|
||||
# colorization enabled.
|
||||
colorize = cfg.options.enable_syntax_coloration and highlight
|
||||
try:
|
||||
lines = markup_stream(request, cfg, blame_data, file_lines,
|
||||
path[-1], mime_type, encoding, colorize)
|
||||
except:
|
||||
if colorize:
|
||||
lines = markup_stream(request, cfg, blame_data, file_lines,
|
||||
path[-1], mime_type, encoding, False)
|
||||
else:
|
||||
raise debug.ViewVCException('Error displaying file contents',
|
||||
'500 Internal Server Error')
|
||||
|
||||
data = common_template_data(request, revision, mime_type)
|
||||
data.merge(ezt.TemplateData({
|
||||
'mime_type' : mime_type,
|
||||
|
|
Loading…
Reference in New Issue