From 0ef0e8e5853459a3a307037bc1eb07746a2c066a Mon Sep 17 00:00:00 2001 From: Mark Date: Sat, 22 Oct 2022 08:37:19 -0700 Subject: [PATCH] Cleaned up commands and styling --- README.md | 1 + lamb/__main__.py | 39 +++++++++++---------- lamb/commands.py | 87 +++++++++++++++++------------------------------ lamb/runner.py | 16 ++------- lamb/runstatus.py | 11 +++--- lamb/utils.py | 49 +++++++++++++++++--------- 6 files changed, 92 insertions(+), 111 deletions(-) diff --git a/README.md b/README.md index 3df1778..f60a6f9 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,7 @@ - Prettyprint functions (combine args, rename bound variables) - Write a nice README - Handle or avoid recursion errors + - Fix colors ## Todo: - live syntax check diff --git a/lamb/__main__.py b/lamb/__main__.py index bb03de2..c3cc3da 100755 --- a/lamb/__main__.py +++ b/lamb/__main__.py @@ -22,8 +22,9 @@ def _(event): session = PromptSession( message = FormattedText([ - ("#00FFFF", "~~> ") + ("class:prompt", "~~> ") ]), + style = utils.style, key_bindings = bindings ) @@ -74,44 +75,42 @@ while True: except ppx.ParseException as e: l = len(to_plain_text(session.message)) printf(FormattedText([ - ("#FF0000", " "*(e.loc + l) + "^\n"), - ("#FF0000", f"Syntax error at char {e.loc}."), - ("#FFFFFF", "\n") + ("class:err", " "*(e.loc + l) + "^\n"), + ("class:err", f"Syntax error at char {e.loc}."), + ("class:text", "\n") ])) continue except tokens.ReductionError as e: printf(FormattedText([ - ("#FF0000", f"{e.msg}"), - ("#FFFFFF", "\n") - ])) + ("class:err", f"{e.msg}\n") + ]), style = utils.style) continue # If this line defined a macro, print nothing. if isinstance(x, rs.MacroStatus): printf(FormattedText([ - ("#FFFFFF", "Set "), - ("#FF00FF", x.macro_label), - ("#FFFFFF", " to "), - ("#FFFFFF", str(x.macro_expr)) - ])) + ("class:text", "Set "), + ("class:syn_macro", x.macro_label), + ("class:text", " to "), + ("class:text", str(x.macro_expr)) + ]), style = utils.style) if isinstance(x, rs.CommandStatus): - printf(x.formatted_text) + printf(x.formatted_text, style = utils.style) # If this line was an expression, print reduction status elif isinstance(x, rs.ReduceStatus): printf(FormattedText([ - - ("#00FF00 bold", f"\nExit reason: "), + ("class:result_header", f"\nExit reason: "), x.stop_reason.value, - ("#00FF00 bold", f"\nReduction count: "), - ("#FFFFFF", str(x.reduction_count)), + ("class:result_header", f"\nReduction count: "), + ("class:text", str(x.reduction_count)), - ("#00FF00 bold", "\n\n => "), - ("#FFFFFF", str(x.result)), - ])) + ("class:result_header", "\n\n => "), + ("class:text", str(x.result)), + ]), style = utils.style) printf("") diff --git a/lamb/commands.py b/lamb/commands.py index 8886308..fe53aaa 100644 --- a/lamb/commands.py +++ b/lamb/commands.py @@ -17,14 +17,21 @@ def lamb_command(*, help_text: str): return inner def run(command, runner): - return commands[command.name](command, runner) + if command.name not in commands: + return CommandStatus( + formatted_text = FormattedText([ + ("class:warn", f"Unknown command \"{command.name}\"") + ]) + ) + else: + return commands[command.name](command, runner) @lamb_command(help_text = "Delete a macro") def mdel(command, runner): if len(command.args) != 1: return CommandStatus( formatted_text = HTML( - "Command :mdel takes exactly one argument." + "Command :mdel takes exactly one argument." ) ) @@ -32,7 +39,7 @@ def mdel(command, runner): if target not in runner.macro_table: return CommandStatus( formatted_text = HTML( - f"Macro \"{target}\" is not defined" + f"Macro \"{target}\" is not defined" ) ) @@ -41,11 +48,13 @@ def mdel(command, runner): @lamb_command(help_text = "Show macros") def macros(command, runner): return CommandStatus( + + # Can't use HTML here, certain characters might break it. formatted_text = FormattedText([ - ("#FF6600 bold", "\nDefined Macros:\n"), + ("class:cmd_h", "\nDefined Macros:\n"), ] + [ - ("#FFFFFF", f"\t{name} \t {exp}\n") + ("class:cmd_text", f"\t{name} \t {exp}\n") for name, exp in runner.macro_table.items() ] ) @@ -60,56 +69,22 @@ def clear(command, runner): @lamb_command(help_text = "Print this help") def help(command, runner): return CommandStatus( - formatted_text = FormattedText([ - ("#FF6600 bold", "\nUsage:\n"), - ( - "#FFFFFF", - "\tWrite lambda expressions using your " - ), - ( - "#00FF00", - "\\" - ), - ( - "#FFFFFF", - " key.\n" + - "\tMacros can be defined using " - ), - - - ("#00FF00", "="), - ( - "#FFFFFF", - ", as in " - ), - ( - "#AAAAAA bold", - "T = λab.a\n" - ), - - - ( - "#FFFFFF", - "\tRun commands using " - ), - ( - "#00FF00", - ":" - ), - ( - "#FFFFFF", - ", for example " - ), - ( - "#AAAAAA bold", - ":help" - ), - - ("#FF6600 bold", "\n\nCommands:\n") - ] + - [ - ("#FFFFFF", f"\t{name} \t {text}\n") - for name, text in help_texts.items() - ] + formatted_text = HTML( + "\n" + + "Usage:" + + "\n" + + "\tWrite lambda expressions using your \\ key." + + "\n" + + "\tMacros can be defined using =, as in T = λab.a" + + "\n" + + "\tRun commands using :, for example :help" + + "\n\n" + + "Commands:"+ + "\n" + + "\n".join([ + f"\t{name} \t {text}" + for name, text in help_texts.items() + ]) + + "" ) ) \ No newline at end of file diff --git a/lamb/runner.py b/lamb/runner.py index 58db6e4..bcc8e20 100644 --- a/lamb/runner.py +++ b/lamb/runner.py @@ -16,18 +16,6 @@ class Runner: # If None, no maximum is enforced. self.reduction_limit: int | None = 300 - def exec_command(self, command: tokens.command) -> rs.CommandStatus: - if command.name in commands.commands: - return commands.run(command, self) - - # Handle unknown commands - else: - return rs.CommandStatus( - formatted_text = FormattedText([ - ("#FFFF00", f"Unknown command \"{command}\"") - ]) - ) - def reduce_expression(self, expr: tokens.LambdaToken) -> rs.ReduceStatus: @@ -58,7 +46,7 @@ class Runner: return rs.ReduceStatus( reduction_count = i - macro_expansions, stop_reason = rs.StopReason.MAX_EXCEEDED, - result = r.output # type: ignore + result = r.output # type: ignore ) @@ -81,7 +69,7 @@ class Runner: # If this line is a command, do the command. elif isinstance(e, tokens.command): - return self.exec_command(e) + return commands.run(e, self) # If this line is a plain expression, reduce it. elif isinstance(e, tokens.LambdaToken): diff --git a/lamb/runstatus.py b/lamb/runstatus.py index 2b2b283..434703c 100644 --- a/lamb/runstatus.py +++ b/lamb/runstatus.py @@ -1,4 +1,5 @@ from prompt_toolkit.formatted_text import FormattedText +from prompt_toolkit.formatted_text import HTML import enum import lamb.tokens as tokens @@ -33,10 +34,10 @@ class MacroStatus(RunStatus): class StopReason(enum.Enum): - BETA_NORMAL = ("#FFFFFF", "β-normal form") - LOOP_DETECTED = ("#FFFF00", "loop detected") - MAX_EXCEEDED = ("#FFFF00", "too many reductions") - INTERRUPT = ("#FF0000", "user interrupt") + BETA_NORMAL = ("class:text", "β-normal form") + LOOP_DETECTED = ("class:warn", "loop detected") + MAX_EXCEEDED = ("class:err", "too many reductions") + INTERRUPT = ("class:warn", "user interrupt") class ReduceStatus(RunStatus): @@ -71,6 +72,6 @@ class CommandStatus(RunStatus): def __init__( self, *, - formatted_text: FormattedText + formatted_text: FormattedText | HTML ): self.formatted_text = formatted_text \ No newline at end of file diff --git a/lamb/utils.py b/lamb/utils.py index 177579e..fb55bb3 100644 --- a/lamb/utils.py +++ b/lamb/utils.py @@ -30,6 +30,38 @@ def autochurch(results): ) +style = Style.from_dict({ + # Basic formatting + "text": "#FFFFFF", + "warn": "#FFFF00", + "err": "#FF0000", + "prompt": "#00FFFF", + + # Syntax + "syn_macro": "#FF00FF", + "syn_lambda": "#FF00FF", + "syn_bound": "#FF00FF", + + # Titles for reduction results + "result_header": "#B4EC85 bold", + + # Command formatting + # cmd_h: section titles + # cmd_code: example snippets + # cmd_text: regular text + # cmd_key: keyboard keys, usually one character + "cmd_h": "#FF6600 bold", + "cmd_code": "#AAAAAA italic", + "cmd_text": "#FFFFFF", + "cmd_key": "#B4EC85 bold", + + # Only used in greeting + "_v": "#B4EC85 bold", + "_l": "#FF6600 bold", + "_s": "#B4EC85 bold", + "_p": "#AAAAAA" +}) + def show_greeting(): # | _.._ _.|_ @@ -62,19 +94,4 @@ def show_greeting(): "<_s> A λ calculus engine", "<_p> Type :help for help", "" - ])), style = Style.from_dict({ - # Heading - "_h": "#FFFFFF bold", - - # Version - "_v": "#B4EC85 bold", - - # Lambda - "_l": "#FF6600 bold", - - # Subtitle - "_s": "#B4EC85 bold", - - # :help message - "_p": "#AAAAAA" - })) \ No newline at end of file + ])), style = style) \ No newline at end of file