Files
MeshTerm/meshterm/tools/about.py
T
Jean-Pierre MartineauandClaude Opus 5 ea9b7c1cb1 Main menu: Device config, Support MeshTerm
Two rows renamed, and the rename carried into the screens they open —
the config editor's table title and its staged-count header, the support
page's own title (it comes from the tool, so it followed on its own).

"Support this project" never said which project; the menu is MeshTerm's
and the section above it is already About MeshTerm, so the name is the
useful half of that phrase. "Device configuration" was the longest label
in the list and set the width of the whole name column: at 19 cells
instead of 23, every description now gets 51 and the widest row is 68.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-12 17:15:00 -04:00

132 lines
4.3 KiB
Python

"""The About MeshTerm tools: the three pages under the menu's last section.
*About MeshTerm*, *About the author*, *Support MeshTerm* — in that order, which is
the order a stranger asks the questions in: what is this, who made it, how do I help.
Each is a page rather than a feature: it reads nothing, transmits nothing, and needs no
device, so it opens straight to its screen (see :mod:`meshterm.ui.about`) instead of
prompting for anything first.
Each also keeps a CLI face — ``meshterm about``, ``meshterm about-author``,
``meshterm support`` — printing the same page to the terminal, so the answers are
reachable from a shell without launching the full-screen session.
The pages themselves are written in markdown under ``meshterm/assets/pages`` (see
:mod:`meshterm.ui.about`); nothing here knows what any of them say.
"""
from __future__ import annotations
from typing import TYPE_CHECKING, Any, Optional
from ..context import AppContext
from .base import Tool, ToolResult, register
if TYPE_CHECKING:
from ..ui.markdown import MarkdownDoc
class _AboutTool(Tool):
"""Shared behaviour for the three About pages: open the screen, or print the page.
The pages differ only in their title, icon, and content, so everything else — the
menu-only screen open, the printing CLI face, the run row — lives here once. A
subclass supplies :meth:`page`, and nothing more.
"""
category = "About MeshTerm"
@staticmethod
def page() -> "MarkdownDoc":
"""Build this page's content.
Overridden by each page. Subclasses import their builder *inside* the override
rather than at module scope: the registry imports every tool module at startup
(see :func:`~meshterm.tools.load_all_tools`), and a page's content is only ever
wanted once someone actually opens it.
"""
raise NotImplementedError
async def prompt_params(self, ctx: AppContext) -> Optional[dict[str, Any]]:
"""Open the page; returning ``None`` completes the invocation with no run row.
The page transmits nothing and stores nothing, so — like the Trophy case and the
mesh walk — it lives here rather than in :meth:`run`, and logs no run of its own.
Args:
ctx: Shared application context.
Returns:
Always ``None``.
"""
from ..ui.about import open_about_page
await open_about_page(ctx, self.title, self.page())
return None
async def run(self, ctx: AppContext, params: dict[str, Any]) -> ToolResult:
"""Print the page — only reachable from the CLI (the menu opens the screen).
Args:
ctx: Shared application context.
params: Unused beyond the injected ``_run_id``.
Returns:
A :class:`ToolResult` naming the page that was shown.
"""
ctx.ui.show(self.page())
return ToolResult(summary={"page": self.name})
@register
class AboutMeshTermTool(_AboutTool):
"""What MeshTerm is, where it came from, and the terms it ships under."""
name = "about"
title = "About MeshTerm"
icon = "📖"
help = "What this is, and the terms it ships under"
order = 10 # the question a stranger asks first
@staticmethod
def page() -> "MarkdownDoc":
"""The *About MeshTerm* page."""
from ..ui.about import about_meshterm
return about_meshterm()
@register
class AboutAuthorTool(_AboutTool):
"""The person behind MeshTerm, on the mesh and off it."""
name = "about-author"
title = "About the author"
icon = "👤"
help = "The person behind MeshTerm, on and off the mesh"
order = 20 # who made the thing you just read about
@staticmethod
def page() -> "MarkdownDoc":
"""The *About the author* page."""
from ..ui.about import about_author
return about_author()
@register
class SupportProjectTool(_AboutTool):
"""What keeps MeshTerm going, and the ways — paid and unpaid — to help it along."""
name = "support"
title = "Support MeshTerm"
icon = "💰"
help = "What keeps MeshTerm going, and how to help"
order = 30 # the ask, and only once the first two have earned it
@staticmethod
def page() -> "MarkdownDoc":
"""The *Support MeshTerm* page."""
from ..ui.about import support_project
return support_project()