diff --git a/src/wud/parse_mod.py b/src/wud/parse_mod.py new file mode 100644 index 0000000..33e0433 --- /dev/null +++ b/src/wud/parse_mod.py @@ -0,0 +1,100 @@ +import inspect +from dataclasses import dataclass, field +import typing + + +@dataclass +class Func: + name: str + desc: str + signature: inspect.Signature + + def __str__(self): + return f"{self.name}{self.signature}\n\t{self.desc}" + + @property + def icon(self): + return "F" + + +@dataclass +class Class: + name: str + desc: str + signature: inspect.Signature + + def __str__(self): + return f"{self.name}{self.signature}\n\t{self.desc}" + + @property + def icon(self): + return "C" + + +@dataclass +class Datum: + name: str + desc: str + value: typing.Any + type_name: str + + def __str__(self): + return f"{self.name} = {self.value} ({self.type_name})\n\t{self.desc}" + + @property + def icon(self): + return "G" + + +@dataclass +class Mod: + name: str + desc: str + functions: list[Func] = field(default_factory=list) + classes: list[Class] = field(default_factory=list) + data: list[Datum] = field(default_factory=list) + + @property + def icon(self): + return "M" + + +def parse_function(func): + try: + signature = inspect.signature(func) + except ValueError: + signature = "..." + return Func(name=func.__name__, desc=func.__doc__, signature=signature) + + +def parse_class(cls): + try: + signature = inspect.signature(cls) + except ValueError: + signature = "..." + return Class(name=cls.__name__, desc=cls.__doc__, signature=signature) + + +def parse_module(mod): + info = Mod(mod.__name__, mod.__doc__) + + for name, member in inspect.getmembers(mod): + if inspect.isclass(member): + info.classes.append(parse_class(member)) + elif inspect.isroutine(member): + info.functions.append(parse_function(member)) + elif not name.startswith("__"): + info.data.append(Datum(name, member.__doc__, member, type(member).__name__)) + + return info + + +if __name__ == "__main__": + import math + + parsed = parse_module(math) + for f in parsed["functions"]: + print(f) + + for d in parsed["data"]: + print(d) diff --git a/src/wud/sidebar.tcss b/src/wud/sidebar.tcss new file mode 100644 index 0000000..132b25b --- /dev/null +++ b/src/wud/sidebar.tcss @@ -0,0 +1,7 @@ +#sidebar { + dock: left; + width: 20; + height: 100%; + color: #0f2b41; + background: dodgerblue; +} diff --git a/src/wud/tui.py b/src/wud/tui.py new file mode 100644 index 0000000..f2f12d0 --- /dev/null +++ b/src/wud/tui.py @@ -0,0 +1,86 @@ +import importlib +from textual.app import App, ComposeResult +from textual.reactive import reactive +from textual.widgets import ( + Static, + Header, + ListView, + ListItem, + Label, + MarkdownViewer, + Markdown, +) +from .parse_mod import parse_module + +TEXT = """\ +Docking a widget removes it from the layout and fixes its position, aligned to either the top, right, bottom, or left edges of a container. + +Docked widgets will not scroll out of view, making them ideal for sticky headers, footers, and sidebars. + +""" + + +class MemberListView(ListView): + def __init__(self, mod_list): + super().__init__(id="sidebar") + self.mod_list = mod_list + + def compose(self): + for f in self.mod_list: + yield ListItem(Label(f"{f.name:<16}{f.icon}")) + + +def func2md(func): + return f"""## {func.name}{func.signature} + {func.desc} + """ + + +def mod2md(mod): + func_md = "\n\n".join(func2md(f) for f in mod.functions) + return f"""# {mod.name} + {mod.desc} + + {func_md} + """ + + +# class DocView(MarkdownViewer): +# +# def __init__(self, mod): +# super().__init__(markdown=mod) +# +# def watch_md(self): +# self.markdown = self.md +# + + +class WudTui(App): + CSS_PATH = "sidebar.tcss" + + def __init__(self, modname): + super().__init__() + _mod = importlib.import_module(modname) + self.mod = parse_module(_mod) + self.mod_list = [self.mod] + self.mod.functions + self.mod.data + + def compose(self) -> ComposeResult: + yield Header() + yield MemberListView(self.mod_list) + yield Markdown(mod2md(self.mod), id="docview") + + def on_mount(self): + self.title = "wud" + self.sub_title = self.mod.name + + def on_list_view_highlighted(self, _): + lv = self.query_one("#sidebar", MemberListView) + md = self.query_one("#docview", Markdown) + md.update(markdown=f"{self.mod_list[lv.index]}") + + +if __name__ == "__main__": + import sys + + app = WudTui(sys.argv[1]) + app.run()