# Copyright (c) 2013 - present Facebook, Inc. # All rights reserved. # # This source code is licensed under the BSD style license found in the # LICENSE file in the root directory of this source tree. An additional grant # of patent rights can be found in the PATENTS file in the same directory. from __future__ import absolute_import from __future__ import division from __future__ import print_function from __future__ import unicode_literals import codecs try: import pygments import pygments.formatters import pygments.lexers except ImportError: pygments = None import sys from . import config, utils BASE_INDENT = 2 # how many lines of context around each report SOURCE_CONTEXT = 2 # syntax highlighting modes PLAIN_FORMATTER = 0 TERMINAL_FORMATTER = 1 class Indenter(str): def __init__(self): super(Indenter, self).__init__() self.text = '' self.indent = [] def indent_get(self): indent = '' for i in self.indent: indent += i return indent def indent_push(self, n=1): self.indent.append(n * BASE_INDENT * ' ') return self def indent_pop(self): return self.indent.pop() return self def newline(self): self.text += '\n' return self def add(self, x): if type(x) != unicode: x = x.decode(config.LOCALE) lines = x.splitlines() indent = self.indent_get() lines = [indent + l for l in lines] self.text += '\n'.join(lines) return self def __unicode__(self): return self.text def __str__(self): return unicode(self).encode(config.LOCALE) def build_source_context(source_name, mode, report_line): start_line = max(1, report_line - SOURCE_CONTEXT) # could go beyond last line, checked in the loop end_line = report_line + SOURCE_CONTEXT n_length = len(str(end_line)) line_number = 1 s = '' with codecs.open(source_name, 'r', encoding=config.LOCALE, errors="replace") as source_file: for line in source_file: if start_line <= line_number <= end_line: num = str(line_number).zfill(n_length) caret = ' ' if line_number == report_line: caret = '> ' s += '%s. %s%s' % (num, caret, line) line_number += 1 return _syntax_highlighting(source_name, mode, s) def _syntax_highlighting(source_name, mode, s): if pygments is None or mode == PLAIN_FORMATTER: return s lexer = pygments.lexers.get_lexer_for_filename(source_name) formatter = None if mode == TERMINAL_FORMATTER: if not sys.stdout.isatty(): return s formatter = pygments.formatters.TerminalFormatter() return pygments.highlight(s, lexer, formatter)