#!/usr/bin/env python import sys from typing import Sequence, Optional from pathlib import Path import contextlib import click from bs4 import BeautifulSoup, Doctype, Tag user_has_lxml = False try: import lxml # type: ignore[import] # noqa: F401 user_has_lxml = True except Exception: pass @click.command() @click.option( "--meta-charset", "_charset", default="utf-8", show_default=True, help="add default meta charset", ) @click.option( "--meta-viewport", "_viewport", help="add default viewport", show_default=True, default="width=device-width, initial-scale=1.0, user-scalable=yes", ) @click.option( "-a", "--add", type=click.Choice(["css-pre-wrap", "css-dark-mode"]), multiple=True, help="flags to add additional features", default=(), ) @click.option( "--raw-css", type=str, help="add raw CSS", default=None, ) @click.argument( "INPUT_FILE", type=click.Path(exists=True, allow_dash=True, path_type=Path), default=None, required=False, ) def main( input_file: Optional[Path], _charset: str, _viewport: str, raw_css: Optional[str], add: Sequence[str], ) -> None: """ A script to create a sensible element for HTML pages. data is typically piped into this, e.g. from something that emits HTML: \b pandoc ./README.md | html-head -a css-dark-mode \b cat README.txt | pygmentize -f html | html-head ... This doesn't affect other data already present in head, it only updates values if they are not present, can safely be used multiple times: \b ... | html-head -a css-dark-mode | ... | html-head ... \b css-pre-wrap: adds CSS to convert
 tags to wrap text
    css-dark-mode:
        adds CSS to convert the page to dark mode
    """
    text = (
        sys.stdin.read()
        if input_file is None or str(input_file) == "-"
        else input_file.read_text()
    )
    soup = BeautifulSoup(text, "lxml" if user_has_lxml else "html.parser")
    # find head tag, or create it and insert with good defaults
    assert soup.body is not None
    maybe_head = soup.head
    head: Tag
    if maybe_head is None:
        head = soup.new_tag("head")
        soup.body.insert_before(head)
    else:
        head = maybe_head
    assert head is not None
    meta_tags = head.find_all("meta")
    if not any(("charset" in getattr(tag, "attrs", {}) for tag in meta_tags)):
        head.append(soup.new_tag("meta", attrs={"charset": _charset}))
    if not any(
        ("viewport" == getattr(tag, "attrs", {}).get("name") for tag in meta_tags)
    ):
        head.append(
            soup.new_tag("meta", attrs={"name": "viewport", "content": _viewport})
        )
    if "css-pre-wrap" in add:
        prewrap = soup.new_tag("style")
        prewrap.string = "pre{white-space:pre-wrap;white-space:-moz-pre-wrap;white-space:-pre-wrap;white-space:-o-pre-wrap;word-wrap:break-word}"
        head.append(prewrap)
    if "css-dark-mode" in add:
        darkmode = soup.new_tag("style")
        darkmode.string = "body{background-color:#1b1b1b;color:#e7e8eb}a{color:#3387cc}"
        head.append(darkmode)

    if raw_css:
        new_styles = soup.new_tag("style")
        new_styles.string = raw_css
        head.append(new_styles)

    if len([a for a in soup.children if isinstance(a, Doctype)]) == 0:
        click.echo("")

    click.echo(str(soup).strip())


if __name__ == "__main__":
    with contextlib.suppress(KeyboardInterrupt):
        main()