mirror of
https://github.com/Cog-Creators/Red-DiscordBot.git
synced 2026-05-14 20:11:48 -04:00
130 lines
4.4 KiB
Python
130 lines
4.4 KiB
Python
import enum
|
|
|
|
from rich.text import Text
|
|
from textual.app import App, ComposeResult
|
|
from textual.binding import Binding
|
|
from textual.events import Click
|
|
from textual.widgets import Footer, Markdown, MarkdownViewer, Static
|
|
from typing_extensions import Self
|
|
|
|
from .changelog import Changelogs
|
|
|
|
|
|
# See https://github.com/Textualize/textual/discussions/6449
|
|
class MarkdownLinkTooltip(Static, inherit_css=False):
|
|
DEFAULT_CSS = """
|
|
MarkdownLinkTooltip {
|
|
layer: _tooltips;
|
|
margin: 1 0;
|
|
padding: 1 2;
|
|
background: $panel;
|
|
width: auto;
|
|
height: auto;
|
|
constrain: inside inflect;
|
|
max-width: 40;
|
|
display: none;
|
|
offset-x: -50%;
|
|
}
|
|
"""
|
|
|
|
|
|
class _MarkdownViewer(MarkdownViewer):
|
|
DEFAULT_CSS = """
|
|
_MarkdownViewer {
|
|
layers: default _tooltips;
|
|
}
|
|
"""
|
|
|
|
def compose(self) -> ComposeResult:
|
|
yield from super().compose()
|
|
yield MarkdownLinkTooltip()
|
|
|
|
def on_markdown_link_clicked(self, message: Markdown.LinkClicked) -> None:
|
|
# We don't want the default behavior of opening the browser/navigating to a file on click.
|
|
message.prevent_default()
|
|
|
|
tooltip = self.get_child_by_type(MarkdownLinkTooltip)
|
|
tooltip.display = True
|
|
# You can't cycle over the links in MarkdownViewer (see Textualize/textual#3555)
|
|
# so using mouse position is fine.
|
|
# Textualize/textual#3555: https://github.com/Textualize/textual/discussions/3555
|
|
tooltip.absolute_offset = self.app.mouse_position
|
|
# For some reason, links only render correctly when Text has a span over the whole text
|
|
# with a link but not when Text just has a style applied to it directly, i.e.:
|
|
# Text(message.href, style=f"link {message.href}")
|
|
# will not work.
|
|
tooltip.update(Text().append(message.href, style=f"link {message.href}"))
|
|
|
|
def on_click(self, message: Click) -> None:
|
|
tooltip = self.get_child_by_type(MarkdownLinkTooltip)
|
|
tooltip.display = False
|
|
|
|
|
|
class ChangelogReaderResult(enum.Enum):
|
|
QUIT = enum.auto()
|
|
CONTINUE = enum.auto()
|
|
|
|
|
|
class ChangelogReaderApp(App[ChangelogReaderResult], inherit_bindings=False):
|
|
ENABLE_COMMAND_PALETTE = False
|
|
BINDINGS = [
|
|
Binding(key="ctrl+c", action="quit", description="Exit redbot-update"),
|
|
Binding(key="q", action="continue", description="Finish reading the changelog"),
|
|
]
|
|
|
|
def __init__(self, markdown_content: str) -> None:
|
|
self.markdown_content = markdown_content
|
|
super().__init__()
|
|
|
|
@classmethod
|
|
def from_changelogs(cls, changelogs: Changelogs) -> Self:
|
|
if not changelogs:
|
|
return cls("")
|
|
|
|
parts = []
|
|
contributors = sorted(
|
|
{
|
|
contributor
|
|
for changelog in changelogs.values()
|
|
for contributor in changelog.contributors
|
|
}
|
|
)
|
|
if contributors:
|
|
contributor_thanks = (
|
|
"# Thanks to our contributors \N{HEAVY BLACK HEART}\N{VARIATION SELECTOR-16}\n"
|
|
"**The releases below were made with help from the following people:** \n"
|
|
)
|
|
contributor_thanks += ", ".join(
|
|
f"[@{contributor}](https://github.com/sponsors/{contributor})"
|
|
for contributor in contributors
|
|
)
|
|
parts.append(contributor_thanks)
|
|
|
|
parts.append("# Read before updating")
|
|
for changelog in reversed(changelogs.values()):
|
|
if changelog.read_before_updating_section:
|
|
parts.append(f"## {changelog.version}")
|
|
parts.append(changelog.read_before_updating_section)
|
|
|
|
parts.append("# User changelog")
|
|
for changelog in reversed(changelogs.values()):
|
|
if changelog.user_changelog_section:
|
|
parts.append(f"## {changelog.version}")
|
|
parts.append(changelog.user_changelog_section)
|
|
|
|
return cls("\n".join(parts))
|
|
|
|
def compose(self) -> ComposeResult:
|
|
markdown_viewer = _MarkdownViewer(
|
|
self.markdown_content, show_table_of_contents=True, open_links=False
|
|
)
|
|
markdown_viewer.code_indent_guides = False
|
|
yield markdown_viewer
|
|
yield Footer()
|
|
|
|
def action_quit(self) -> None:
|
|
self.exit(ChangelogReaderResult.QUIT)
|
|
|
|
def action_continue(self) -> None:
|
|
self.exit(ChangelogReaderResult.CONTINUE)
|