Cleaned up commands and styling
This commit is contained in:
		| @ -7,6 +7,7 @@ | |||||||
|  - Prettyprint functions (combine args, rename bound variables) |  - Prettyprint functions (combine args, rename bound variables) | ||||||
|  - Write a nice README |  - Write a nice README | ||||||
|  - Handle or avoid recursion errors |  - Handle or avoid recursion errors | ||||||
|  |  - Fix colors | ||||||
|  |  | ||||||
| ## Todo: | ## Todo: | ||||||
|  - live syntax check |  - live syntax check | ||||||
|  | |||||||
| @ -22,8 +22,9 @@ def _(event): | |||||||
|  |  | ||||||
| session = PromptSession( | session = PromptSession( | ||||||
| 	message = FormattedText([ | 	message = FormattedText([ | ||||||
| 		("#00FFFF", "~~> ") | 		("class:prompt", "~~> ") | ||||||
| 	]), | 	]), | ||||||
|  | 	style = utils.style, | ||||||
| 	key_bindings = bindings | 	key_bindings = bindings | ||||||
| ) | ) | ||||||
|  |  | ||||||
| @ -74,44 +75,42 @@ while True: | |||||||
| 	except ppx.ParseException as e: | 	except ppx.ParseException as e: | ||||||
| 		l = len(to_plain_text(session.message)) | 		l = len(to_plain_text(session.message)) | ||||||
| 		printf(FormattedText([ | 		printf(FormattedText([ | ||||||
| 			("#FF0000", " "*(e.loc + l) + "^\n"), | 			("class:err", " "*(e.loc + l) + "^\n"), | ||||||
| 			("#FF0000", f"Syntax error at char {e.loc}."), | 			("class:err", f"Syntax error at char {e.loc}."), | ||||||
| 			("#FFFFFF", "\n") | 			("class:text", "\n") | ||||||
| 		])) | 		])) | ||||||
| 		continue | 		continue | ||||||
| 	except tokens.ReductionError as e: | 	except tokens.ReductionError as e: | ||||||
| 		printf(FormattedText([ | 		printf(FormattedText([ | ||||||
| 			("#FF0000", f"{e.msg}"), | 			("class:err", f"{e.msg}\n") | ||||||
| 			("#FFFFFF", "\n") | 		]), style = utils.style) | ||||||
| 		])) |  | ||||||
| 		continue | 		continue | ||||||
|  |  | ||||||
| 	# If this line defined a macro, print nothing. | 	# If this line defined a macro, print nothing. | ||||||
| 	if isinstance(x, rs.MacroStatus): | 	if isinstance(x, rs.MacroStatus): | ||||||
| 		printf(FormattedText([ | 		printf(FormattedText([ | ||||||
| 			("#FFFFFF", "Set "), | 			("class:text", "Set "), | ||||||
| 			("#FF00FF", x.macro_label), | 			("class:syn_macro", x.macro_label), | ||||||
| 			("#FFFFFF", " to "), | 			("class:text", " to "), | ||||||
| 			("#FFFFFF", str(x.macro_expr)) | 			("class:text", str(x.macro_expr)) | ||||||
| 		])) | 		]), style = utils.style) | ||||||
|  |  | ||||||
|  |  | ||||||
| 	if isinstance(x, rs.CommandStatus): | 	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 | 	# If this line was an expression, print reduction status | ||||||
| 	elif isinstance(x, rs.ReduceStatus): | 	elif isinstance(x, rs.ReduceStatus): | ||||||
| 		printf(FormattedText([ | 		printf(FormattedText([ | ||||||
|  | 			("class:result_header", f"\nExit reason: "), | ||||||
| 			("#00FF00 bold", f"\nExit reason: "), |  | ||||||
| 			x.stop_reason.value, | 			x.stop_reason.value, | ||||||
|  |  | ||||||
| 			("#00FF00 bold", f"\nReduction count: "), | 			("class:result_header", f"\nReduction count: "), | ||||||
| 			("#FFFFFF", str(x.reduction_count)), | 			("class:text", str(x.reduction_count)), | ||||||
|  |  | ||||||
|  |  | ||||||
| 			("#00FF00 bold", "\n\n    => "), | 			("class:result_header", "\n\n    => "), | ||||||
| 			("#FFFFFF", str(x.result)), | 			("class:text", str(x.result)), | ||||||
| 		])) | 		]), style = utils.style) | ||||||
|  |  | ||||||
| 	printf("") | 	printf("") | ||||||
|  | |||||||
| @ -17,14 +17,21 @@ def lamb_command(*, help_text: str): | |||||||
| 	return inner | 	return inner | ||||||
|  |  | ||||||
| def run(command, runner): | 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") | @lamb_command(help_text = "Delete a macro") | ||||||
| def mdel(command, runner): | def mdel(command, runner): | ||||||
| 	if len(command.args) != 1: | 	if len(command.args) != 1: | ||||||
| 		return CommandStatus( | 		return CommandStatus( | ||||||
| 			formatted_text = HTML( | 			formatted_text = HTML( | ||||||
| 				"<red>Command <grey>:mdel</grey> takes exactly one argument.</red>" | 				"<warn>Command <cmd_code>:mdel</cmd_code> takes exactly one argument.</warn>" | ||||||
| 			) | 			) | ||||||
| 		) | 		) | ||||||
|  |  | ||||||
| @ -32,7 +39,7 @@ def mdel(command, runner): | |||||||
| 	if target not in runner.macro_table: | 	if target not in runner.macro_table: | ||||||
| 		return CommandStatus( | 		return CommandStatus( | ||||||
| 			formatted_text = HTML( | 			formatted_text = HTML( | ||||||
| 				f"<red>Macro \"{target}\" is not defined</red>" | 				f"<warn>Macro \"{target}\" is not defined</warn>" | ||||||
| 			) | 			) | ||||||
| 		) | 		) | ||||||
|  |  | ||||||
| @ -41,11 +48,13 @@ def mdel(command, runner): | |||||||
| @lamb_command(help_text = "Show macros") | @lamb_command(help_text = "Show macros") | ||||||
| def macros(command, runner): | def macros(command, runner): | ||||||
| 	return CommandStatus( | 	return CommandStatus( | ||||||
|  |  | ||||||
|  | 		# Can't use HTML here, certain characters might break it. | ||||||
| 		formatted_text = FormattedText([ | 		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() | 			for name, exp in runner.macro_table.items() | ||||||
| 		] | 		] | ||||||
| 		) | 		) | ||||||
| @ -60,56 +69,22 @@ def clear(command, runner): | |||||||
| @lamb_command(help_text = "Print this help") | @lamb_command(help_text = "Print this help") | ||||||
| def help(command, runner): | def help(command, runner): | ||||||
| 	return CommandStatus( | 	return CommandStatus( | ||||||
| 		formatted_text = FormattedText([ | 		formatted_text = HTML( | ||||||
| 			("#FF6600 bold", "\nUsage:\n"), | 			"\n<cmd_text>" + | ||||||
| 			( | 			"<cmd_h>Usage:</cmd_h>" + | ||||||
| 				"#FFFFFF", | 			"\n" + | ||||||
| 				"\tWrite lambda expressions using your " | 			"\tWrite lambda expressions using your <cmd_key>\\</cmd_key> key." + | ||||||
| 			), | 			"\n" + | ||||||
| 			( | 			"\tMacros can be defined using <cmd_key>=</cmd_key>, as in <cmd_code>T = λab.a</cmd_code>" + | ||||||
| 				"#00FF00", | 			"\n" + | ||||||
| 				"\\" | 			"\tRun commands using <cmd_key>:</cmd_key>, for example <cmd_code>:help</cmd_code>" + | ||||||
| 			), | 			"\n\n" + | ||||||
| 			( | 			"<cmd_h>Commands:</cmd_h>"+ | ||||||
| 				"#FFFFFF", | 			"\n" + | ||||||
| 				" key.\n" + | 			"\n".join([ | ||||||
| 				"\tMacros can be defined using " | 				f"\t{name} \t {text}" | ||||||
| 			), | 				for name, text in help_texts.items() | ||||||
|  | 			]) + | ||||||
|  | 			"</cmd_text>" | ||||||
| 			("#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() |  | ||||||
| 		] |  | ||||||
| 		) | 		) | ||||||
| 	) | 	) | ||||||
| @ -16,18 +16,6 @@ class Runner: | |||||||
| 		# If None, no maximum is enforced. | 		# If None, no maximum is enforced. | ||||||
| 		self.reduction_limit: int | None = 300 | 		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: | 	def reduce_expression(self, expr: tokens.LambdaToken) -> rs.ReduceStatus: | ||||||
|  |  | ||||||
| @ -58,7 +46,7 @@ class Runner: | |||||||
| 		return rs.ReduceStatus( | 		return rs.ReduceStatus( | ||||||
| 			reduction_count = i - macro_expansions, | 			reduction_count = i - macro_expansions, | ||||||
| 			stop_reason = rs.StopReason.MAX_EXCEEDED, | 			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. | 		# If this line is a command, do the command. | ||||||
| 		elif isinstance(e, tokens.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. | 		# If this line is a plain expression, reduce it. | ||||||
| 		elif isinstance(e, tokens.LambdaToken): | 		elif isinstance(e, tokens.LambdaToken): | ||||||
|  | |||||||
| @ -1,4 +1,5 @@ | |||||||
| from prompt_toolkit.formatted_text import FormattedText | from prompt_toolkit.formatted_text import FormattedText | ||||||
|  | from prompt_toolkit.formatted_text import HTML | ||||||
| import enum | import enum | ||||||
|  |  | ||||||
| import lamb.tokens as tokens | import lamb.tokens as tokens | ||||||
| @ -33,10 +34,10 @@ class MacroStatus(RunStatus): | |||||||
|  |  | ||||||
|  |  | ||||||
| class StopReason(enum.Enum): | class StopReason(enum.Enum): | ||||||
| 	BETA_NORMAL		= ("#FFFFFF", "β-normal form") | 	BETA_NORMAL		= ("class:text", "β-normal form") | ||||||
| 	LOOP_DETECTED	= ("#FFFF00", "loop detected") | 	LOOP_DETECTED	= ("class:warn", "loop detected") | ||||||
| 	MAX_EXCEEDED	= ("#FFFF00", "too many reductions") | 	MAX_EXCEEDED	= ("class:err", "too many reductions") | ||||||
| 	INTERRUPT		= ("#FF0000", "user interrupt") | 	INTERRUPT		= ("class:warn", "user interrupt") | ||||||
|  |  | ||||||
|  |  | ||||||
| class ReduceStatus(RunStatus): | class ReduceStatus(RunStatus): | ||||||
| @ -71,6 +72,6 @@ class CommandStatus(RunStatus): | |||||||
| 	def __init__( | 	def __init__( | ||||||
| 		self, | 		self, | ||||||
| 		*, | 		*, | ||||||
| 		formatted_text: FormattedText | 		formatted_text: FormattedText | HTML | ||||||
| 	): | 	): | ||||||
| 		self.formatted_text = formatted_text | 		self.formatted_text = formatted_text | ||||||
| @ -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(): | def show_greeting(): | ||||||
| 	#   |  _.._ _.|_ | 	#   |  _.._ _.|_ | ||||||
| @ -62,19 +94,4 @@ def show_greeting(): | |||||||
| 		"<_s> A λ calculus engine</_s>", | 		"<_s> A λ calculus engine</_s>", | ||||||
| 		"<_p> Type :help for help</_p>", | 		"<_p> Type :help for help</_p>", | ||||||
| 		"" | 		"" | ||||||
| 	])), style = Style.from_dict({ | 	])), style = style) | ||||||
| 		# Heading |  | ||||||
| 		"_h": "#FFFFFF bold", |  | ||||||
|  |  | ||||||
| 		# Version |  | ||||||
| 		"_v": "#B4EC85 bold", |  | ||||||
|  |  | ||||||
| 		# Lambda |  | ||||||
| 		"_l": "#FF6600 bold", |  | ||||||
|  |  | ||||||
| 		# Subtitle |  | ||||||
| 		"_s": "#B4EC85 bold", |  | ||||||
|  |  | ||||||
| 		# :help message |  | ||||||
| 		"_p": "#AAAAAA" |  | ||||||
| 	})) |  | ||||||
		Reference in New Issue
	
	Block a user