""" Main cheat.sh wrapper. Get answers from getters (in get_answer), adds syntax highlighting or html markup and returns the result. """ from gevent.monkey import patch_all from gevent.subprocess import Popen, PIPE patch_all() # pylint: disable=wrong-import-position,wrong-import-order import sys import os import re import colored from pygments import highlight as pygments_highlight from pygments.formatters import Terminal256Formatter # pylint: disable=no-name-in-module MYDIR = os.path.abspath(os.path.dirname(os.path.dirname('__file__'))) sys.path.append("%s/lib/" % MYDIR) from globals import error, ANSI2HTML, COLOR_STYLES from buttons import TWITTER_BUTTON, GITHUB_BUTTON, GITHUB_BUTTON_FOOTER from languages_data import LEXER from get_answer import get_topic_type, get_topics_list, get_answer, find_answer_by_keyword # import beautifier # pylint: disable=wrong-import-position,wrong-import-order ANSI_ESCAPE = re.compile(r'(\x9B|\x1B\[)[0-?]*[ -\/]*[@-~]') def remove_ansi(sometext): """ Remove ANSI sequences from `sometext` and convert it into plaintext. """ return ANSI_ESCAPE.sub('', sometext) def html_wrapper(data): """ Convert ANSI text `data` to HTML """ proc = Popen( ["bash", ANSI2HTML, "--palette=solarized", "--bg=dark"], stdin=PIPE, stdout=PIPE, stderr=PIPE) data = data.encode('utf-8') stdout, stderr = proc.communicate(data) if proc.returncode != 0: error(stdout + stderr) return stdout.decode('utf-8') def _colorize_internal(topic, answer, html_needed): def _colorize_line(line): if line.startswith('T'): line = colored.fg("grey_62") + line + colored.attr('reset') line = re.sub(r"\{(.*?)\}", colored.fg("orange_3") + r"\1"+colored.fg('grey_35'), line) return line line = re.sub(r"\[(F.*?)\]", colored.bg("black") + colored.fg("cyan") + r"[\1]"+colored.attr('reset'), line) line = re.sub(r"\[(g.*?)\]", colored.bg("dark_gray") \ + colored.fg("grey_0") \ + r"[\1]"+colored.attr('reset'), line) line = re.sub(r"\{(.*?)\}", colored.fg("orange_3") + r"\1"+colored.attr('reset'), line) line = re.sub(r"<(.*?)>", colored.fg("cyan") + r"\1"+colored.attr('reset'), line) return line if topic in [':list', ':bash_completion']: return answer if topic == ':firstpage': lines = answer.splitlines() answer_lines = lines[:9] answer_lines.append(colored.fg('grey_35')+lines[9]+colored.attr('reset')) for line in lines[10:]: answer_lines.append(_colorize_line(line)) if html_needed: answer_lines = answer_lines[:-2] answer = "\n".join(answer_lines) + "\n" return answer def _colorize_ansi_answer(topic, answer, color_style): color_style = color_style or "native" lexer = LEXER['bash'] for lexer_name, lexer_value in LEXER.items(): if topic.startswith("%s/" % lexer_name): color_style = color_style or "monokai" if lexer_name == 'php': answer = "\n" % answer lexer = lexer_value break formatter = Terminal256Formatter(style=color_style) return pygments_highlight(answer, lexer(), formatter).lstrip('\n') def _github_button(topic_type): repository = { "cheat.sheets" : 'chubin/cheat.sheets', "cheat.sheets dir" : 'chubin/cheat.sheets', "tldr" : 'tldr-pages/tldr', "cheat" : 'chrisallenlane/cheat', "learnxiny" : 'adambard/learnxinyminutes-docs', "internal" : '', "search" : '', "unknown" : '', } full_name = repository.get(topic_type, '') if not full_name: return '' short_name = full_name.split('/', 1)[1] # pylint: disable=unused-variable button = ( "" '%(short_name)s' ) % locals() return button def _render_html(query, result, editable, repository_button, request_options): result = result + "\n$" result = html_wrapper(result) title = "cheat.sh/%s" % query # title += ('\nscript' # ' src="/files/awesomplete.min.js" async>') # submit button: thanks to http://stackoverflow.com/questions/477691/ submit_button = ('') topic_list = ('%s' % ("\n".join("" % x for x in get_topics_list()))) curl_line = "$ curl cheat.sh/" if query == ':firstpage': query = "" form_html = ('
' '%s%s' '' '%s' '') \ % (submit_button, curl_line, query, topic_list) edit_button = '' if editable: # It's possible that topic directory starts with omited underscore if '/' in query: query = '_' + query edit_page_link = 'https://github.com/chubin/cheat.sheets/edit/master/sheets/' + query edit_button = ( '
'
            '[edit]'
            '
') % edit_page_link result = re.sub("
", edit_button + form_html + "
", result)
    result = re.sub("", "" + title, result)
    if not request_options.get('quiet'):
        result = result.replace('',
                                TWITTER_BUTTON \
                                + GITHUB_BUTTON \
                                + repository_button \
                                + GITHUB_BUTTON_FOOTER \
                                + '')
    return result

def _visualize(query, keyword, answers, request_options, html=None):

    search_mode = bool(keyword)

    highlight = not bool(request_options and request_options.get('no-terminal'))
    color_style = request_options.get('style', '')
    if color_style not in COLOR_STYLES:
        color_style = ''

    found = True            # if the page was found in the database
    editable = False        # can generated page be edited on github (only cheat.sheets pages can)
    result = ""
    for topic, answer in answers:   # pylint: disable=too-many-nested-blocks

        if topic == 'LIMITED':
            result += colored.bg('dark_goldenrod') \
                    + colored.fg('yellow_1') \
                    + ' ' +  answer + ' ' \
                    + colored.attr('reset') + "\n"
            break

        if topic in [":list", ":bash_completion"]:
            highlight = False

        topic_type = get_topic_type(topic)
        if topic_type == 'unknown':
            found = False

        if topic_type == "cheat.sheets":
            editable = True

        if not highlight:
            if search_mode:
                result += "\n[%s]\n" % topic
        else:

            if topic_type == "internal":
                answer = _colorize_internal(topic, answer, html)
            else:
                answer = _colorize_ansi_answer(topic, answer, color_style)

            if search_mode:
                result += "\n%s%s %s %s%s\n" % (colored.bg('dark_gray'),
                                                colored.attr("res_underlined"),
                                                topic,
                                                colored.attr("res_underlined"),
                                                colored.attr('reset'))
        result += answer

    if search_mode:
        result = result.lstrip('\n')
        editable = False
        repository_button = ''
    else:
        repository_button = _github_button(topic_type)

    if html:
        result = _render_html(
            query, result, editable, repository_button, request_options)


    return result, found

def cheat_wrapper(query, request_options=None, html=False):
    """
    Giant megafunction that delivers cheat sheet for `query`.
    If `html` is True, the answer is formated as HTML.
    Additional request options specified in `request_options`.

    This function is really really bad, and should be rewritten
    as soon as possible.
    """

    def _parse_query(query):
        topic = query
        keyword = None
        search_options = ""

        keyword = None
        if '~' in query:
            topic = query
            pos = topic.index('~')
            keyword = topic[pos+1:]
            topic = topic[:pos]

            if '/' in keyword:
                search_options = keyword[::-1]
                search_options = search_options[:search_options.index('/')]
                keyword = keyword[:-len(search_options)-1]

        return topic, keyword, search_options

    # at the moment, we just remove trailing slashes
    # so queries python/ and python are equal
    query = query.rstrip('/')
    topic, keyword, search_options = _parse_query(query)

    if keyword:
        answers = find_answer_by_keyword(
            topic, keyword, options=search_options, request_options=request_options)
    else:
        answers = [(topic, get_answer(topic, keyword, request_options=request_options))]

    return _visualize(query, keyword, answers, request_options, html=html)