""" ANSI frontend. Exports: visualize(answer_data, request_options) Format: answer_data = { 'answers': '...',} answers = [answer,...] answer = { 'topic': '...', 'topic_type': '...', 'answer': '...', 'format': 'ansi|code|markdown|text...', } Configuration parameters: frontend.styles """ import os import sys import re import colored from pygments import highlight as pygments_highlight from pygments.formatters import ( Terminal256Formatter, ) # pylint: disable=no-name-in-module # pylint: disable=wrong-import-position sys.path.append(os.path.abspath(os.path.join(__file__, ".."))) from config import CONFIG import languages_data # pylint: enable=wrong-import-position import fmt.internal import fmt.comments def visualize(answer_data, request_options): """ Renders `answer_data` as ANSI output. """ answers = answer_data["answers"] return _visualize( answers, request_options, search_mode=bool(answer_data["keyword"]) ) 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 _limited_answer(answer): return ( colored.bg("dark_goldenrod") + colored.fg("yellow_1") + " " + answer + " " + colored.attr("reset") + "\n" ) def _colorize_ansi_answer( topic, answer, color_style, # pylint: disable=too-many-arguments highlight_all=True, highlight_code=False, unindent_code=False, language=None, ): color_style = color_style or "native" lexer_class = languages_data.LEXER["bash"] if "/" in topic: if language is None: section_name = topic.split("/", 1)[0].lower() else: section_name = language section_name = languages_data.get_lexer_name(section_name) lexer_class = languages_data.LEXER.get(section_name, lexer_class) if section_name == "php": answer = "\n" % answer if highlight_all: highlight = ( lambda answer: pygments_highlight( answer, lexer_class(), Terminal256Formatter(style=color_style) ).strip("\n") + "\n" ) else: highlight = lambda x: x if highlight_code: blocks = fmt.comments.code_blocks( answer, wrap_lines=True, unindent_code=(4 if unindent_code else False) ) highlighted_blocks = [] for block in blocks: if block[0] == 1: this_block = highlight(block[1]) else: this_block = block[1].strip("\n") + "\n" highlighted_blocks.append(this_block) result = "\n".join(highlighted_blocks) else: result = highlight(answer).lstrip("\n") return result def _visualize(answers, request_options, search_mode=False): highlight = not bool(request_options and request_options.get("no-terminal")) color_style = (request_options or {}).get("style", "") if color_style not in CONFIG["frontend.styles"]: color_style = "" # if there is more than one answer, # show the source of the answer multiple_answers = len(answers) > 1 found = True result = "" for answer_dict in answers: topic = answer_dict["topic"] topic_type = answer_dict["topic_type"] answer = answer_dict["answer"] found = found and not topic_type == "unknown" if multiple_answers and topic != "LIMITED": section_name = f"{topic_type}:{topic}" if not highlight: result += f"#[{section_name}]\n" else: result += "".join( [ "\n", colored.bg("dark_gray"), colored.attr("res_underlined"), f" {section_name} ", colored.attr("res_underlined"), colored.attr("reset"), "\n", ] ) if answer_dict["format"] in ["ansi", "text"]: result += answer elif topic == ":firstpage-v1": result += fmt.internal.colorize_internal_firstpage_v1(answer) elif topic == "LIMITED": result += _limited_answer(topic) else: result += _colorize_ansi_answer( topic, answer, color_style, highlight_all=highlight, highlight_code=( topic_type == "question" and not request_options.get("add_comments") and not request_options.get("remove_text") ), language=answer_dict.get("filetype"), ) if request_options.get("no-terminal"): result = remove_ansi(result) result = result.strip("\n") + "\n" return result, found