From 48e7d405ddc6f4751567ad1481dab8fb131e66e6 Mon Sep 17 00:00:00 2001 From: Mark Date: Fri, 11 Nov 2022 17:04:05 -0800 Subject: [PATCH] Improved history & highlighting --- .vscode/settings.json | 1 + README.md | 11 ++++++++--- lamb/nodes/functions.py | 7 +++---- lamb/nodes/nodes.py | 4 ++-- lamb/runner/commands.py | 5 ++--- lamb/runner/runner.py | 26 ++++++++++++++++---------- lamb/utils.py | 5 +++++ 7 files changed, 37 insertions(+), 22 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 16a556c..13b366e 100755 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,5 +1,6 @@ { "cSpell.words": [ + "appendleft", "autochurch", "delmac", "Endnodes", diff --git a/README.md b/README.md index 6b432f7..eda6ee3 100644 --- a/README.md +++ b/README.md @@ -48,6 +48,8 @@ There are many useful macros in [macros.lamb](./macros.lamb). Load them with the ==> :load macros.lamb ``` +You may use up/down arrows to recall history. + Have fun! ------------------------------------------------- @@ -66,7 +68,12 @@ Lamb understands many commands. Prefix them with a `:` in the prompt. `:mdel [macro]` Delete a macro -`:step [yes | no]` Enable or disable step-by-step reduction. Toggle if no argument is given. +`:step [yes | no]` Enable or disable step-by-step reduction. Toggle if no argument is given. When reducing by steps, the prompt tells you what kind of reduction was done last: + + - `M`: Macro expansion + - `C`: Church expansion + - `H`: History expansion + - `F`: Function application `:expand [yes | no]` Enable or disable full expansion. Toggle if no argument is given. If full expansion is enabled, ALL macros will be expanded when printing output. @@ -81,7 +88,6 @@ The lines in a file look exactly the same as regular entries in the prompt, but ## Todo (pre-release, in this order): - - History queue - Prevent macro-chaining recursion - Update screenshot - Update documentation @@ -91,7 +97,6 @@ The lines in a file look exactly the same as regular entries in the prompt, but ## Todo: - Cleanup warnings - - Syntax highlight printouts - Truncate long expressions in warnings - History indexing - Show history command diff --git a/lamb/nodes/functions.py b/lamb/nodes/functions.py index 723068a..9788f54 100644 --- a/lamb/nodes/functions.py +++ b/lamb/nodes/functions.py @@ -162,14 +162,13 @@ def prepare(root: lbn.Root, *, ban_macro_name = None) -> list: it = iter(root) for s, n in it: if isinstance(n, lbn.History): - if len(root.runner.history) == 0: + if root.runner.history[0] == None: raise lbn.ReductionError("There isn't any history to reference.") else: warnings += [ ("class:code", "$"), - ("class:warn", " will be expanded to "), - ("class:code", f"{n.expand()[1]}\n"), - ] + ("class:warn", " will be expanded to ") + ] + lamb.utils.lex_str(str(n.expand()[1])) # If this expression is part of a macro, # make sure we don't reference it inside itself. diff --git a/lamb/nodes/nodes.py b/lamb/nodes/nodes.py index 6a7cc28..130a283 100644 --- a/lamb/nodes/nodes.py +++ b/lamb/nodes/nodes.py @@ -321,12 +321,12 @@ class History(ExpandableEndNode): def expand(self) -> tuple[lbn.ReductionType, Node]: # We shouldn't ever get here, prepare() # catches empty history. - if len(self.runner.history) == 0: + if self.runner.history[0] == None: raise Exception(f"Tried to expand empty history.") # .left is VERY important! # self.runner.history will contain Root nodes, # and we don't want those *inside* our tree. - return lbn.ReductionType.HIST_EXPAND, lbn.clone(self.runner.history[-1].left) + return lbn.ReductionType.HIST_EXPAND, lbn.clone(self.runner.history[0].left) def copy(self): return History(runner = self.runner) diff --git a/lamb/runner/commands.py b/lamb/runner/commands.py index 6a7efd6..038ba71 100644 --- a/lamb/runner/commands.py +++ b/lamb/runner/commands.py @@ -234,9 +234,8 @@ def cmd_load(command, runner): printf( FormattedText([ - ("class:ok", f"Loaded {x.label}: "), - ("class:code", str(x.expr)) - ]), + ("class:ok", f"Loaded {x.label}: ") + ] + lamb.utils.lex_str(str(x.expr))), style = lamb.utils.style ) diff --git a/lamb/runner/runner.py b/lamb/runner/runner.py index 63ca1ac..8a082eb 100644 --- a/lamb/runner/runner.py +++ b/lamb/runner/runner.py @@ -3,7 +3,7 @@ from prompt_toolkit.formatted_text import FormattedText from prompt_toolkit.key_binding import KeyBindings from prompt_toolkit import prompt from prompt_toolkit import print_formatted_text as printf -import enum +import collections import math import time @@ -58,7 +58,10 @@ class Runner: # so that all digits appear to be changing. self.iter_update = 231 - self.history: list[lamb.nodes.Root] = [] + self.history = collections.deque( + [None] * 10, + 10) + # If true, reduce step-by-step. self.step_reduction = False @@ -160,10 +163,9 @@ class Runner: try: s = prompt( message = FormattedText([ - ("class:muted", lamb.nodes.reduction_text[red_type]), - ("class:muted", f":{k:03} "), - ("class:text", str(node)), - ]), + ("class:prompt", lamb.nodes.reduction_text[red_type]), + ("class:prompt", f":{k:03} ") + ] + lamb.utils.lex_str(str(node))), style = lamb.utils.style, key_bindings = step_bindings ) @@ -218,9 +220,8 @@ class Runner: only_macro ): out_text += [ - ("class:ok", "\n\n => "), - ("class:text", str(node)), # type: ignore - ] + ("class:ok", "\n\n => ") + ] + lamb.utils.lex_str(str(node)) printf( @@ -230,7 +231,12 @@ class Runner: # Save to history # Do this at the end so we don't always fully expand. - self.history.append(lamb.nodes.expand(node, force_all = True)[1]) + self.history.appendleft( + lamb.nodes.expand( # type: ignore + node, + force_all = True + )[1] + ) def save_macro( self, diff --git a/lamb/utils.py b/lamb/utils.py index 62617a0..5647e7f 100644 --- a/lamb/utils.py +++ b/lamb/utils.py @@ -4,6 +4,7 @@ from prompt_toolkit.lexers import Lexer from prompt_toolkit.key_binding import KeyBindings from prompt_toolkit import print_formatted_text as printf from importlib.metadata import version +from prompt_toolkit.document import Document import re @@ -77,6 +78,10 @@ class LambdaLexer(Lexer): return inner + +def lex_str(s: str) -> list[tuple[str, str]]: + return LambdaLexer().lex_document(Document(s))(0) + def show_greeting(): # | _.._ _.|_ # |_(_|| | ||_)