blob: 3122c0ecd92f94c6ece026faac6c806be399c77f [file] [edit]
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright 2017, Data61, CSIRO (ABN 41 687 119 230)
#
# SPDX-License-Identifier: BSD-2-Clause
#
#
from __future__ import absolute_import, division, print_function, \
unicode_literals
from camkes.internal.seven import cmp, filter, map, zip
from camkes.internal.terminal import BOLD, RED, RESET, terminal_supports_colour
def _get_line(filename, lineno):
'''
Retrieve a given line from a file.
'''
try:
with open(filename, 'rt') as f:
for no, line in enumerate(f, 1):
if no == lineno:
return line
except IOError:
# File did not exist.
pass
return None
class CAmkESError(Exception):
def __init__(self, lines):
super(CAmkESError, self).__init__(*lines)
'''
Generic basis for CAmkES errors.
'''
@staticmethod
def _format_message(message, filename=None, lineno=None, min_col=None,
max_col=None):
msg = []
line = None
if filename is not None:
msg.extend([filename, ':'])
if lineno is not None:
# It is not particularly efficient to read a file that we have
# already read, but we assume as we're on an error handling
# path here that we don't care about efficiency.
line = _get_line(filename, lineno)
if lineno is not None:
msg.extend([str(lineno), ':'])
if min_col is not None:
msg.extend([str(min_col), ':'])
if len(msg) > 0:
msg.append(' ')
indent = sum(len(x) for x in msg)
# If we retrieved the actual source line, try pretty printing it in the
# error message.
if line is not None:
if min_col is not None and max_col is not None:
msg.append(line[:min_col-1])
if terminal_supports_colour():
msg.extend([RED, BOLD])
msg.append(line[min_col-1:max_col])
if terminal_supports_colour():
msg.append(RESET)
msg.append(line[max_col:])
else:
msg.append(line)
if min_col is not None:
msg.extend([' ' * (indent + min_col - 1), '^'])
if max_col is not None:
msg.append('^' * (max_col - min_col))
msg.append('\n')
msg.append(message)
return ''.join(msg).split('\n')