From ed8530999702e2363d8934dd1a9069af966744b8 Mon Sep 17 00:00:00 2001 From: Tab Atkins-Bittner Date: Fri, 28 Feb 2025 14:55:20 -0800 Subject: [PATCH] Add 'bikeshed outline' command, for generating a document outline. --- bikeshed/cli.py | 47 ++++++++++++++++++++++++--------------------- bikeshed/outline.py | 18 ++++++++++++----- docs/index.bs | 8 ++++++++ 3 files changed, 46 insertions(+), 27 deletions(-) diff --git a/bikeshed/cli.py b/bikeshed/cli.py index 6df754218c..67b797c839 100644 --- a/bikeshed/cli.py +++ b/bikeshed/cli.py @@ -373,15 +373,12 @@ def main() -> None: action="store_true", help="Finds HTML comments containing 'Big Text: foo' and turns them into comments containing 'foo' in big text.", ) - sourceParser.add_argument( - "--outline", - dest="outline", - action="store_true", - help="Generates a document outline and prints to stdout.", - ) sourceParser.add_argument("infile", nargs="?", default=None, help="Path to the source file.") sourceParser.add_argument("outfile", nargs="?", default=None, help="Path to the output file.") + outlineParser = subparsers.add_parser("outline", help="Generates an outline for the spec.") + outlineParser.add_argument("infile", nargs="?", default=None, help="Path to the source file.") + testParser = subparsers.add_parser("test", help="Tools for running Bikeshed's testsuite.") testParser.add_argument( "--rebase", @@ -495,6 +492,8 @@ def main() -> None: handleIssuesList(options) elif options.subparserName == "source": handleSource(options) + elif options.subparserName == "outline": + handleOutline(options) elif options.subparserName == "test": handleTest(options, extras) elif options.subparserName == "profile": @@ -683,23 +682,27 @@ def handleIssuesList(options: argparse.Namespace) -> None: def handleSource(options: argparse.Namespace) -> None: - if options.outline: - from . import outline - from .Spec import Spec + from . import fonts - with m.messagesSilent() as _: - doc = Spec(inputFilename=options.infile).preprocess() - m.say(outline.printOutline(doc)) - else: - from . import fonts - - try: - fontPath = config.scriptPath("fonts", "smallblocks.bsfont") - font = fonts.Font.fromPath(fontPath) - fonts.replaceComments(font=font, inputFilename=options.infile, outputFilename=options.outfile) - except Exception as e: - m.die(f"Error trying to embiggen text:\n{e}") - return + try: + fontPath = config.scriptPath("fonts", "smallblocks.bsfont") + font = fonts.Font.fromPath(fontPath) + fonts.replaceComments(font=font, inputFilename=options.infile, outputFilename=options.outfile) + except Exception as e: + m.die(f"Error trying to embiggen text:\n{e}") + return + + +def handleOutline(options: argparse.Namespace) -> None: + from . import outline + from .Spec import Spec + + doc = Spec(inputFilename=options.infile) + if not doc.valid: + return + with m.messagesSilent() as _: + doc.preprocess() + m.say(outline.printOutline(doc)) def handleTest(options: argparse.Namespace, extras: list[str]) -> None: diff --git a/bikeshed/outline.py b/bikeshed/outline.py index 4bc6eef3c7..c05464b8a6 100644 --- a/bikeshed/outline.py +++ b/bikeshed/outline.py @@ -1,6 +1,7 @@ from __future__ import annotations import dataclasses +import os from . import h, t from . import unsortedJunk as u # noqa: N813 @@ -18,13 +19,17 @@ def printOutline(doc: t.Spec) -> str: entries = generateOutline(doc) lineNumWidth = max(len(str(e.lineNum)) for e in entries) idWidth = max(len(str(e.id or "")) for e in entries) + consoleWidth = os.get_terminal_size().columns lines = [] for entry in entries: if entry.level == 2: prefix = "" else: prefix = " " * (entry.level - 2) - lines.append(f"{entry.lineNum:{lineNumWidth}} | #{entry.id:{idWidth}} | {prefix}{entry.text}") + line = f"{entry.lineNum:{lineNumWidth}} | #{entry.id:{idWidth}} | {prefix}{entry.text}" + if len(line) > consoleWidth: + line = line[: consoleWidth - 2] + "…" + lines.append(line) return "\n".join(lines) @@ -35,11 +40,14 @@ def generateOutline(doc: t.Spec) -> list[OutlineEntry]: id = el.get("id", None) level = int((h.tagName(el) or "h0")[1]) try: - num,_,rest = el.get("bs-line-number").partition(":") - lineNum = int(num) - int(rest) + lineNum = int(el.get("bs-line-number", "")) except: - continue + try: + num, _, rest = el.get("bs-line-number", "").partition(":") + lineNum = int(num) + int(rest) + except: # noqa: S112 + continue entries.append(OutlineEntry(text, id, level, lineNum)) return entries diff --git a/docs/index.bs b/docs/index.bs index b1cc93752c..4e5ce37353 100644 --- a/docs/index.bs +++ b/docs/index.bs @@ -989,6 +989,14 @@ The `source` command applies various transformations to the source document itse rather than producing a separate output document. Its options are described in [[#source]]. +`bikeshed outline` {#cli-outline} +--------------------------------- + +The `outline` command processes your document, +then outputs an outline to stdout, +listing the text of each heading +along with its source line number and ID. + `bikeshed issues-list` {#cli-issues-list} -----------------------------------------