2. Sphinx Doc

Sphinx Doc is a collection of scripts and templates to allow for simple setup, administration and output formatting of reStructuredText documents.

The focus is on providing a simple standalone README article and a book with chapters made from single README files.

It employs snippets(1) and the python package PyJsMo.

2.1. Documentation workflow

figure 2.1 shows the definitive state diagram for the documentation workflow. Some state transitions are triggered by a list of mandatory shell commands. For alternatives, e.g.,

\[\begin{split}\left\{\begin{array}{l} \mbox{touch file}\\ \mbox{sda automodule module}\\ \mbox{sda chapter add 'Chapter title'}\\ \end{array}\right.\end{split}\]

at least one command or an equivalent must be excuted. There is no exception to this requirement.

' -*- plantuml -*-
' Copyright (C) 2019, Wolfgang Scherer, <Wolfgang.Scherer at gmx.de>
'
' This file is part of Documentation Standard.
'
' Permission is granted to copy, distribute and/or modify this document
' under the terms of the GNU Free Documentation License, Version 1.3
' or any later version published by the Free Software Foundation;
' with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
' A copy of the license is included in the section entitled "GNU
' Free Documentation License".

@startuml
/' |:here:| '/

scale 1080 height

hide empty description

skinparam state {
  StartColor<<break>> DarkOrange
  BackgroundColor<<stable>> lime
  BackgroundColor<<unstable>> yellow
  BackgroundColor<<break>> DarkOrange
  EndColor<<break>> yellow
}

' skinparam linetype ortho
' skinparam linetype polyline

[*] --> UPDBOOK
State "Update Book" as UPDBOOK {
    State "local repo synchronized" as ULCLSYNC
    State "work directory synchronized" as UWDSYNC
    [*] --> ULCLSYNC : hg pull
    ULCLSYNC --> UWDSYNC : hg update
    ULCLSYNC --> UWDSYNC : hg merge
    UWDSYNC --> [*]
}
UPDBOOK : enter / hg pull
UPDBOOK : do / hg update
UPDBOOK : exit / hg merge
UPDBOOK --> STABLE <<stable>>

[*] --> GETBOOK
State "Get Book" as GETBOOK {
    note as GETBOOK_ACT
    {{
    partition "Clone book" {
    start
    :hg clone ""ssh:/""""/host/""""/path/book-dir"";
    stop
    }
    }}
    end note
}
GETBOOK : exit / hg clone ""ssh:/""""/host/""""/path/book-dir""
GETBOOK --> STABLE

[*] --> NEWBOOK
State "New Book" as NEWBOOK {
    [*] -->  INITIALIZED
        note as NEWBOOK_ACT
        {{
        partition "Init book" {
        :mkdir book-dir
        cd book-dir;
        :sda init 'Book title';
        :hg init;
        }
        }}
        end note
    INITIALIZED --> INITIALIZED : / - hg add\l\\ - hg forget
    INITIALIZED --> [*] : hg commit
}
NEWBOOK : enter / init book
NEWBOOK : do / ""hg add""
NEWBOOK : exit / ""hg commit""
NEWBOOK --> STABLE

STABLE --> MODIFYING <<unstable>> : emacs file\lvi file
MODIFYING --> PAUSING : adhoc\nstable point\nreached
PAUSING --> MODIFYING
MODIFYING --> COMMITTING : adhoc\nstable point\nreached
MODIFYING --> DISCARDED: hg revert file

STABLE --> ADDING <<unstable>> : / - touch file\l| - sda automodule module\l\\ - sda chapter add 'Chapter title'\lhg add file
ADDING --> COMMITTING : sda chapter clean
COMMITTING --> STABLE

ADDING  --> DISCARDED  : hg forget file\l/ - rm -f file\l| - rm -f doc/module.rst\l| - sda chapter rollback\l\\    rm -f README-chapter.txt
DISCARDED -right-> STABLE

State PAUSING {
    State "Doing something else" as BREAK <<break>> {
	note as PAUSING_ACT
	{{
	partition "Schedule other task(s)" {
	start
	:available for other tasks>
	:continue this job<
	stop
	}
	}}
	end note
    }
    State "local repo synchronized" as MLCLSYNC
    State "work directory synchronized" as MWDSYNC
    [*] <<break>> --> BREAK
    BREAK --> MLCLSYNC : hg pull
    MLCLSYNC --> MWDSYNC : hg update
    MLCLSYNC --> MWDSYNC : hg merge
    MWDSYNC --> [*] <<break>>
}

State COMMITTING {
    State "local repo synchronized" as LCLSYNC
    State "work directory synchronized" as WDSYNC
    State "local repo up to date" as LCLUP
    State "remote repo up to date" as RMTUP
    [*] --> LCLSYNC : hg pull
    LCLSYNC --> WDSYNC : hg update
    LCLSYNC --> WDSYNC : hg merge
    WDSYNC --> LCLUP : hg commit
    LCLUP --> RMTUP : hg push
    RMTUP --> [*]
}

' COMMITTING -[hidden]-> [*]
STABLE -right-> [*] : Stop\nWorking

' (progn (forward-line 1) (snip-insert-mode "puml.t.ide" t) (insert "\n"))
' :ide-menu: Emacs IDE Menu - Buffer @BUFFER@
' . M-x `eIDE-menu' ()(eIDE-menu "z")

' :ide: OCCUR-OUTLINE: Sections: `||: sec :||'
' . (x-symbol-tag-occur-outline "sec" '("||:" ":||") '("|:" ":|"))

' :ide: MENU-OUTLINE:  Sections `||: sec :||'
' . (x-eIDE-menu-outline "sec" '("||:" ":||") '("|:" ":|"))

' :ide: OCCUR-OUTLINE: Default `|||: sec :|||'
' . (x-symbol-tag-occur-outline)

' :ide: MENU-OUTLINE:  Default `|||: sec :|||'
' . (x-eIDE-menu-outline)

' :ide: +-#+
' . Buffer Outline Sections ()

' :ide: PLANTUML: HELP
' . (let ((args (concat (file-name-sans-extension (buffer-file-name)) ""))) (compile (concat "plantuml -h ")))

' :ide: PLANTUML: this file's EPS
' . (let ((args (concat (file-name-sans-extension (buffer-file-name)) ".eps"))) (compile (concat "plantuml -teps " (buffer-file-name))))

' :ide: PLANTUML: this file's PDF
' . (let ((args (concat (file-name-sans-extension (buffer-file-name)) ".pdf"))) (compile (concat "plantuml -tpdf " (buffer-file-name))))

' :ide: PLANTUML: this file's PNG
' . (let ((args (concat (file-name-sans-extension (buffer-file-name)) ".png"))) (compile (concat "plantuml -tpng " (buffer-file-name))))

' :ide: PLANTUML: this file's SVG
' . (let ((args (concat (file-name-sans-extension (buffer-file-name)) ".svg"))) (compile (concat "plantuml -tsvg " (buffer-file-name))))

' :ide: PLANTUML: this file's PNG + display
' . (let ((args (concat (file-name-sans-extension (buffer-file-name)) ".png"))) (compile (concat "plantuml -tpng " (buffer-file-name) " && display " args)))

' :ide: PLANTUML: this file's PNG + VIEW
' . (let ((args (concat (file-name-sans-extension (buffer-file-name)) ".png"))) (shell-command (concat "plantuml -tpng " (buffer-file-name) " ")) (view-file-other-window args))

' :ide: PLANTUML: this file's SVG + VIEW
' . (let ((args (concat (file-name-sans-extension (buffer-file-name)) ".svg"))) (shell-command (concat "plantuml -tsvg " (buffer-file-name) " ")) (view-file-other-window args))

' Local Variables:
' mode: plantuml
' mode: snip-minor
' snip-show-inactive: t
' snip-mode: plantuml
' truncate-lines: t
' comment-start: "'"
' comment-end: ""
' End:
@enduml

figure 2.1 Documentation workflow

2.2. Initialize documentation

2.2.1. New article

The command

sda chapter new 'Chapter title'

is roughly equivalent to

snn --mode rst --key title --value 'Chapter title' README-chapter-title.txt

2.2.2. New book

  • Make book directory

  • cd to book directory

  • Execute

    sda init "Book Title"
    

This creates an empty README.txt and a doc subdirectory for building the full version of a documentation book with chapters.

2.3. Documentation output formats

2.3.1. Article format

sda readme README.txt              # => README.html
sda readme --format pdf README.txt # => README.pdf

2.3.2. Book format

sda make html                      # => doc/_build/html/
sda make latexpdf                  # => doc/_build/latex/

sda view html                      # xdg-open 'doc/_build/html/index.html'
sda view pdf                       # xdg-open "$(  echo doc/_build/latex/*.aux | sed 's,\.aux$,\.pdf,;1q' )"

2.4. Update documentation template structure

|:todo:| add to glossary

  1. The book directory must not have any uncommitted changes.

  2. The book directory must be synchronized with master repository.

  3. The book at the book directory should build without warnings.

    If there are warnings, record them to be able to distinguish between old warnings and new warnings.

    sda make clean
    sda make html
    sda make pdf
    
  4. Update template framework (snippets) at the book directory

    sda update
    

    This creates a new sub-directory BOOK-DIR-update with a new documentation project using the title from the main README (see figure 2.2).

    @startuml /' a0 '/
skinparam padding 1
partition "Update README template structure"  {
start
:get **basename of working**
**directory** as update directory;
:get **title** from README.txt;
:* **create** update directory
* **change** to update directory;
:Keep original */.snippets//**;
:Initialize update directory
with */sphinx-doc-init.sh// title**;
:move_to_orig\ncompare updated files with original tree|
stop
}
@enduml

    figure 2.2 SphinxDoc - update template structure

    Any generated files in BOOK-DIR-update, that are not present in BOOK-DIR updated, are moved to the corresponding location. Files that are identical (ignoring copyright lines) are deleted. (see figure 2.3).

    @startuml /' a1 '/
skinparam padding 1
partition "move_to_orig - compare updated files with original tree"  {
start
while (for each file in directory) is (do)
    if (file **not** in orig tree) then (yes)
        :mv "${file}" ../"${file}";
    elseif (is a directory?) then (yes)
        :move_to_orig "${file}"|
    elseif (no diff?) then (yes)
        :rm "${file}";
    endif
endwhile
:remove empty directories;
stop
}
@enduml

    figure 2.3 SphinxDoc - compare updated files with original tree

  5. Files in BOOK-DIR-update that differ from files in BOOK-DIR must be merged manually with M-x ediff-directories or kdiff3(1).

    (let* ((project (file-name-base (directory-file-name default-directory)))
           (update (concat default-directory project "-update")))
      (ediff-directories update default-directory ""))
    
  6. Run a fresh build to detect any errors.

  7. Commit changes using the phrase template framework update (don’t forget adding new files).

  8. Push commits to master repository.

  9. Publish repository.

  10. Remove update directory.

2.5. Document administration

Document administration is performed with sda, a shortcut link to sphinx-doc-admin.sh.

@startuml /' a0 '/
skinparam padding 1
partition "sphinx-doc-admin.sh" {
start
floating note right
sphinx-doc-admin.sh - Sphinx based documenation administration

usage: sphinx-doc-admin.sh [OPTIONS] COMMAND [COMMAND-OPTIONS] [COMMAND-ARGS]

OPTIONS
-d, --doc-dir  DOCDIR
--debug                do not execute commands
-v, --verbose

COMMANDS
init       [OPTIONS] [PROJECT-NAME]
update     [OPTIONS]
readme     [OPTIONS] [FILE]
make       [ARGS]
view       [FORMAT-OR-FILE]
automodule MODULE-OR-FILE ...
chapter    [SUB-COMMAND] [ARGS]

doc-dirs   [OPTIONS] [SEARCH-DIR ..]
locate     [OPTIONS]

help

COMMAND MAKE
make       [ARGS]
Default target is //html//

COMMAND VIEW
view       [FORMAT-OR-FILE ..]
Formats are //html// and //pdf// (default: //html//).

COMMAND CHAPTER
chapter [SUB-COMMAND] [COMMON-OPTIONS] [ARGS]
COMMON-OPTIONS
| option              | args | description                                |
| -p, --preserve-case |      | do not lowercase title for filename suffix |
| -h, --help          |      | show help                                  |
chapter new TOPIC-or-FILENAME
Generate/rename "README-" FN-CHAPTER-TOPIC ".txt",
if it does not exist.
1. If TOPIC-or-FILENAME is the name of an existing file
- extract TOPIC from FILENAME
2. If --preserve-case is given,
- use TOPIC as CHAPTER-TOPIC, otherwise
- use TOPIC converted to lowercase as CHAPTER-TOPIC.

3. Construct FN-TOPIC by replacing all non-alpha characters
in CHAPTER-TOPIC with dashes "-" and squeezing multiple
dashes into a single dash.
4. Construct CHAPTER-FILENAME from FN-TOPIC as:
"README" "-" FN-TOPIC ".txt"

5. If CHAPTER-FILENAME exists
- if FILENAME exists
- if FILENAME is different from CHAPTER-FILENAME
- warn about existing CHAPTER-FILENAME for FILENAME
- warn about existing CHAPTER-FILENAME for TOPIC
- if FILENAME exists
- if FILENAME is different from CHAPTER-FILENAME
- rename FILENAME as CHAPTER-FILENAME
- Create new CHAPTER-FILENAME with title TOPIC.

chapter add CHAPTER-FILENAME-OR-TOPIC
In addition to creating README-CANONICAL-CHAPTER-TOPIC.txt like
//chapter new//, register appropriate entries in control files:

.hgignore
${opt_doc_dir}/index-contents.snip
${opt_doc_dir}/doc_defs_standalone.inc
${opt_doc_dir}/Makefile
${opt_doc_dir}/doc_defs_combined.inc
README-chapter-topic.txt

chapter rollback [COMMON-OPTIONS] [OPTIONS]
Restore documentation files from backups of last added
chapter

OPTIONS
| option      | args | description          |
| -f, --force |      | ignore missing files |

chapter clean
Delete documentation file backups of last added chapter

chapter remove CHAPTER-FILENAME-OR-TOPIC
Delete chapter from documentation files

find doc-dir directories containing conf.py

| option         | args | description                                    |
| -d, --doc-dirs |      | show doc directories (default)                 |
| -p, --projects |      | show project directories                       |
| -c, --clean    |      | remove backup and update directories (default) |
| -a, --all      |      | do not remove backup and update directories    |
end note
:configuration;
:option processing;
:Find directory with README.txt;
:determine command;
if (no command specified?) then (yes)
    :error message;
    :usage;
    end
endif
    if (command == init) then (yes)
    :call function
    command_init|
    elseif (command == update) then (yes)
    :call function
    command_update|
    elseif (command == readme) then (yes)
    :call function
    command_readme|
    elseif (command == make) then (yes)
    :call function
    command_make|
    elseif (command == view) then (yes)
    :call function
    command_view|
    elseif (command == automodule) then (yes)
    :call function
    command_automodule|
    elseif (command == chapter) then (yes)
    :call function
    command_chapter|
    elseif (command == doc-dirs) then (yes)
    :call function
    command_doc_dirs|
    elseif (command == locate) then (yes)
    :call function
    command_locate|
    elseif (command == help) then (yes)
    :call usage|
    else
    :error message;
    end
    endif
stop
} /' move before //stop//, if there are subsections '/
@enduml

2.5.1. Automodule files

Add automodule documentation files for python modules to the doc directory.

sda automodule MODULE-OR-FILE ...

@startuml /' a2 '/
skinparam padding 1
partition "automodule command" {
    start
    :set //--help// as default;
    :cd to //${opt_doc_dir}// directory;
    while (for each //module_or_file// argument) is (do)
        :construct module name
        - remove //.py//
        - translate ///// => //.//;
        if (automodule file exist) then (yes)
            :warning message;
        else
        :create automodule file;
        endif
    endwhile
    stop
}
@enduml

2.5.2. Chapters

Latest versions of the documentation have |:chapter:| symbol tags, which can be easily found with M-x symbol-tag-grep-find (usually defined as M-g).

Chapter administration entails a number of use cases:

@startuml /' u0 '/
skinparam padding 1
left to right direction
actor :User: as User
    usecase (generate new\nREADME-CTOPIC.txt from TOPIC\n[but do not integrate into book]) as CHPNEW
    usecase (generate new\nREADME-CTOPIC.txt\nfrom TOPIC\nand integrate into book) as CHPADD0
    usecase (integrate existing\nREADME-CTOPIC.txt) as CHPADD1
    usecase (a previous run\nof //sphinx-doc-admin.sh//\nwas interrupted) as CHPADDCONT
    usecase (some of the control files\nare already modified) as CTRLMOD
    usecase (run\n//chapter new 'TOPIC'//) as RCHAPNEWTOPIC
    usecase (run\n//chapter add README-CTOPIC.txt//) as RCHAPADDFILE
    usecase (update control files) as UPDCTRL
    User         --> CHPNEW
    User         --> CHPADD0
    User         --> CHPADD1
    User         --> CHPADDCONT
    User         --> CTRLMOD
    CHPNEW       --|> RCHAPNEWTOPIC
    CHPADD0 "1"  --|> RCHAPNEWTOPIC
    CHPADD0 "2"  --|> CHPADD1
    CHPADD1      --|> RCHAPADDFILE
    CHPADDCONT   --|> RCHAPADDFILE
    CTRLMOD      --|> RCHAPADDFILE
    RCHAPADDFILE --|> UPDCTRL
    usecase (rollback control files\nbefore commit with\n//chapter rollback//) as CHPROLLBACK
    User --> CHPROLLBACK
    usecase (delete control files with\n//chapter clean//) as CHPCLEAN
    User --> CHPCLEAN
    usecase (remove chapter reference\nfrom control files with\n//chapter remove FILEN-OR-TOPIC//) as CHPREMOVE
    User --> CHPREMOVE
@enduml

sda chapter SUB-COMMAND

@startuml /' a1 '/
skinparam padding 1
partition "chapter command" {
    start
    floating note right
    control files:
    * .hgignore
    * ${opt_doc_dir}/index-contents.snip
    * ${opt_doc_dir}/doc_defs_standalone.inc
    * ${opt_doc_dir}/Makefile
    * ${opt_doc_dir}/doc_defs_combined.inc
    end note
    if (no sub command specified?) then (yes)
        :error message;
        end
    endif
    if (sub command is valid?) then (yes)
        else
        :error message;
        end
        endif
    :cd to top directory with README.txt;
    if (sub command == new or sub command == add?) then (yes)
    if (//README-CANONICAL-CHAPTER-TOPIC.txt// does not exist in current directory?) then (yes)
        :snn //--mode// rst //--key// title //--value// 'Chapter topic' //README-CANONICAL-CHAPTER-TOPIC.txt//;
    endif
    endif
    if (sub command == add?) then (yes)
    while (for file in **control files**) is (do)
                if (chapter reference does\nnot exist in **file**) then (yes)
                    :write a backup
                    file **file-000**;
                    :put new file entry
                    at the right place;
                endif
    endwhile
    elseif (sub command == rollback?) then (yes)
    if (all backup files found?) then (yes)
        while (for each control file) is (do)
            :overwrite file with
            backup from file-000;
        endwhile
    else
        :error message;
        end
    endif
    elseif (sub command == clean?) then (yes)
    while (for each control file) is (do)
        :delete backup file-000;
    endwhile
    elseif (sub command == remove?) then (yes)
    if (chapter file does not exist?) then (yes)
        end
    endif
    while (for _file in FILES) is (do)
        :remove chapter entry from _file;
        if (there was an entry?) then (yes)
            if (there is no backup file?) then (yes)
                :make backup;
            endif
            :activate new _file;
        endif
    endwhile
    endif
stop
}
@enduml

2.5.2.1. Adding a chapter

The following steps are automatically performed with:

sda chapter add topic
  • Create a new README-topic.txt:

    snn --mode rst README-topic.txt
    
  • Add a new entry to the variable CHAPTERS in doc/Makefile:

    CHAPTERS += ../README-topic.txt
    
  • Add the chapter file base topic to the toctree directive in doc/index-contents.snip:

    .. toctree::
       :maxdepth: 1
    
       topic
    

    Add a rule to .hgignore:

    ^doc/topic\.rst\.auto$
    

    Define a document reference in doc/doc_defs_standalone.inc:

    .. |chapter-topic|            replace:: document :file:`README-topic`
    

    Define a chapter reference in doc/doc_defs_combined.inc:

    .. |chapter-topic|            replace:: chapter :doc:`topic`
    

2.5.3. View processed documents

sda view FORMAT-OR-FILE

sda view html
sda view pdf

@startuml /' a4 '/
skinparam padding 1
partition "view command" {
    start
    :set //html// as default view format;
    while (for each _format_or_file in FORMATS-OR-FILES) is (do)
        if (_format_or_file does **not** exist) then (yes)
            if (_format_or_file matches //html//) then (yes)
                :use //${opt_doc_dir}/_build/html/index.html// as file;
            elseif (_format_or_file matches //pdf//) then (yes)
                :use //${opt_doc_dir}/_build/latex/book.pdf// as file;
            elseif (_format_or_file matches //epub//) then (yes)
                :use //${opt_doc_dir}/_build/epub/book.epub// as file;
            endif
        endif
        if (_format_or_file exists) then (yes)
            :call xdg-open with _format_or_file;
        else
        :error message;
        endif
    endwhile
    stop
}
@enduml

2.5.4. Command handlers for backends

@startuml /' a3 '/
skinparam padding 1
partition "init command" {
    start
    :exec sphinx-doc-init.sh ${1+"$@"}|
    stop
}
partition "update command" {
    start
    :exec sphinx-doc-update.sh ${1+"$@"}|
    stop
}
partition "readme command" {
    start
    :exec sphinx-readme.sh --doc-dir "${opt_doc_dir}" ${1+"$@"}|
    stop
}
partition "make command" {
    start
    :set //html// as default target;
    :cd to //${opt_doc_dir}// directory;
    :call make(1) with args|
    stop
}
partition "doc-dirs command" {
    start
    :- find files conf.py
    - post-process and filter file names;
    stop
}
partition "locate command" {
    start
    :exec sphinx-doc-locate.sh ${1+"$@"}|
    stop
}
@enduml

2.6. Structural specification

  • reStructuredText is a markup language specification in the class of wiki markup languages. (Examples for other markup languages are HTML, TeX/LaTex, NROFF). reStructuredText is the official Python documentation markup.

  • UML is used for documenting programs. It is created from textual descriptions with PlantUML. See section 12, Unified Modeling Language for details.

  • Docutils is the reference library for translating reStructuredText markup into other formats like HTML/PDF/EPUB.

  • The document generator Sphinx extends Docutils and the reStructuredText specification with roles and directives. There are also various extensions to integrate other markup specifications (e.g. PlantUML, Pygments for highlighting). See section 14, Sphinx Documentation Generator for further details .

    The program sphinx-build(1) generates HTML/PDF/EPUB documentation from reStructuredText documents and doc strings of python(1) modules. It is also used in the command sda readme (sphinx-readme.sh) to generate standalone HTML/PDF/EPUB from a single README file.

@startuml
' |:here:|
hide circle
hide members
skinparam padding 1

!definelong GENERATORS
  +HTML()
  +PDF()
  +EPUB()
!enddefinelong

package "Specifications" as PSPEC {  /' |:here:||:sec:| '/
  class "UML"                     as UML
  class "UML Diagram"             as UMLDIA
  class "reStructuredText"        as RST

  UML <|.. UMLDIA : <<illustrates>>
}

package "Documents" as PDOC { /' |:sec:| '/
  class "Python <i>__</i>doc__"   as PYDOC
  class "README.txt"              as README
  class "Documentation"           as DOC

  PYDOC  "*" --o DOC
  README "*" --o DOC
}

package "Generators" as PGEN { /' |:sec:| '/

  object "PlantUML"                as PUML {
    PNG()
    SVG()
  }
  show PUML members

  object "Docutils"                as DUT {
    GENERATORS
  }
  show DUT members

  object "Sphinx"                  as SPH {
    +extension[]
    GENERATORS
  }
  show SPH members

  class "Generator" as GEN {
    generates()
  }
  show GEN methods

  DUT  ..|> GEN
  SPH  ..|> GEN
  DUT  <|-- SPH : <<extends>>
  PUML <..  SPH : <<integrates>>

}

package "Output" as POUT { /' |:sec:| '/
  object "README.html"              as RHTML
  object "index.html"               as IHTML
}

' |:here:||:sec:| Relations

UMLDIA <|.. PUML : <<implements>>

RST <|.. DUT : <<implements>>
RST --o  PYDOC
RST --o  README

DOC    <|.. IHTML
README <|.. RHTML

(README, RHTML) .. GEN
(DOC, IHTML) ..    GEN

' |:here:|
@enduml

2.6.1. README chapters

@startuml

skinparam padding 1

' |:here:| definitions

!define dir_top <i>dir</i> = .
!define dir_doc <i>dir</i> = doc
!define parts_eq <i>parts</i> =
!define dir_top_parts dir_top, parts_eq
!define dir_doc_parts dir_doc, parts_eq

' parts definitions

!definelong R_PARTS
  dir_top_parts
  - top
  - title
  - contents
  - abstract
  - body
  - defs
  - bottom
!enddefinelong

!definelong I_PARTS
  dir_doc_parts
  - top
  - title
  - abstract
  - index-contents.snip
  - index-header.snip
  - defs
  - index-footer.snip
  - bottom
!enddefinelong

!definelong O_PARTS
  dir_doc_parts
  - top
  - overview-header.snip
  - body
  - defs
  - overview-footer.snip
  - bottom
!enddefinelong

!definelong C_PARTS
  dir_doc_parts
  - top
  - title
  - abstract
  - chapter-header.snip
  - body
  - defs
  - chapter-footer.snip
  - bottom
!enddefinelong

package "Combined output" as OUTC { /' |:here:| '/
  object "**index.html**" as ih {
    dir = doc/_build/html
  }
  object "Document.pdf" as ip {
    dir = doc/_build/latex
  }
}

package "Single chapter output" as OUTS { /' |:sec:| '/
  object "README.pdf" as RP {
    dir_top
  }
  object "**README.html**" as RH {
    dir_top
  }
  object "README-topic1.html" as RH1 {
    dir_top
  }
  object "README-topic2.html" as RH2 {
    dir_top
  }
}

package "Chapters" as IC { /' |:sec:| '/
  object "**README.txt**" as R {
    R_PARTS
  }
  object "README-topic1.txt" as RT1 {
    R_PARTS
  }
  object "README-topic2.txt" as RT2 {
    R_PARTS
  }
}

package "Index" as PI { /' |:sec:| '/
  object "**index.rst**" as i {
    I_PARTS
  }
  object "toctree" as TT {
   - overview
   - topic1
   - topic2
  }
}

package "Generated chapters" as PC { /' |:sec:| '/
  object "overview.rst" as O {
    O_PARTS
  }
  object "topic1.rst" as t1 {
    C_PARTS
  }
  object "topic2.rst" as t2 {
    C_PARTS
  }
}

' |:here:| Helper Relations

ih  -[hidden] ip
ip  -[hidden] RP
RP  -[hidden] RH
RH  -[hidden] RH1
RH1 -[hidden] RH2

' |:here:| Single Chapter Output

RH  ..|> R   : < sphinx-build\nsda readme
RP  ..|> R   : < sphinx-build\nsda readme\n--format pdf
RH1 ..|> RT1 : < sphinx-build\nsda readme
RH2 ..|> RT2 : < sphinx-build\nsda readme

' |:sec:| Combined Documentation Chapters

R   <|..  i  : snippets\nsnr --key doc_index >
R   <|..  O  : snippets\nsnr --key doc_overview >
RT1 <|..  t1 : snippets\nsnr --key doc_chapter >
RT2 <|..  t2 : snippets\nsnr --key doc_chapter >

' |:sec:| Combined Documentation Output

ih ..|> i : < sphinx-build\nmake html
ip ..|> i : < sphinx-build\nmake latexpdf

' |:sec:| toctree references

i   o-    TT
TT  .u.>  O
TT  .u.>  t1
TT  .u.>  t2

' |:here:|

@enduml

2.6.2. README snippets

@startuml
skinparam padding 2
hide methods

!define SNIP <b><color:blue>rem</color></b>
!define SKIP <b><color:red>skip</color></b>
!define QUOTE <b><color:black>quote</color></b>
!define REM <b><color:black>rem</color></b>
!define INDENT <b><color:black>indent</color></b>

!definelong NO_OUT_BLOCKS
!enddefinelong

!definelong OUT_BLOCKS
!enddefinelong

package "README snippet setup" as RSS {

' |:here:|

class "rst_new" as RSNP {
 -- template aliases --
 snip_quote    : alias QUOTE / REM

 .. doc_index ..
 doc_index     : block alias SNIP / SKIP
 not_doc_index : block alias SKIP / SNIP
 di_indent     : alias INDENT / REM
 not_di_indent : alias REM / INDENT

 .. minimal ..
 minimal     : block alias SNIP / SKIP
 not_minimal : block alias SKIP / SNIP
}

hide RIND circle
hide RCHP circle
hide RMIN circle

class "README.txt (doc_index)" as RIND {
  doc_index     = SNIP
  not_doc_index = SKIP
  di_indent     = INDENT
  not_di_indent = REM
  minimal       = SKIP
  not_minimal   = SNIP
  snip_quote    = QUOTE
  -- output block aliases --
  .. doc type ..
  doc_standalone
  not_doc_standalone
  doc_index
  not_doc_index
  doc_overview
  not_doc_overview
  doc_chapter
  not_doc_chapter
  .. part ..
  part_top
  part_title
  part_contents
  part_abstract
  part_body
  part_defs
  part_bottom
}

class "README.txt (chapter)" as RCHP {
  doc_index     = SKIP
  not_doc_index = SNIP
  di_indent     = REM
  not_di_indent = INDENT
  minimal       = SKIP
  not_minimal   = SNIP
  snip_quote    = QUOTE
  -- output block aliases --
  .. doc type ..
  doc_standalone
  not_doc_standalone
  doc_index
  not_doc_index
  doc_overview
  not_doc_overview
  doc_chapter
  not_doc_chapter
  .. part ..
  part_top
  part_title
  part_contents
  part_abstract
  part_body
  part_defs
  part_bottom
}

class "README.txt (minimal)" as RMIN {
  doc_index     = SKIP
  not_doc_index = SNIP
  di_indent     = REM
  not_di_indent = INDENT
  minimal       = SNIP
  not_minimal   = SKIP
  snip_quote    = REM
  -- output block aliases --
  .. doc type ..
  .. part ..
}

' |:here:|
}

RSNP <|.. RIND : snn ~--mode rst\n~--key doc_index >
RSNP <|.. RCHP : snn ~--mode rst >
RSNP <|.. RMIN : snn ~--mode rst\n~--key minmal >

' |:here:|
@enduml

2.7. How to properly move chapter files and sections

2.7.1. Rename chapter file in same document directory

@startuml
left to right direction

package "Document **doc**" as doc_old {
    object "**chapter-old**" as chp_old {
    }
    object "**chapter-new**" as chp_new {
    }

    chp_old --> chp_new : renamed to
}
@enduml

  • Move README-chapter-old.txt to README-chapter-new.txt.

  • Execute M-x grep-find RET chapter-old RET.
    Rename info for chapter-old to info for chapter-new.
  • Clean + compile doc-new.
    Analyze error messages and correct errors.

2.7.2. Move chapter file to other document directory

@startuml
left to right direction

package "Document **doc-old**" as doc_old {
    object "**chapter-old**" as chp_old {
    }
}

package "Document **doc-new**" as doc_new {
    object "**chapter-new**" as chp_new {
    }
}

chp_old --> chp_new : moved to
@enduml

  • Move README-chapter-old.txt from doc-old to README-chapter-new.txt in doc-new.

  • Execute M-x grep-find RET chapter-old RET in doc-old.
    Keep document references from doc/doc_def_standalone.inc in doc/doc_def.inc.
    Move and rename info for chapter-old from doc-old to doc-new.
  • Clean + compile doc-new.
    Analyze error messages and correct errors.
    E.g. get missing substitutions/references/images/data from doc-old.
  • Clean + compile doc-old.
    Analyze error messages and correct errors.

2.7.3. How to move a section from one chapter file to another chapter file

@startuml
left to right direction

package "Document **doc-old**" as doc_old {
    package "Chapter **old**" as chp_old {
        object "Section **old**" as sec_old {
        }
    }
}

package "Document **doc-new**" as doc_new {
    package "Chapter **new**" as chp_new {
        object "Section **new**" as sec_new {
        }
    }
}

sec_old --> sec_new : moved to
@enduml

  • Remove section-old section from chapter-old.
    Insert as section-new in chapter-new.
  • Clean + compile doc-new.
    Analyze error messages and correct errors.
    E.g. get missing substitutions/references/images/data from doc-old.
  • Clean + compile doc-old.
    Analyze error messages and correct errors.

2.7.4. Traceability of section modifications

|:todo:| incorrect, needs to be updated

Case-by-case analysis:

  1. Move sections before chapter documents:

    • Section section-old moved from chapter-old to chapter-new in doc-old
    • chapter-new moved from doc-old to chapter-new in doc-new
    • chapter-new moved to chapter-new-new in doc-new

    Consequences:

    • doc-old no longer exists. It must be looked up in the document processing logs.
    • doc-new no longer exists. It must be looked up in the document processing logs.
    • The version history of the section modification resides in the old repositories (doc-old, :doc-new).
  2. Move chapter documents before sections:

    • doc-old moved to doc-old-new
    • doc-new moved to doc-new-new
    • Section section moved from doc-old-new to doc-new-new

    Consequences:

    • The version history of the section modification resides in the new repositories (doc-old-new, :doc-new-new), which is better.

2.8. ReST section overlines

manual (book) class:

File Book title Chapter Section Subsection Paragraph Subparagraph
README.txt ### === --- ~~~ ...  
README-chapter-topic.txt   ### === --- ~~~ ...

howto (article) class:

File Article title Section Subsection Paragraph Subparagraph
README.txt ### === --- ~~~ ...
README-chapter-topic.txt ### === --- ~~~ ...