col_stack = []

def format(text: str, fmt: str) -> str:
    last_col = "\u001b[0m" if len(col_stack) == 0 else col_stack[:-1]
    
    col_stack.append(f"\u001b[{fmt}m")

    value = f"\u001b[{fmt}m{text}{last_col}"
    col_stack.pop()

    return value 


def head(text: str) -> str:
    return format(text, "31;1;4")

def f(text: str) -> str:
    return format(text, "32;1")

def infix_notation(query):
    return f"""
{head("Präfix-Notation")}
    Operatoren werden zwischen die Operanden gesetzt

    (A + B)
    (A v B)
"""


def praefix_notation(query):
    return f"""
{head("Präfix-Notation")}
    Operatoren werden vor die Operanden gesetzt

    + A B 
    v A B 
"""


def aussage(query):
    return f"""
{head("Aussagenlogik")}

- Prinzip der Zweiwertigkeit: Jede Aussage ist wahr oder falsch
- Prinzip vom ausgeschlossenen Widerspruch: Es gibt keine Aussage, die sowohl wahr als auch falsch ist.

→ Jede Aussage ist entweder wahr oder falsch.
"""


def signatur(q):
    return f"""
{head("Signatur (Aussagenlogik)")}
abzählbare Menge von Aussagensymbolen

AS = {{ P0, ..., Pn }}
"""

def negation(q):
    return f"""
{head("Negation (Junktor)")}
Beispiel:   ¬A
Gesprochen: „nicht A“

 A | ¬A 
--------
 W |  F
 F |  W

"""

def implikation(q):
    return f"""
{head("Implikation (Junktor)")}
Beispiel:  A → B
Gesprochen: „wenn A dann B“

Äquivalent zu (¬A ∨ B)

 A | B | A → B
--------------
 W | W |   W
 W | F |   F
 F | W |   W
 F | F |   W

"""

def disjunktion(q):
    return f"""
{head("Disjunktion (Junktor)")}
Beispiel:  A ∨ B
Gesprochen: „A oder B“

 A | B | A ∧ B
--------------
 W | W |   W
 W | F |   W
 F | W |   W
 F | F |   F

"""

def konjunktion(q):
    return f"""
{head("Konjunktion (Junktor)")}
Beispiel:  A ∧ B
Gesprochen: „A und B“

 A | B | A ∧ B
--------------
 W | W |   W
 W | F |   F
 F | W |   F
 F | F |   F

"""


def formel(q):
    return f"""
{head("Formel (Aussagenlogik)")}
Formeln werden durch Kombination von Aussagensymbolen und Junktoren gebildet.
Die Menge aller aussagenlogischen Formeln über AS ist induktiv wie folgt definiert:

  * 1. für jedes P ∈ AS ist P eine Formel
  * wenn 𝜑 und ψ Formeln sind, dann sind auch
        2. ¬𝜑
        3. (𝜑 ∧ ψ)
        4. (𝜑 ∨ ψ)
        5. (𝜑 → ψ)
        6. (𝜑 ↔ ψ)
    Formeln.

Wir verwenden griechische Buchstaben (𝜑, ψ, ...) zur
Benennung von Formeln.
"""

def aussagensymbol(q):
    return f"""
{head("Aussagensymbol (Aussagenlogik)")}
Atomare Formeln, die einen Wahrheitswert darstellen
    AS = {f("{ A, B }")}
    𝜑  =  A  ∧  B 
    .-----^-----^          
    '- Aussagensymbol
"""

keywords = [
    (["infix", "Infixnotation", "Algebraische Notation"], infix_notation),
    (["prefix", "präfix", "präfixnotation"], praefix_notation),
    (["aussage"], aussage),

    (["signatur"], signatur),

    (["negation"], negation),
    (["implikation"], implikation),
    (["konjunktion"], konjunktion),
    (["disjunktion"], disjunktion),
    (["aussagensymbol"], aussagensymbol)
]