working interactively

This commit is contained in:
James Turk 2024-07-28 02:54:32 -04:00
parent 16d6ed9a5f
commit 82c1bcb269
3 changed files with 193 additions and 0 deletions

100
src/wud/parse_mod.py Normal file
View File

@ -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)

7
src/wud/sidebar.tcss Normal file
View File

@ -0,0 +1,7 @@
#sidebar {
dock: left;
width: 20;
height: 100%;
color: #0f2b41;
background: dodgerblue;
}

86
src/wud/tui.py Normal file
View File

@ -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()