From edd0e6668f00a6c1e7fe1c8ac2b4d9cbac211215 Mon Sep 17 00:00:00 2001 From: Thomas Walker Lynch Date: Fri, 13 Mar 2026 11:03:51 +0000 Subject: [PATCH] today has been omitted due to brevity missing content put back --- consumer/release/{ => RT}/document/setup.js | 2 +- .../{ => RT}/document/style_manual.html | 34 ++ .../release/RT/layout/article_tech_ref.js | 75 +++- developer/authored/RT/document/setup.js | 4 + .../authored/RT/document/style_manual.html | 354 ++++++++++++++++++ .../authored/RT/layout/article_tech_ref.js | 75 +++- developer/tool/promote | 311 +++++++++++++++ document/style_manual.html | 34 ++ 8 files changed, 884 insertions(+), 5 deletions(-) rename consumer/release/{ => RT}/document/setup.js (89%) rename consumer/release/{ => RT}/document/style_manual.html (87%) create mode 100644 developer/authored/RT/document/setup.js create mode 100644 developer/authored/RT/document/style_manual.html create mode 100755 developer/tool/promote diff --git a/consumer/release/document/setup.js b/consumer/release/RT/document/setup.js similarity index 89% rename from consumer/release/document/setup.js rename to consumer/release/RT/document/setup.js index bf2554a..343de0f 100644 --- a/consumer/release/document/setup.js +++ b/consumer/release/RT/document/setup.js @@ -1,4 +1,4 @@ -window.RT_REPO_ROOT = "../../.."; +window.RT_REPO_ROOT = "../../../../"; document.write(''); document.write(''); document.write(''); diff --git a/consumer/release/document/style_manual.html b/consumer/release/RT/document/style_manual.html similarity index 87% rename from consumer/release/document/style_manual.html rename to consumer/release/RT/document/style_manual.html index 7503831..befc746 100644 --- a/consumer/release/document/style_manual.html +++ b/consumer/release/RT/document/style_manual.html @@ -315,6 +315,40 @@ + +

RT Conventions

+

Headings are first letter capitalized. Remaining words are as they would be in English prose.

+ +

Exercises

+ +
    +
  1. +

    + Term Occurrences: If an author tags a word with <RT-term> five times in a document, how many times will the term be visually decorated by the styling engine? How does a person force the engine to decorate a later occurrence? +

    +
  2. +
  3. +

    + Term Normalization: A person writes <RT-term>Parse Tree</RT-term> in paragraph one, and <RT-term>parse tree</RT-term> in paragraph two. Will the system assign a definition anchor to the second occurrence? +

    +
  4. +
  5. +

    + TOC Generation: What happens if one places an <RT-TOC> tag without a level attribute before the first heading of a section? +

    +
  6. +
  7. +

    + Code and Math Formatting: How does the RT system determine whether to render an <RT-code> or <RT-math> element inline with the text versus as a standalone block? +

    +
  8. +
  9. +

    + Pagination Logic: When the script bundles elements into an <RT-page> container, how does the soft limit pagination handle a heading that falls at the very bottom of the page capacity? +

    +
  10. +
+ diff --git a/consumer/release/RT/layout/article_tech_ref.js b/consumer/release/RT/layout/article_tech_ref.js index 795e2e1..67fba92 100644 --- a/consumer/release/RT/layout/article_tech_ref.js +++ b/consumer/release/RT/layout/article_tech_ref.js @@ -47,8 +47,79 @@ style.color = "var(--rt-content-main)"; } - // CSS injection for headers, lists, etc., goes here - // (Omitted for brevity, but carried over from the original file) + // CSS injection for headers, lists, and layout mapped from theme variables +// CSS injection for headers, lists, and layout mapped from theme variables + const style_node = document.createElement("style"); + style_node.innerHTML = ` + rt-article { + font-family: 'Noto Sans JP', Arial, sans-serif; + background-color: var(--rt-surface-0); + color: var(--rt-content-main); + padding: 2rem; + } + rt-article rt-page { + display: block; + padding: 3rem; + margin: 1.25rem auto; + max-width: 46.875rem; + background-color: var(--rt-surface-0); + box-shadow: 0 0 0.625rem var(--rt-brand-primary); + } + + /* --- HEADER CASCADE --- */ + rt-article h1 { + font-size: 1.5rem; + text-align: center; + color: var(--rt-brand-primary); + font-weight: 500; /* Softened from the default heavy bold */ + margin-top: 1.5rem; + line-height: 1.15; + } + rt-article h2 { + font-size: 1.25rem; + color: var(--rt-brand-secondary); + text-align: left; + margin-top: 2rem; + margin-left: 0; + } + rt-article h3 { + font-size: 1.125rem; + color: var(--rt-brand-tertiary); + text-align: left; + margin-top: 1.5rem; + margin-left: 4ch; /* Indented 4 characters */ + } + rt-article h4 { + font-size: 1.05rem; + color: var(--rt-content-main); + font-weight: 600; + text-align: left; + margin-top: 1.25rem; + margin-left: 8ch; /* Indented 8 characters */ + } + + /* --- BODY TEXT (Flush Left) --- */ + rt-article p, + rt-article ul, + rt-article ol { + color: var(--rt-content-main); + text-align: justify; + margin-bottom: 1rem; + margin-left: 0; + } + rt-article li { + margin-bottom: 0.5rem; + } + + /* --- CODE FORMATTING --- */ + rt-article rt-code { + font-family: 'Courier New', Courier, monospace; + background-color: var(--rt-surface-code); + padding: 0.125rem 0.25rem; + color: var(--rt-content-main); + } + `; + document.head.appendChild(style_node); }; // 3. The Execution Sequence diff --git a/developer/authored/RT/document/setup.js b/developer/authored/RT/document/setup.js new file mode 100644 index 0000000..343de0f --- /dev/null +++ b/developer/authored/RT/document/setup.js @@ -0,0 +1,4 @@ +window.RT_REPO_ROOT = "../../../../"; +document.write(''); +document.write(''); +document.write(''); diff --git a/developer/authored/RT/document/style_manual.html b/developer/authored/RT/document/style_manual.html new file mode 100644 index 0000000..befc746 --- /dev/null +++ b/developer/authored/RT/document/style_manual.html @@ -0,0 +1,354 @@ + + + + + RT Style System: Reference Manual + + + + + + + + + + +

Table of Custom Tags

+ +

Style Tag Reference

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TagDescription
<RT-article>Article container.
<RT-title> + Title block and metadata. +
<RT-TOC>Generates TOC.
<RT-term>Conventional term.
<RT-term-em>Forces emphasis for a term even after first occurrence.
<RT-neologism>Project specific term.
<RT-neologism-em>Forces emphasis for a neologism even after first occurrence.
<RT-code>Code span or code block.
<RT-math>Inline or block math.
<RT-page>Automatically inserted pagination tag.
+ +

Architecture Overview

+

+ The RT Style System is a client-side, JavaScript-driven publishing framework designed to turn raw HTML into high-readability technical documentation. Unlike standard CSS frameworks, RT uses JavaScript to handle complex layout tasks like ink-ratio balancing and dynamic pagination. +

+ +

Pulling style files into a document

+

Put `setup.js` in the directory, and include it at the top of the document, + `setup.js` points at the style files and is installation specific.

+ + +

Semantic Tags

+

+ The system relies on a specific set of custom tags in the RT- namespace to separate structure from presentation. +

+ +

Terminology

+ +

Conventional Terms

+

+ Use <RT-term> for standard, industry accepted technical terms. The system decorates only the first occurrence of each unique term so that the first appearance functions as a definition point, and later appearances do not overload the page with styling. +

+ + + The Singleton Pattern restricts instantiation... + + +

+ Renders as: The Singleton Pattern restricts instantiation... +

+ +

Neologisms

+

+ Use <RT-neologism> for terms invented specifically for the current document or project. Neologisms are styled more strongly than conventional terms, visually distinguishing "jargon you should know" from "jargon we just made up." +

+ + + We define the Hyper Tape as a construct... + + +

+ Renders as: We define the Hyper Tape as a construct... +

+ +

First Occurrence Rule

+

+ The term system is intentionally conservative. For the tags <RT-term> and <RT-neologism>, only the first occurrence of a unique term is decorated. Subsequent mentions are rendered as normal prose. +

+ +

+ Uniqueness is tracked by normalizing the term text (trimmed, then lowercased). This means that Symbol and symbol count as the same term. +

+ +

Forced Emphasis Variants

+

+ Sometimes a later mention of a term should be emphasized again. For that purpose, the system provides explicit emphasis tags: +

+ + + +

+ These variants are always decorated, even if the term appeared earlier. +

+ +

Automatic Definition Anchors

+

+ For first occurrences, the term module automatically assigns an id attribute if one does not already exist. This creates stable anchors for future indexing and linking. +

+ + + We define a Symbol as... + + +

+ The first occurrence will be given an id similar to def-symbol. For neologisms, an additional marker is used, for example def-neo-hyper-tape. +

+ +

Technical Content

+ +

Code

+

+ Use <RT-code>. If placed inline, it acts like a span. If placed as a block (with newlines), it acts like a pre formatted block with a theme aware border. +

+ + + # Block Code Example + def hello(): + return "World" + + +

Mathematics

+

+ Use <RT-math>. The system auto detects if it is a block equation or inline variable and wraps it in MathJax delimiters. +

+

+ Inline: Let x be the input. +

+

+ Block: +

+ + f(x) = \sum_{i=0}^{n} x_i + + +

Navigation & Layout

+ +

Automatic Table of Contents

+

+ Use <RT-TOC> to insert a generated table of contents. The tag scans the document forward from its current position to collect headings. +

+ +

Explicit Mode

+

+ Use the level="N" attribute to target a specific heading depth. +

+ + +

Implicit Mode

+

+ If no level is specified, the TOC scans backwards to find the nearest heading (for example H1) and assumes you want to collect children one level deeper (for example H2). +

+

+ Note: Implicit mode can fail if placed before the first heading of a section. Use explicit levels for robust results. +

+ +

The Title Block

+

+ Use <RT-title> as the first element in your <body> (before the article container). This tag generates a standardized, styled header block with the document title and metadata. +

+ +

Attributes

+ + +

Example

+ + + + + +

+ Renders as: A centered, high contrast H1 followed by a serif styled metadata row containing the author and date. +

+ +

The Article Container

+

+ The root element must be <RT-article>. This is the boundary for the pagination logic. +

+ +

Pagination

+

+ The script paginate_by_element.js scans the article. It calculates the height of every element (including margins) and bundles them into <RT-page> elements. +

+

+ Soft Limit Pagination: The system attempts to keep headers with their following paragraphs. It will break a page early rather than stranding a header at the bottom. +

+ +

Debugging

+ +

Debug Tokens

+

+ RT provides a lightweight debug logging system in utility.js. Logging is controlled by a set of active debug tokens. Each log message is assigned a token, and the message prints only if that token is enabled. +

+ +

+ Examples of common tokens include style, layout, pagination, selector, config, and term. +

+ +

How Logging is Gated

+

+ Normal log and warning output are gated. The methods debug.log(token,message) and debug.warn(token,message) will print only when the token exists in debug.active_tokens. +

+ +

+ This prevents the console from being flooded during normal use, while still allowing deep visibility during development. +

+ +

Errors are Always Printed

+

+ Errors are treated differently. The method debug.error(token,message) always prints, regardless of token state. These messages represent failures that require attention. +

+ +

Enabling and Disabling Tokens

+

+ Tokens may be enabled or disabled in two ways: by editing the active_tokens set in utility.js, or at runtime by calling: +

+ + + window.StyleRT.debug.enable('term') + window.StyleRT.debug.disable('term') + + +

+ For example, the term system (RT_term.js) uses the term token. When that token is enabled, the module will print messages describing how terms were detected and which term definitions were assigned IDs. +

+ +

Themes

+

+ The system supports hot swapping themes by changing the script import in the head. +

+ + +

Manifest

+ + 1. style_orchestrator.js (Example/default footer script) + 2. utility.js (Math/Color physics) + 3. article_tech_ref.js (Typography and CSS injection) + 4. RT_code.js (Code block logic) + 5. RT_math.js (MathJax wrapper) + 6. RT_term.js (Term styling) + 7. RT_TOC.js (Navigation generator) + 8. paginate_by_element.js (Page splitter) + 9. page_fixed_glow.js (Visual page container) + + + + + +

RT Conventions

+

Headings are first letter capitalized. Remaining words are as they would be in English prose.

+ +

Exercises

+ +
    +
  1. +

    + Term Occurrences: If an author tags a word with <RT-term> five times in a document, how many times will the term be visually decorated by the styling engine? How does a person force the engine to decorate a later occurrence? +

    +
  2. +
  3. +

    + Term Normalization: A person writes <RT-term>Parse Tree</RT-term> in paragraph one, and <RT-term>parse tree</RT-term> in paragraph two. Will the system assign a definition anchor to the second occurrence? +

    +
  4. +
  5. +

    + TOC Generation: What happens if one places an <RT-TOC> tag without a level attribute before the first heading of a section? +

    +
  6. +
  7. +

    + Code and Math Formatting: How does the RT system determine whether to render an <RT-code> or <RT-math> element inline with the text versus as a standalone block? +

    +
  8. +
  9. +

    + Pagination Logic: When the script bundles elements into an <RT-page> container, how does the soft limit pagination handle a heading that falls at the very bottom of the page capacity? +

    +
  10. +
+ +
+ + diff --git a/developer/authored/RT/layout/article_tech_ref.js b/developer/authored/RT/layout/article_tech_ref.js index 795e2e1..67fba92 100644 --- a/developer/authored/RT/layout/article_tech_ref.js +++ b/developer/authored/RT/layout/article_tech_ref.js @@ -47,8 +47,79 @@ style.color = "var(--rt-content-main)"; } - // CSS injection for headers, lists, etc., goes here - // (Omitted for brevity, but carried over from the original file) + // CSS injection for headers, lists, and layout mapped from theme variables +// CSS injection for headers, lists, and layout mapped from theme variables + const style_node = document.createElement("style"); + style_node.innerHTML = ` + rt-article { + font-family: 'Noto Sans JP', Arial, sans-serif; + background-color: var(--rt-surface-0); + color: var(--rt-content-main); + padding: 2rem; + } + rt-article rt-page { + display: block; + padding: 3rem; + margin: 1.25rem auto; + max-width: 46.875rem; + background-color: var(--rt-surface-0); + box-shadow: 0 0 0.625rem var(--rt-brand-primary); + } + + /* --- HEADER CASCADE --- */ + rt-article h1 { + font-size: 1.5rem; + text-align: center; + color: var(--rt-brand-primary); + font-weight: 500; /* Softened from the default heavy bold */ + margin-top: 1.5rem; + line-height: 1.15; + } + rt-article h2 { + font-size: 1.25rem; + color: var(--rt-brand-secondary); + text-align: left; + margin-top: 2rem; + margin-left: 0; + } + rt-article h3 { + font-size: 1.125rem; + color: var(--rt-brand-tertiary); + text-align: left; + margin-top: 1.5rem; + margin-left: 4ch; /* Indented 4 characters */ + } + rt-article h4 { + font-size: 1.05rem; + color: var(--rt-content-main); + font-weight: 600; + text-align: left; + margin-top: 1.25rem; + margin-left: 8ch; /* Indented 8 characters */ + } + + /* --- BODY TEXT (Flush Left) --- */ + rt-article p, + rt-article ul, + rt-article ol { + color: var(--rt-content-main); + text-align: justify; + margin-bottom: 1rem; + margin-left: 0; + } + rt-article li { + margin-bottom: 0.5rem; + } + + /* --- CODE FORMATTING --- */ + rt-article rt-code { + font-family: 'Courier New', Courier, monospace; + background-color: var(--rt-surface-code); + padding: 0.125rem 0.25rem; + color: var(--rt-content-main); + } + `; + document.head.appendChild(style_node); }; // 3. The Execution Sequence diff --git a/developer/tool/promote b/developer/tool/promote new file mode 100755 index 0000000..a4d8888 --- /dev/null +++ b/developer/tool/promote @@ -0,0 +1,311 @@ +#!/usr/bin/env -S python3 -B +# -*- mode: python; coding: utf-8; python-indent-offset: 2; indent-tabs-mode: nil -*- + +import os ,sys ,shutil ,stat ,pwd ,grp ,glob ,tempfile ,filecmp + +HELP = """usage: promote {write|clean|ls|diff|help|dry write} + write Writes promoted files from scratchpad/made into consumer/made. Only updates newer files. + clean Remove all contents of the consumer/made directory. + ls List consumer/made as an indented tree: PERMS OWNER NAME. + diff List missing, orphaned, or out-of-sync files between scratchpad and consumer. + help Show this message. + dry write Preview what write would do without modifying the filesystem. +""" + +SETUP_MUST_BE = "developer/tool/setup" +DEFAULT_DIR_MODE = 0o700 +DEFAULT_FILE_MODE = 0o400 + +def exit_with_status(msg ,code=1): + print(f"release: {msg}" ,file=sys.stderr) + sys.exit(code) + +def assert_setup(): + setup_val = os.environ.get("SETUP" ,"") + if( setup_val != SETUP_MUST_BE ): + hint = ( + "SETUP is not 'developer/tool/setup'.\n" + "Enter the project with: . setup developer\n" + "That script exports: ROLE=developer; SETUP=$ROLE/tool/setup" + ) + exit_with_status(f"bad environment: SETUP='{setup_val}'. {hint}") + +def repo_home(): + rh = os.environ.get("REPO_HOME") + if( not rh ): + exit_with_status("REPO_HOME not set") + return rh + +def dpath(*parts): + return os.path.join( + repo_home() + ,"developer" + ,*parts + ) + +def cpath(*parts): + return os.path.join( + repo_home() + ,"consumer" + ,"made" + ,*parts + ) + +def dev_root(): + return dpath() + +def consumer_root(): + return cpath() + +def _display_src(p_abs: str) -> str: + try: + if( os.path.commonpath([dev_root()]) == os.path.commonpath([dev_root() ,p_abs]) ): + return os.path.relpath(p_abs ,dev_root()) + except Exception: + pass + return p_abs + +def _display_dst(p_abs: str) -> str: + try: + rel = os.path.relpath( + p_abs + ,consumer_root() + ) + rel = "" if rel == "." else rel + return "$REPO_HOME/consumer/made" + ("/" + rel if rel else "") + except Exception: + return p_abs + +def ensure_mode(path_str ,mode): + try: os.chmod(path_str ,mode) + except Exception: pass + +def ensure_dir(path_str ,mode=DEFAULT_DIR_MODE ,dry=False): + if( dry ): + if( not os.path.isdir(path_str) ): + shown = _display_dst(path_str) if path_str.startswith(consumer_root()) else ( + os.path.relpath(path_str ,dev_root()) if path_str.startswith(dev_root()) else path_str + ) + print(f"(dry) mkdir -m {oct(mode)[2:]} '{shown}'") + return + os.makedirs(path_str ,exist_ok=True) + ensure_mode(path_str ,mode) + +def filemode(m): + try: return stat.filemode(m) + except Exception: return oct(m & 0o777) + +def owner_group(st): + try: return f"{pwd.getpwuid(st.st_uid).pw_name}:{grp.getgrgid(st.st_gid).gr_name}" + except Exception: return f"{st.st_uid}:{st.st_gid}" + +def list_tree(root_dp): + if( not os.path.isdir(root_dp) ): + return + + entries = [] + def gather(path_str ,depth ,is_root): + try: + it = list(os.scandir(path_str)) + except FileNotFoundError: + return + dirs = [TM_e for TM_e in it if TM_e.is_dir(follow_symlinks=False)] + files = [TM_e for TM_e in it if not TM_e.is_dir(follow_symlinks=False)] + dirs.sort(key=lambda TM_e: TM_e.name) + files.sort(key=lambda TM_e: TM_e.name) + + if( is_root ): + for TM_f in ( TM_e for TM_e in files if TM_e.name.startswith(".") ): + st = os.lstat(TM_f.path) + entries.append((False ,depth ,filemode(st.st_mode) ,owner_group(st) ,TM_f.name)) + for TM_d in dirs: + st = os.lstat(TM_d.path) + entries.append((True ,depth ,filemode(st.st_mode) ,owner_group(st) ,TM_d.name + "/")) + gather(TM_d.path ,depth + 1 ,False) + for TM_f in ( TM_e for TM_e in files if not TM_e.name.startswith(".") ): + st = os.lstat(TM_f.path) + entries.append((False ,depth ,filemode(st.st_mode) ,owner_group(st) ,TM_f.name)) + else: + for TM_d in dirs: + st = os.lstat(TM_d.path) + entries.append((True ,depth ,filemode(st.st_mode) ,owner_group(st) ,TM_d.name + "/")) + gather(TM_d.path ,depth + 1 ,False) + for TM_f in files: + st = os.lstat(TM_f.path) + entries.append((False ,depth ,filemode(st.st_mode) ,owner_group(st) ,TM_f.name)) + + gather(root_dp ,1 ,True) + + ogw = 0 + for TM_isdir ,TM_depth ,TM_perms ,TM_ownergrp ,TM_name in entries: + if( len(TM_ownergrp) > ogw ): + ogw = len(TM_ownergrp) + + print("consumer/made/") + for TM_isdir ,TM_depth ,TM_perms ,TM_ownergrp ,TM_name in entries: + indent = " " * TM_depth + print(f"{TM_perms} {TM_ownergrp:<{ogw}} {indent}{TM_name}") + +def copy_one(src_abs ,dst_abs ,mode ,dry=False): + src_show = _display_src(src_abs) + dst_show = _display_dst(dst_abs) + parent = os.path.dirname(dst_abs) + os.makedirs(parent ,exist_ok=True) + + if( dry ): + if( os.path.exists(dst_abs) ): + print(f"(dry) unlink '{dst_show}'") + print(f"(dry) install -m {oct(mode)[2:]} -D '{src_show}' '{dst_show}'") + return + + fd ,tmp_path = tempfile.mkstemp(prefix=".tmp." ,dir=parent) + try: + with os.fdopen(fd ,"wb") as tmpf, open(src_abs ,"rb") as sf: + shutil.copyfileobj(sf ,tmpf) + tmpf.flush() + os.chmod(tmp_path ,mode) + os.replace(tmp_path ,dst_abs) + finally: + try: + if( os.path.exists(tmp_path) ): + os.unlink(tmp_path) + except Exception: + pass + + print(f"+ install -m {oct(mode)[2:]} '{src_show}' '{dst_show}'") + +def cmd_write(dry=False): + assert_setup() + ensure_dir(cpath() ,DEFAULT_DIR_MODE ,dry=dry) + + src_root = dpath( + "scratchpad" + ,"made" + ) + if( not os.path.isdir(src_root) ): + exit_with_status(f"cannot find developer scratchpad made at '{_display_src(src_root)}'") + + wrote = False + for TM_root ,TM_dirs ,TM_files in os.walk(src_root): + TM_dirs.sort() + TM_files.sort() + for TM_fn in TM_files: + src_abs = os.path.join(TM_root ,TM_fn) + rel = os.path.relpath(src_abs ,src_root) + dst_abs = os.path.join(cpath() ,rel) + + if( os.path.exists(dst_abs) ): + # Use content comparison instead of timestamps + if( filecmp.cmp(src_abs ,dst_abs ,shallow=False) ): + continue + + st = os.stat(src_abs) + is_exec = st.st_mode & stat.S_IXUSR + mode = 0o500 if is_exec else 0o400 + + copy_one( + src_abs + ,dst_abs + ,mode + ,dry=dry + ) + wrote = True + + if( not wrote ): + print(f"(info) nothing new to promote from {_display_src(src_root)}") + +def cmd_diff(): + assert_setup() + dst_root = cpath() + src_root = dpath( + "scratchpad" + ,"made" + ) + + src_files = set() + if( os.path.isdir(src_root) ): + for TM_root ,TM_dirs ,TM_files in os.walk(src_root): + for TM_fn in TM_files: + src_files.add(os.path.relpath(os.path.join(TM_root ,TM_fn) ,src_root)) + + dst_files = set() + if( os.path.isdir(dst_root) ): + for TM_root ,TM_dirs ,TM_files in os.walk(dst_root): + for TM_fn in TM_files: + dst_files.add(os.path.relpath(os.path.join(TM_root ,TM_fn) ,dst_root)) + + if( not src_files and not dst_files ): + print("No differences found. Both directories are empty or missing.") + return + + all_files = sorted(list(src_files | dst_files)) + found_diff = False + + for TM_rel in all_files: + if( TM_rel not in dst_files ): + print(f"Pending promotion (missing in consumer made): {TM_rel}") + found_diff = True + elif( TM_rel not in src_files ): + print(f"Orphaned in consumer made (missing in scratchpad): {TM_rel}") + found_diff = True + else: + src_abs = os.path.join(src_root ,TM_rel) + dst_abs = os.path.join(dst_root ,TM_rel) + + # Compare contents first + if( not filecmp.cmp(src_abs ,dst_abs ,shallow=False) ): + src_mtime = os.stat(src_abs).st_mtime + dst_mtime = os.stat(dst_abs).st_mtime + + # If they differ, check timestamps to infer direction + if( src_mtime > dst_mtime ): + print(f"Pending update (contents differ, newer in scratchpad): {TM_rel}") + else: + print(f"Contents differ (locally modified in consumer made): {TM_rel}") + found_diff = True + + if( not found_diff ): + print("No differences found. Consumer made matches developer scratchpad made.") + + +def cmd_clean(): + assert_setup() + consumer_root_dir = cpath() + if( not os.path.isdir(consumer_root_dir) ): + return + for TM_name in os.listdir(consumer_root_dir): + p = os.path.join(consumer_root_dir ,TM_name) + if( os.path.isdir(p) and not os.path.islink(p) ): + shutil.rmtree(p ,ignore_errors=True) + else: + try: os.unlink(p) + except FileNotFoundError: pass + +def CLI(): + if( len(sys.argv) < 2 ): + print(HELP) + return + + cmd = sys.argv[1] + args = sys.argv[2:] + + if( cmd == "write" ): + cmd_write(dry=False) + elif( cmd == "clean" ): + cmd_clean() + elif( cmd == "ls" ): + list_tree(cpath()) + elif( cmd == "diff" ): + cmd_diff() + elif( cmd == "help" ): + print(HELP) + elif( cmd == "dry" ): + if( args and args[0] == "write" ): + cmd_write(dry=True) + else: + print(HELP) + else: + print(HELP) + +if __name__ == "__main__": + CLI() diff --git a/document/style_manual.html b/document/style_manual.html index 7503831..befc746 100644 --- a/document/style_manual.html +++ b/document/style_manual.html @@ -315,6 +315,40 @@ + +

RT Conventions

+

Headings are first letter capitalized. Remaining words are as they would be in English prose.

+ +

Exercises

+ +
    +
  1. +

    + Term Occurrences: If an author tags a word with <RT-term> five times in a document, how many times will the term be visually decorated by the styling engine? How does a person force the engine to decorate a later occurrence? +

    +
  2. +
  3. +

    + Term Normalization: A person writes <RT-term>Parse Tree</RT-term> in paragraph one, and <RT-term>parse tree</RT-term> in paragraph two. Will the system assign a definition anchor to the second occurrence? +

    +
  4. +
  5. +

    + TOC Generation: What happens if one places an <RT-TOC> tag without a level attribute before the first heading of a section? +

    +
  6. +
  7. +

    + Code and Math Formatting: How does the RT system determine whether to render an <RT-code> or <RT-math> element inline with the text versus as a standalone block? +

    +
  8. +
  9. +

    + Pagination Logic: When the script bundles elements into an <RT-page> container, how does the soft limit pagination handle a heading that falls at the very bottom of the page capacity? +

    +
  10. +
+ -- 2.20.1