From edbd985043421b5a90ad4a1656064dd3c1adfe81 Mon Sep 17 00:00:00 2001 From: Greenscreener Date: Sun, 20 Aug 2023 01:20:28 +0200 Subject: [PATCH] =?UTF-8?q?P=C5=99id=C3=A1no=20n=C4=9Bkolik=20zp=C5=AFsob?= =?UTF-8?q?=C5=AF,=20jak=20importovat=20commands.=20Resolves=20#31?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/formatitko/context.py | 6 +++-- src/formatitko/transform_processor.py | 33 ++++++++++++++++++++++----- test/test.md | 2 +- 3 files changed, 32 insertions(+), 9 deletions(-) diff --git a/src/formatitko/context.py b/src/formatitko/context.py index adaa9da..8abc209 100644 --- a/src/formatitko/context.py +++ b/src/formatitko/context.py @@ -46,9 +46,11 @@ class Context: def unset_command(self, command: str): del self._commands[command] - def add_commands_from_module(self, module: ModuleType, module_name: str=""): + def add_commands_from_module(self, module: Union[dict[str, CommandCallable], ModuleType], module_name: str=""): + if isinstance(module, ModuleType): + module = module.__dict__ prefix = module_name+"." if module_name else "" - for name, func in module.__dict__.items(): + for name, func in module: if isinstance(func, CommandCallable): self.set_command(prefix+name, func) diff --git a/src/formatitko/transform_processor.py b/src/formatitko/transform_processor.py index a7c51ba..1e31521 100644 --- a/src/formatitko/transform_processor.py +++ b/src/formatitko/transform_processor.py @@ -3,16 +3,18 @@ from panflute import Cite, Code, Emph, Image, LineBreak, Link, Math, Note, Quote from panflute import BlockQuote, BulletList, Citation, CodeBlock, Definition, DefinitionItem, DefinitionList, Div, Figure, Header, HorizontalRule, LineBlock, LineItem, ListItem, MetaBlocks, MetaBool, MetaInlines, MetaList, MetaMap, MetaString, Null, OrderedList, Para, Plain, RawBlock, Table, TableBody, TableFoot, TableHead from panflute import TableRow, TableCell, Caption, Doc from typing import Union, Callable +from types import ModuleType import os import re import warnings +import importlib from .whitespace import NBSP from .elements import FQuoted from .context import Group, InlineGroup, BlockGroup from .util import nullify, import_md -from .context import Context +from .context import Context, CommandCallable from .whitespace import Whitespace, bavlna from .command import BlockCommand, InlineCommand, Command from .command_util import handle_command_define, parse_command @@ -33,6 +35,7 @@ class TransformProcessor: self.context: Context = None self.root_file_path = root_file_path self.root_highlight_style = "default" + self._command_modules = [] self.TYPE_DICT = { TableRow: self.transform_TableRow, @@ -100,6 +103,9 @@ class TransformProcessor: BlockCommand: self.transform_BlockCommand } + def add_command_module(self, module: Union[dict[str, CommandCallable], ModuleType], module_name: str=""): + self._command_modules.append((module, module_name)) + def get_pretransformers(self) -> list[Callable[[ELCl],ELCl]]: return [self.handle_if_attribute, self.handle_ifnot_attribute] @@ -324,6 +330,8 @@ class TransformProcessor: if self.context is not None: raise DoubleDocError() self.context = Context(e, self.root_file_path) + for module, module_name in self._command_modules: + self.context.add_commands_from_module(module, module_name) e.content = self.transform(e.content) e.content = [BlockGroup(*e.content, context=self.context)] return e @@ -422,12 +430,25 @@ class TransformProcessor: e = InlineCommand(identifier=e.identifier, classes=e.classes, attributes={**e.attributes, "c": e.content[0].text[1:]}) return self.transform(e) - ## Handle import [#path/file.md]{} - # This is the exact opposite of partials. We take the commands, flags - # and metadata but drop the content. + ## Handle import [#ksp_formatitko as ksp]{}, [#ksp_formatitko]{type=module} or [#path/file.md]{type=md} + # Import a python module as commands (type=module, the default) or + # import all metadata from a md file, dropping its contents. elif re.match(r"^#.+$", e.content[0].text): - importedDoc = import_md(open(self.context.dir + "/" + e.content[0].text[1:], "r").read()) - self.transform(importedDoc.content) + if not "type" in e.attributes: + e.attributes["type"] = "module" + if e.attributes["type"] == "md": + importedDoc = import_md(open(self.context.dir + "/" + e.content[0].text[1:], "r").read()) + self.transform(importedDoc.content) + elif e.attributes["type"] == "module": + matches = re.match(r"^(\w+)(?: as (\w+))?$", e.content[0].text[1:]) + if not matches: + raise SyntaxError(f"`{e.content[0].text[1:]}`: invalid syntax") + module = importlib.import_module(matches.group(1)) + module_name = matches.group(1) if matches.group(2) is None else matches.group(2) + self.context.add_commands_from_module(module, module_name) + else: + raise SyntaxError(f"`{e.attributes['type']}`: invalid import type") + return nullify(e) ## Handle metadata print [$key1.key2]{} diff --git a/test/test.md b/test/test.md index 8cafab2..7f1eb8d 100644 --- a/test/test.md +++ b/test/test.md @@ -4,7 +4,7 @@ subtitle: 'A subtitle' are_we_there_yet: False lang: "en" --- -[#test-files/test-import.md]{} +[#test-files/test-import.md]{type=md} # Hello world! ## H2