clan: implement OSC8 hyperlinks for help output

The name of the terminal help output stays the same to keep
compatibility with legacy terminal implementations.
This commit is contained in:
a-kenji 2024-06-26 22:41:43 +02:00 committed by kenji
parent 33ea53ee8f
commit d9ba61c30a
4 changed files with 73 additions and 29 deletions

View File

@ -28,6 +28,7 @@ from . import (
from .custom_logger import setup_logging
from .dirs import get_clan_flake_toplevel_or_env
from .errors import ClanCmdError, ClanError
from .hyperlink import help_hyperlink
from .profiler import profile
from .ssh import cli as ssh_cli
@ -89,9 +90,9 @@ def create_parser(prog: str | None = None) -> argparse.ArgumentParser:
prog=prog,
description="The clan cli tool.",
epilog=(
"""
Online reference for the clan cli tool: https://docs.clan.lol/reference/cli/
For more detailed information, visit: https://docs.clan.lol
f"""
Online reference for the clan cli tool: {help_hyperlink("cli reference", "https://docs.clan.lol/reference/cli/")}
For more detailed information, visit: {help_hyperlink("docs", "https://docs.clan.lol")}
"""
),
formatter_class=argparse.RawTextHelpFormatter,
@ -127,7 +128,7 @@ Note: The meta results from clan/meta.json and manual flake arguments. It may no
help="manage backups of clan machines",
description="manage backups of clan machines",
epilog=(
"""
f"""
This subcommand provides an interface to backups that clan machines expose.
Examples:
@ -142,7 +143,7 @@ Examples:
The backup to restore for the machine [MACHINE] with the configured [PROVIDER]
with the name [NAME].
For more detailed information, visit: https://docs.clan.lol/getting-started/backups/
For more detailed information visit: {help_hyperlink("backups", "https://docs.clan.lol/getting-started/backups")}.
"""
),
formatter_class=argparse.RawTextHelpFormatter,
@ -154,13 +155,13 @@ For more detailed information, visit: https://docs.clan.lol/getting-started/back
help="create a clan flake inside the current directory",
description="create a clan flake inside the current directory",
epilog=(
"""
f"""
Examples:
$ clan flakes create [DIR]
Will create a new clan flake in the specified directory and create it if it
doesn't exist yet. The flake will be created from a default template.
For more detailed information, visit: https://docs.clan.lol/getting-started
For more detailed information, visit: {help_hyperlink("getting-started", "https://docs.clan.lol/getting-started")}
"""
),
formatter_class=argparse.RawTextHelpFormatter,
@ -185,7 +186,7 @@ For more detailed information, visit: https://docs.clan.lol/getting-started
help="ssh to a remote machine",
description="ssh to a remote machine",
epilog=(
"""
f"""
This subcommand allows seamless ssh access to the nixos-image builders.
Examples:
@ -195,7 +196,7 @@ Examples:
the json string. [JSON] can either be a json formatted string itself, or point
towards a file containing the deployment information
For more detailed information, visit: https://docs.clan.lol/getting-started/deploy
For more detailed information, visit: {help_hyperlink("deploy", "https://docs.clan.lol/getting-started/deploy")}
"""
),
formatter_class=argparse.RawTextHelpFormatter,
@ -207,7 +208,7 @@ For more detailed information, visit: https://docs.clan.lol/getting-started/depl
help="manage secrets",
description="manage secrets",
epilog=(
"""
f"""
This subcommand provides an interface to secret facts.
Examples:
@ -219,7 +220,7 @@ Examples:
$ clan secrets get [SECRET]
Will display the content of the specified secret.
For more detailed information, visit: https://docs.clan.lol/getting-started/secrets/
For more detailed information, visit: {help_hyperlink("secrets", "https://docs.clan.lol/getting-started/secrets")}
"""
),
formatter_class=argparse.RawTextHelpFormatter,
@ -231,7 +232,7 @@ For more detailed information, visit: https://docs.clan.lol/getting-started/secr
help="manage facts",
description="manage facts",
epilog=(
"""
f"""
This subcommand provides an interface to facts of clan machines.
Facts are artifacts that a service can generate.
@ -256,7 +257,7 @@ Examples:
This is especially useful for resetting certain passwords while leaving the rest
of the facts for a machine in place.
For more detailed information, visit: https://docs.clan.lol/getting-started/secrets/
For more detailed information, visit: {help_hyperlink("secrets", "https://docs.clan.lol/getting-started/secrets")}
"""
),
formatter_class=argparse.RawTextHelpFormatter,
@ -268,7 +269,7 @@ For more detailed information, visit: https://docs.clan.lol/getting-started/secr
help="manage machines and their configuration",
description="manage machines and their configuration",
epilog=(
"""
f"""
This subcommand provides an interface to machines managed by clan.
Examples:
@ -283,7 +284,7 @@ Examples:
$ clan machines install [MACHINES] [TARGET_HOST]
Will install the specified machine [MACHINE], to the specified [TARGET_HOST].
For more detailed information, visit: https://docs.clan.lol/getting-started/deploy
For more detailed information, visit: {help_hyperlink("deploy", "https://docs.clan.lol/deploy")}
"""
),
formatter_class=argparse.RawTextHelpFormatter,
@ -314,7 +315,7 @@ For more detailed information, visit: https://docs.clan.lol/getting-started/depl
help="query state information about machines",
description="query state information about machines",
epilog=(
"""
f"""
This subcommand provides an interface to the state managed by clan.
State can be folders and databases that modules depend on managed by clan.
@ -334,7 +335,7 @@ Examples:
$ clan state list [MACHINE]
List state of the machines managed by clan.
For more detailed information, visit: https://docs.clan.lol/getting-started/backups
For more detailed information, visit: {help_hyperlink("getting-started", "https://docs.clan.lol/backups")}
"""
),
formatter_class=argparse.RawTextHelpFormatter,

View File

@ -1,6 +1,7 @@
# !/usr/bin/env python3
import argparse
from ..hyperlink import help_hyperlink
from .check import register_check_parser
from .generate import register_generate_parser
from .list import register_list_parser
@ -20,7 +21,7 @@ def register_parser(parser: argparse.ArgumentParser) -> None:
"check",
help="check if facts are up to date",
epilog=(
"""
f"""
This subcommand allows checking if all facts are up to date.
Examples:
@ -29,7 +30,7 @@ Examples:
Will check facts for the specified machine.
For more detailed information, visit: https://docs.clan.lol/getting-started/secrets/
For more detailed information, visit: {help_hyperlink("secrets", "https://docs.clan.lol/getting-started/secrets")}
"""
),
formatter_class=argparse.RawTextHelpFormatter,
@ -40,7 +41,7 @@ For more detailed information, visit: https://docs.clan.lol/getting-started/secr
"list",
help="list all facts",
epilog=(
"""
f"""
This subcommand allows listing all public facts for a specific machine.
The resulting list will be a json string with the name of the fact as its key
@ -48,9 +49,9 @@ and the fact itself as it's value.
This is how an example output might look like:
```
{
\u007b
"[FACT_NAME]": "[FACT]"
}
\u007d
```
Examples:
@ -59,7 +60,7 @@ Examples:
Will list facts for the specified machine.
For more detailed information, visit: https://docs.clan.lol/getting-started/secrets/
For more detailed information, visit: {help_hyperlink("secrets", "https://docs.clan.lol/getting-started/secrets")}
"""
),
formatter_class=argparse.RawTextHelpFormatter,
@ -70,7 +71,7 @@ For more detailed information, visit: https://docs.clan.lol/getting-started/secr
"generate",
help="generate public and secret facts for machines",
epilog=(
"""
f"""
This subcommand allows control of the generation of facts.
Often this function will be invoked automatically on deploying machines,
but there are situations the user may want to have more granular control,
@ -99,7 +100,7 @@ Examples:
This is especially useful for resetting certain passwords while leaving the rest
of the facts for a machine in place.
For more detailed information, visit: https://docs.clan.lol/getting-started/secrets/
For more detailed information, visit: {help_hyperlink("secrets", "https://docs.clan.lol/getting-started/secrets")}
"""
),
formatter_class=argparse.RawTextHelpFormatter,
@ -110,7 +111,7 @@ For more detailed information, visit: https://docs.clan.lol/getting-started/secr
"upload",
help="upload secrets for machines",
epilog=(
"""
f"""
This subcommand allows uploading secrets to remote machines.
If using sops as a secret backend it will upload the private key to the machine.
@ -123,7 +124,7 @@ Examples:
$ clan facts upload [MACHINE]
Will upload secrets to a specific machine.
For more detailed information, visit: https://docs.clan.lol/getting-started/secrets/
For more detailed information, visit: {help_hyperlink("secrets", "https://docs.clan.lol/getting-started/secrets")}
"""
),
formatter_class=argparse.RawTextHelpFormatter,

View File

@ -0,0 +1,41 @@
# Implementation of OSC8
def hyperlink(text: str, url: str) -> str:
"""
Generate OSC8 escape sequence for hyperlinks.
Args:
url (str): The URL to link to.
text (str): The text to display.
Returns:
str: The formatted string with an embedded hyperlink.
"""
esc = "\033"
return f"{esc}]8;;{url}{esc}\\{text}{esc}]8;;{esc}\\"
def hyperlink_same_text_and_url(url: str) -> str:
"""
Keep the description and the link the same to support legacy terminals.
"""
return hyperlink(url, url)
def help_hyperlink(description: str, url: str) -> str:
import sys
"""
Keep the description and the link the same to support legacy terminals.
"""
if sys.argv[0].__contains__("docs.py"):
return docs_hyperlink(description, url)
else:
return hyperlink_same_text_and_url(url)
def docs_hyperlink(description: str, url: str) -> str:
"""
Returns a markdown hyperlink
"""
return f"[{description}]({url})"

View File

@ -105,8 +105,9 @@ def epilog_to_md(text: str) -> str:
md += "\n"
md += "\n"
else:
if contains_https_link(line):
line = convert_to_markdown_link(line)
# TODO: check, if the link is already a markdown link, only convert if not
# if contains_https_link(line):
# line = convert_to_markdown_link(line)
md += line
md += "\n"
else: