Trochu zpoužitelněný systém příkazů. Resolves #24.
Asi nemá úplně smysl mít nějaký magický nedeterministický způsob, jak dělat výstupy příkazů víc inline. Pokud příkazy chtějí být volatelné inline, musí se postarat o to, že jejich výstup s tím bude kompatibilní. Příkaz si může ověřit, jestli se očekává inlinovost podle toho, jestli je parametr `e` třídy BlockCommand nebo `InlineCommand`.
This commit is contained in:
		
							parent
							
								
									f8c1cac18e
								
							
						
					
					
						commit
						f63ed7b56a
					
				
					 7 changed files with 42 additions and 23 deletions
				
			
		|  | @ -1,7 +1,5 @@ | ||||||
| from panflute import Span, Div, Element, Plain, Para | from panflute import Span, Div, Element, Plain, Para | ||||||
| 
 | 
 | ||||||
| from .util import inlinify |  | ||||||
| 
 |  | ||||||
| class InlineError(Exception): | class InlineError(Exception): | ||||||
| 	pass | 	pass | ||||||
| 
 | 
 | ||||||
|  | @ -11,18 +9,21 @@ class Command: | ||||||
| # This distinction is needed because while transforming the tree, inline | # This distinction is needed because while transforming the tree, inline | ||||||
| # elements cannot be replaced with block ones | # elements cannot be replaced with block ones | ||||||
| class InlineCommand(Span, Command): | class InlineCommand(Span, Command): | ||||||
| 	def replaceSelf(self, content: list[Element]) -> Span: | 	def replaceSelf(self, *content: list[Element]) -> Span: | ||||||
| 		try: | 		try: | ||||||
| 			return Span(*content) | 			return Span(*content) | ||||||
| 		except TypeError: | 		except TypeError: | ||||||
| 			if inlinify(content): | 			if len(content) == 1 and (isinstance(content[0], Para) or isinstance(content[0], Plain)): | ||||||
| 				return Span(inlinify(content)) | 				return Span(*content[0].content) | ||||||
| 			else: | 			else: | ||||||
| 				raise InlineError(f"The command {self.attributes['c']} returned multiple Paragraphs and must be executed using `::: {{c={self.attributes['c']}}}\\n:::`.\n\n{content}") | 				raise InlineError(f"The command {self.attributes['c']} returned multiple Paragraphs and must be executed using `::: {{c={self.attributes['c']}}}\\n:::`.\n\n{content}") | ||||||
| 	pass | 	pass | ||||||
| 
 | 
 | ||||||
| class BlockCommand(Div, Command): | class BlockCommand(Div, Command): | ||||||
| 	def replaceSelf(self, content: list[Element]) -> Div: | 	def replaceSelf(self, *content: list[Element]) -> Div: | ||||||
| 		return Div(*content) | 		try: | ||||||
|  | 			return Div(*content) | ||||||
|  | 		except TypeError: | ||||||
|  | 			return Div(Para(*content)) | ||||||
| 	pass | 	pass | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1,6 +1,7 @@ | ||||||
| import panflute as pf | import panflute as pf | ||||||
| import formatitko.elements as fe | import formatitko.elements as fe | ||||||
| from formatitko.util import import_md_list | from formatitko.util import import_md_list | ||||||
|  | from formatitko.util import parse_string | ||||||
| 
 | 
 | ||||||
| from formatitko.context import Context | from formatitko.context import Context | ||||||
| from formatitko.command import Command | from formatitko.command import Command | ||||||
|  |  | ||||||
|  | @ -111,7 +111,7 @@ def transform(e: Element, c: Context) -> Element: | ||||||
| 		if not c.trusted: | 		if not c.trusted: | ||||||
| 			return nullify(e) | 			return nullify(e) | ||||||
| 		command_output = parse_command(e.text)(BlockCommand(), c) | 		command_output = parse_command(e.text)(BlockCommand(), c) | ||||||
| 		e = Div(*([] if command_output is None else command_output)) | 		e = BlockCommand().replaceSelf(*([] if command_output is None else command_output)) | ||||||
| 		e = e.walk(transform, c) | 		e = e.walk(transform, c) | ||||||
| 
 | 
 | ||||||
| 	# Command defines for calling using BlockCommand and InlineCommand. If | 	# Command defines for calling using BlockCommand and InlineCommand. If | ||||||
|  | @ -164,7 +164,7 @@ def transform(e: Element, c: Context) -> Element: | ||||||
| 		if not c.get_command(e.attributes["c"]): | 		if not c.get_command(e.attributes["c"]): | ||||||
| 			raise NameError(f"Command not defined '{e.attributes['c']}'.") | 			raise NameError(f"Command not defined '{e.attributes['c']}'.") | ||||||
| 		command_output = c.get_command(e.attributes["c"])(e, c) | 		command_output = c.get_command(e.attributes["c"])(e, c) | ||||||
| 		e = e.replaceSelf([] if command_output is None else command_output) | 		e = e.replaceSelf(*command_output) | ||||||
| 		e = e.walk(transform, c) | 		e = e.walk(transform, c) | ||||||
| 
 | 
 | ||||||
| 	return e | 	return e | ||||||
|  |  | ||||||
|  | @ -1,22 +1,13 @@ | ||||||
| from panflute import Element, Block, Inline, Null, Str, Doc, convert_text, Para, Plain, Span | from panflute import Element, Block, Inline, Null, Str, Doc, convert_text, Para, Plain, Span, Space | ||||||
| import re | import re | ||||||
| from typing import Union | from typing import Union | ||||||
| 
 | 
 | ||||||
| # It sometimes happens that an element contains a single paragraph or even a | # It sometimes happens that an element contains a single paragraph or even a | ||||||
| # single plaintext line. It can be sometimes useful to extract this single | # single plaintext line. It can be sometimes useful to extract this single | ||||||
| # paragraph, which is inline. | # paragraph, which is inline. | ||||||
| def inlinify(e: Union[Element, list[Element]]) -> Union[Element, None]: | def inlinify(e: Element) -> Union[list[Element], None]: | ||||||
| 	if isinstance(e, Element): | 	if len(e.content) == 1 and (isinstance(e.content[0], Para) or isinstance(e.content[0], Plain)): | ||||||
| 		content = e.content | 		return e.content[0].content | ||||||
| 	else: |  | ||||||
| 		content = e |  | ||||||
| 	if len(content) == 0: |  | ||||||
| 		return Str("") |  | ||||||
| 	if len(content) == 1 and (isinstance(content[0], Para) or isinstance(content[0], Plain)): |  | ||||||
| 		return Span(*content[0].content) |  | ||||||
| 	if len(content) == 1 and inlinify(content[0]) is not None: |  | ||||||
| 		return inlinify(content[0]) |  | ||||||
| 	return None |  | ||||||
| 
 | 
 | ||||||
| # In transform, inline elements cannot be replaced with Block ones and also | # In transform, inline elements cannot be replaced with Block ones and also | ||||||
| # cannot be removed from the tree entirely, because that would mess up the | # cannot be removed from the tree entirely, because that would mess up the | ||||||
|  | @ -28,6 +19,20 @@ def nullify(e: Element) -> Union[Str, Null]: | ||||||
| 	else: | 	else: | ||||||
| 		return Null() | 		return Null() | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|  | def parse_string(s: str) -> list[Union[Str, Space]]: | ||||||
|  | 	words = s.split(" ") | ||||||
|  | 	output = [] | ||||||
|  | 	first_word, *words = words | ||||||
|  | 	if first_word != "": | ||||||
|  | 		output.append(Str(first_word)) | ||||||
|  | 	for word in words: | ||||||
|  | 		output.append(Space()) | ||||||
|  | 		if word != "": | ||||||
|  | 			output.append(Str(word)) | ||||||
|  | 	return output | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| # A helper function to import markdown using panflute (which calls pandoc). If | # A helper function to import markdown using panflute (which calls pandoc). If | ||||||
| # we ever want to disable or enable some of panflute's markdown extensions, | # we ever want to disable or enable some of panflute's markdown extensions, | ||||||
| # this is the place to do it. | # this is the place to do it. | ||||||
|  |  | ||||||
|  | @ -5,3 +5,6 @@ return element.content | ||||||
| ```python {define=opendatatask} | ```python {define=opendatatask} | ||||||
| return import_md_list("Toto je praktická open-data úloha. V [odevzdávátku](https://ksp.mff.cuni.cz/h/odevzdavatko/) si necháte vygenerovat vstupy a odevzdáte příslušné výstupy. Záleží jen na vás, jak výstupy vyrobíte.") | return import_md_list("Toto je praktická open-data úloha. V [odevzdávátku](https://ksp.mff.cuni.cz/h/odevzdavatko/) si necháte vygenerovat vstupy a odevzdáte příslušné výstupy. Záleží jen na vás, jak výstupy vyrobíte.") | ||||||
| ``` | ``` | ||||||
|  | ```python {define=opendatatask2} | ||||||
|  | return [*parse_string("Toto je praktická open-data úloha. V "),pf.Link(pf.Str("odevzdávátku"), url="https://ksp.mff.cuni.cz/h/odevzdavatko/"),*parse_string(" si necháte vygenertovat vstupy a odevzdáte příslušné výstupy. Záleží jen na vás, jak výstupy vyrobíte.")] | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | @ -19,6 +19,14 @@ context.set_flag("cat", True) | ||||||
| ```python {.run} | ```python {.run} | ||||||
| return import_md_list(f"The subdocument's title is\n\n# {context.get_metadata('title')}\n\nThe subdocument's subtitle is\n\n## {context.get_metadata('subtitle')}") | return import_md_list(f"The subdocument's title is\n\n# {context.get_metadata('title')}\n\nThe subdocument's subtitle is\n\n## {context.get_metadata('subtitle')}") | ||||||
| ``` | ``` | ||||||
|  | ```python {.run} | ||||||
|  | return [ | ||||||
|  | 	pf.Para(*parse_string("The subdocument's title is")), | ||||||
|  | 	pf.Header(*parse_string(context.get_metadata('title')), level=1), | ||||||
|  | 	pf.Para(*parse_string("The subdocument's subtitle is")), | ||||||
|  | 	pf.Header(*parse_string(context.get_metadata('subtitle')), level=2) | ||||||
|  | ] | ||||||
|  | ``` | ||||||
| 
 | 
 | ||||||
| ```markdown {.group} | ```markdown {.group} | ||||||
| --- | --- | ||||||
|  |  | ||||||
|  | @ -38,7 +38,7 @@ context.set_flag("cat", True) | ||||||
| context.set_metadata("a", {}) | context.set_metadata("a", {}) | ||||||
| context.set_metadata("a.b", {}) | context.set_metadata("a.b", {}) | ||||||
| context.set_metadata("a.b.c", "Bruh **bruh** bruh") | context.set_metadata("a.b.c", "Bruh **bruh** bruh") | ||||||
| return import_md_list(f"The main document's title is '{context.get_metadata('title')}'") | return [*parse_string("The main document's title is "), fe.FQuoted(*parse_string(context.get_metadata('title')), style="simple"), pf.Str(".")] | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| ```python {style=native} | ```python {style=native} | ||||||
|  | @ -64,6 +64,7 @@ V pravém jízdním bruhu. | ||||||
| V pravém jízdním bruhu. | V pravém jízdním bruhu. | ||||||
| 
 | 
 | ||||||
| [!opendatatask]{} | [!opendatatask]{} | ||||||
|  | [!opendatatask2]{} | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| [This too!]{if=cat} | [This too!]{if=cat} | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue