def context(token, position=None, length=None, margin=(None, None)):
    """
    Get the context of a token or a specific position in its input.

    Arguments:
        token:
            The token to show context for.
        position:
            A custom position that marks the beginning of the target text.
            Defaults to the starting position of the token.
        length:
            Length of the target text.  Defaults to the length of the token 
            value if the position of `left' is not specified; and 1 otherwise.
        margin:
            Left/right margins from the target text's left/right boundary.
            Defaults to (None, None), which would extend the margin to the 
            entire line of input.

    Returns:
        A string formated with the context of the target text and an 
        additional line under it to highlight the target text.

    Example:

        A quick brown foox jumps over a lazy dog.
        --------------^^^^-----------------------

        A quick brown fo
        --------------^^
        ox jumps over a lazy dog.
        ^^-----------------------
    """
    length = length or (1 if position else len(token.value))
    position = position or token.lexpos
    start = token.lexer.lexdata.rfind('\n', 0, position) + 1  # closest newline character to the left of the token of interest
    if margin[0] is not None:
        start = max(start, position - margin[0])
    end = token.lexer.lexdata.find('\n', position + length)  # closest newline character to the right of the token of interest
    if margin[1] is not None:
        if end == -1:
            end = min(len(token.lexer.lexdata), position + length + margin[1])
        else:
            end = min(end, position + length + margin[1])
    else:
        if end == -1:
            end = len(token.lexer.lexdata)
    context = token.lexer.lexdata[start : end]
    underline = '-' * (position - start) + '^' * length + '-' * (end - position - length)
    for i,c in enumerate(context):
        if c == '\n':
            underline[i] = c
    return '\n' + '\n'.join([
            '\n'.join(l) for l in
            zip(context.split('\n'), underline.split('\n'))]) + '\n'