Parse a single line from a theme file.

        Format:
            <element>: <foreground> <background> <attributes>

def _parse_line(cls, element, line, filename=None):
        """
        Parse a single line from a theme file.

        Format:
            <element>: <foreground> <background> <attributes>
        """

        items = line.split()
        if len(items) == 2:
            fg, bg, attrs = items[0], items[1], ''
        elif len(items) == 3:
            fg, bg, attrs = items
        else:
            raise ConfigError(
                'Error loading {0}, invalid line:\n'
                '    {1} = {2}'.format(filename, element, line))

        if fg.startswith('#'):
            fg = cls.rgb_to_ansi(fg)
        if bg.startswith('#'):
            bg = cls.rgb_to_ansi(bg)

        if fg not in cls.COLOR_CODES:
            raise ConfigError(
                'Error loading {0}, invalid <foreground>:\n'
                '    {1} = {2}'.format(filename, element, line))
        fg_code = cls.COLOR_CODES[fg]

        if bg not in cls.COLOR_CODES:
            raise ConfigError(
                'Error loading {0}, invalid <background>:\n'
                '    {1} = {2}'.format(filename, element, line))
        bg_code = cls.COLOR_CODES[bg]

        attrs_code = curses.A_NORMAL
        for attr in attrs.split('+'):
            if attr not in cls.ATTRIBUTE_CODES:
                raise ConfigError(
                    'Error loading {0}, invalid <attributes>:\n'
                    '    {1} = {2}'.format(filename, element, line))
            attr_code = cls.ATTRIBUTE_CODES[attr]
            if attr_code is None:
                attrs_code = None
                break
            else:
                attrs_code |= attr_code

        return fg_code, bg_code, attrs_code