160 lines
5.6 KiB
Python
160 lines
5.6 KiB
Python
import types
|
|
|
|
from core.builtin_concepts import BuiltinConcepts
|
|
from core.concept import Concept
|
|
from core.global_symbols import NotInit
|
|
from printer.FormatInstructions import FormatInstructions, FormatDetailType
|
|
from printer.Formatter import Formatter
|
|
|
|
COLORS = {
|
|
"reset": "\u001b[0m",
|
|
"black": "\u001b[30m",
|
|
"red": "\u001b[31m",
|
|
"green": "\u001b[32m",
|
|
"yellow": "\u001b[33m",
|
|
"blue": "\u001b[34m",
|
|
"magenta": "\u001b[35m",
|
|
"cyan": "\u001b[36m",
|
|
"white": "\u001b[37m",
|
|
}
|
|
EXECUTION_CONTEXT_CLASS = "core.sheerka.ExecutionContext.ExecutionContext"
|
|
|
|
|
|
class SheerkaPrinter:
|
|
"""
|
|
Class use to format the output
|
|
"""
|
|
|
|
out = print
|
|
|
|
def __init__(self, sheerka):
|
|
self.sheerka = sheerka
|
|
self.formatter = Formatter()
|
|
self.custom_concepts_printers = {}
|
|
self.reset()
|
|
|
|
def reset(self):
|
|
self.custom_concepts_printers = {
|
|
str(BuiltinConcepts.EXPLANATION): self.print_explanation,
|
|
str(BuiltinConcepts.RETURN_VALUE): self.print_return_value,
|
|
str(BuiltinConcepts.TO_LIST): self.print_to_list,
|
|
}
|
|
self.formatter.reset_formats()
|
|
self.formatter.register_format_l(EXECUTION_CONTEXT_CLASS, "[{id:3}] %tab%{desc} ({status})")
|
|
self.formatter.register_format_l(SyntaxError,
|
|
'%red%{self.__class__.__name__}: {msg}\\n{text}\\n{"^": >{offset}}%reset%')
|
|
self.formatter.register_format_l(Exception, "%red%{self}%reset%")
|
|
|
|
def register_custom_printer(self, concept, custom_format):
|
|
key = concept.key if isinstance(concept, Concept) else concept
|
|
self.custom_concepts_printers[str(key)] = custom_format
|
|
return self
|
|
|
|
def register_format_l(self, obj, template):
|
|
self.formatter.register_format_l(obj, template)
|
|
|
|
def register_format_d(self, obj, properties=None, format_type=FormatDetailType.Props_In_Line):
|
|
self.formatter.register_format_d(obj, properties, format_type)
|
|
|
|
def print(self, to_print, instructions=None):
|
|
"""
|
|
Print using SheerkaPrinter.out
|
|
:param to_print:
|
|
:param instructions: FormatInstructions
|
|
:return:
|
|
"""
|
|
instructions = instructions or FormatInstructions()
|
|
try:
|
|
self.fp(instructions, to_print)
|
|
except Exception as ex:
|
|
self.fp(instructions, ex)
|
|
return
|
|
|
|
def fp(self, instructions, item):
|
|
"""
|
|
fp stands for format and print
|
|
:param instructions:
|
|
:param item:
|
|
:return:
|
|
"""
|
|
|
|
# first, get the merged instructions
|
|
instructions = self.merge_instructions(instructions, item)
|
|
|
|
# We can only print string
|
|
if isinstance(item, str):
|
|
for color in COLORS:
|
|
item = item.replace("%" + color + "%", "" if instructions.no_color else COLORS[color])
|
|
if "%tab%" in item:
|
|
self.out(item.replace("%tab%", instructions.tab))
|
|
else:
|
|
self.out(instructions.tab + item)
|
|
return
|
|
|
|
# if list or generator, print one by one
|
|
elif hasattr(item, "__iter__"):
|
|
for i in item:
|
|
self.fp(instructions, i)
|
|
return
|
|
|
|
# Custom print required
|
|
elif isinstance(item, Concept) and item.key in self.custom_concepts_printers:
|
|
self.custom_concepts_printers[item.key](self, instructions, item)
|
|
|
|
# get the format per line and print
|
|
else:
|
|
self.fp(instructions, self.formatter.format_l(item, instructions.format_l))
|
|
|
|
# print details
|
|
format_d = self.formatter.format_d(item, instructions.format_d)
|
|
if format_d:
|
|
self.fp(instructions, format_d)
|
|
|
|
if instructions.recursive_props:
|
|
for k, v in instructions.recursive_props.items():
|
|
if hasattr(item, k) and v > 0 and (value := getattr(item, k)) != NotInit:
|
|
self.fp(instructions.recurse(k), value)
|
|
|
|
@staticmethod
|
|
def merge_instructions(instructions, obj):
|
|
"""
|
|
Merge the format instruction coming from the context with the one from obj
|
|
Note that if obj is not a Concept, there is not instruction to merge
|
|
:param instructions:
|
|
:param obj:
|
|
:return:
|
|
"""
|
|
if not hasattr(obj, "get_format_instructions"):
|
|
return instructions
|
|
|
|
obj_instructions = obj.get_format_instructions()
|
|
if obj_instructions is None:
|
|
return instructions
|
|
|
|
return instructions.clone().merge(obj_instructions)
|
|
|
|
@staticmethod
|
|
def print_explanation(printer, instructions, item):
|
|
explanation_instructions = instructions.clone().merge(item.instructions)
|
|
printer.fp(explanation_instructions, f"%blue%{item.digest}%reset% : {item.command}")
|
|
printer.fp(explanation_instructions, item.body)
|
|
|
|
@staticmethod
|
|
def print_to_list(printer, instructions, item):
|
|
explanation_instructions = instructions.clone().merge(item.get_format_instructions())
|
|
printer.fp(explanation_instructions, item.body)
|
|
|
|
@staticmethod
|
|
def print_return_value(printer, instructions, item):
|
|
if printer.sheerka.isinstance(item.body, BuiltinConcepts.EXPLANATION):
|
|
return printer.fp(instructions, item.body)
|
|
|
|
if printer.sheerka.isinstance(item.body, BuiltinConcepts.TO_LIST):
|
|
return printer.fp(instructions, item.body)
|
|
|
|
if isinstance(item.body, (list, tuple, types.GeneratorType)):
|
|
return printer.fp(instructions, item.body)
|
|
|
|
status = item.status
|
|
return printer.fp(instructions, str(item) if status else f"%red%{item}%reset%")
|