working interactively
This commit is contained in:
parent
16d6ed9a5f
commit
82c1bcb269
100
src/wud/parse_mod.py
Normal file
100
src/wud/parse_mod.py
Normal 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
7
src/wud/sidebar.tcss
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#sidebar {
|
||||||
|
dock: left;
|
||||||
|
width: 20;
|
||||||
|
height: 100%;
|
||||||
|
color: #0f2b41;
|
||||||
|
background: dodgerblue;
|
||||||
|
}
|
86
src/wud/tui.py
Normal file
86
src/wud/tui.py
Normal 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()
|
Loading…
Reference in New Issue
Block a user