aboutsummaryrefslogtreecommitdiffhomepage
path: root/org/ocda_reserved.org
blob: eddf45504d4e428bba54bc20d18aaa75f6805bd4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
-*- mode: org -*-
#+TITLE:       sisudoc spine (doc_reform) object-centric document abstraction
#+DESCRIPTION: documents - structuring, publishing in multiple formats & search
#+SUMMARY:     process markup document, create document abstraction
#+FILETAGS:    :spine:abstraction:
#+AUTHOR:      Ralph Amissah
#+EMAIL:       [[mailto:ralph.amissah@gmail.com][ralph.amissah@gmail.com]]
#+COPYRIGHT:   Copyright (C) 2015 (continuously updated, current 2026) Ralph Amissah
#+LANGUAGE:    en
#+STARTUP:     content hideblocks hidestars noindent entitiespretty
#+PROPERTY:    header-args+ :eval never-export :exports code
#+PROPERTY:    header-args+ :noweb yes :padline no
#+PROPERTY:    header-args+ :results silent :cache no
#+PROPERTY:    header-args+ :mkdirp yes
#+OPTIONS:     H:3 num:nil toc:t \n:t ::t |:t ^:nil -:t f:t *:t
- magic single double-quote → " ← FIX changes hilighting behavior (occuring
  after it) in org document. INVESTIGATE (org-mode CONFIG?) FIND & FIX

- [[./doc-reform.org][doc-reform.org]]  [[./][org/]]

* reserved file names

#+HEADER: :tangle "../src/sisudoc/ocda/meta/reserved_names.d"
#+HEADER: :noweb yes
#+BEGIN_SRC d
<<doc_header_including_copyright_and_license>>
/++
  the segment names spine keeps for itself<br><br>

  the one list of them, and the check that says when a document's own
  heading has claimed one<br><br>

  [sisudoc.ocda.meta.reserved_names]
+/
module sisudoc.ocda.meta.reserved_names;
@safe:
/+ ↓ spine names the sections it generates, these names are reserved.
     .
     The table of contents, the gathered endnotes, the glossary, the
     bibliography, the book index and the blurb are not in the markup: spine
     makes them, and gives each a segment name of its own. A document whose
     own heading asks for one of those names ("1~endnotes Endnote") is asking
     for a name that is already taken, and before this was noticed both wrote
     into the same file: the generated section and the author's heading, with
     the navigation listing that file twice, the second time behind its own
     earlier entry in reading order.
     .
     The parser therefore seeds the set of heading anchor names it has seen
     with these before it reads a document, so that a heading claiming one is
     disambiguated by ocn suffix the same way a repeated anchor tag is, and
     the generated section keeps the name the table of contents links to.
     .
     Two things live here rather than in the parser:
     .
       the list      so that the parser's seeding and the check below cannot
                     come to hold different ideas of what is reserved;
                     .
       the check     which runs over a finished abstraction, names the
                     headings that were renamed, and is what tells an author
                     that a heading of theirs is not called what they wrote.
                     A warning: the document is correct and complete, and the
                     name it ends up with works. --strict makes it a failure,
                     for the run that is meant to be publishable.
     .
     The renaming is not something the author has to accept. A heading given
     any other anchor name ("1~my-notes Endnote") keeps it, and the warning
     goes away.
+/
/+ ↓ mixed in as a named mixin (mixin spineReservedNames _name;) and its
     imports are inside its functions rather than at template scope: what a
     mixin template declares at its own scope is visible in the scope it is
     mixed into, and an import there can hijack a name the host was already
     resolving by UFCS.
+/
template spineReservedNames() {
  /+ ↓ the names spine makes for itself, in one place.
       _the_title is the head section's own; the rest are the generated
       sections, and are the section keys of the abstraction.
  +/
  string[] reservedHeadingAnchorNames() {
    return [
      "toc", "endnotes", "glossary", "bibliography", "bookindex", "blurb",
      "_the_title",
    ];
  }
  /+ ↓ the same, as the set the parser seeds itself with +/
  bool[string] reservedHeadingAnchorTags() {
    bool[string] _reserved;
    foreach (_name; reservedHeadingAnchorNames()) { _reserved[_name] = true; }
    return _reserved;
  }
  /+ ↓ one heading that asked for a name spine had already taken +/
  struct ST_ReservedNameUse {
    string section;    // where in the abstraction it sits
    string reserved;   // the name it asked for
    string anchor;     // the name it was given instead
    string level;      // as marked up, :A :B 1 2 ...
    int    ocn;
  }
  /+ ↓ was this heading renamed out of the way of a reserved name?
       .
       Read off the anchor rather than reported by the parser: the parser
       renames by appending the object's number, so "endnotes" becomes
       "endnotes-135" on the object whose ocn is 135, and that pairing is what
       identifies it. Requiring the number to be the object's own is what keeps
       a heading an author really did call "endnotes-135" from being reported as
       something it is not.
  +/
  private string _reservedNameClaimedBy(O)(O obj) {
    import std.conv : to;
    string _anchor = obj.tags.anchor_tag_html;
    if (_anchor.length == 0) { return ""; }
    string _suffix = "-" ~ obj.metainfo.ocn.to!string;
    if (_anchor.length <= _suffix.length) { return ""; }
    if (_anchor[($ - _suffix.length) .. $] != _suffix) { return ""; }
    string _stem = _anchor[0 .. ($ - _suffix.length)];
    foreach (_name; reservedHeadingAnchorNames()) {
      if (_stem == _name) { return _name; }
    }
    return "";
  }
  /+ ↓ every heading of a document that claimed a reserved name.
       document order, the section order the .ssp is written in, so that two
       runs over the same document report it the same way round.
  +/
  ST_ReservedNameUse[] reservedNameHeadings(D)(D doc) {
    import std.algorithm : canFind, sort;
    import std.conv : to;
    ST_ReservedNameUse[] _out;
    string[] _sections = ["head", "toc", "body", "endnotes",
      "glossary", "bibliography", "bookindex", "blurb", "tail"];
    string[] _extra;
    foreach (_k; doc.abstraction.byKey) {
      if (!_sections.canFind(_k)) { _extra ~= _k; }
    }
    foreach (_k; _extra.sort) { _sections ~= _k; }
    foreach (section; _sections) {
      if (section !in doc.abstraction) { continue; }
      foreach (obj; doc.abstraction[section]) {
        if (obj.metainfo.is_a != "heading") { continue; }
        string _claimed = _reservedNameClaimedBy(obj);
        if (_claimed.length == 0) { continue; }
        /+ ↓ the generated sections carry the reserved names themselves and are
             not what this is about: they are headings spine made, and they keep
             the plain name. Only an object that was renamed reaches here, and a
             generated one never is.
        +/
        ST_ReservedNameUse _u;
        _u.section  = section;
        _u.reserved = _claimed;
        _u.anchor   = obj.tags.anchor_tag_html;
        _u.level    = obj.metainfo.marked_up_level;
        _u.ocn      = obj.metainfo.ocn.to!int;
        _out ~= _u;
      }
    }
    return _out;
  }
  /+ ↓ the report, as the lines to print.
       the document is named once and its headings indented under it, as the ocn
       alignment check does, so that a run over a collection reads as a list of
       documents.
  +/
  string[] reservedNameReportLines(
    string             doc_key,
    string             lang,
    ST_ReservedNameUse[] _uses,
  ) {
    import std.conv : to;
    string[] _out;
    if (_uses.length == 0) { return _out; }
    _out ~= "WARNING reserved segment name: " ~ doc_key
      ~ ((lang.length > 0) ? " [" ~ lang ~ "]" : "");
    foreach (_u; _uses) {
      _out ~= "  heading " ~ _u.level ~ " at ocn " ~ _u.ocn.to!string
        ~ " asks for \"" ~ _u.reserved
        ~ "\", which spine gives its own generated section";
      _out ~= "    it is named \"" ~ _u.anchor
        ~ "\" instead; give the heading another name to keep one of your own";
    }
    return _out;
  }
}
#+END_SRC

* org includes
** project version

#+NAME: spine_version
#+HEADER: :noweb yes
#+BEGIN_SRC emacs-lisp
<<./sisudoc_spine_version_info_and_doc_header_including_copyright_and_license.org:spine_project_version()>>
#+END_SRC

** year

#+NAME: year
#+HEADER: :noweb yes
#+BEGIN_SRC emacs-lisp
<<./sisudoc_spine_version_info_and_doc_header_including_copyright_and_license.org:year()>>
#+END_SRC

** document header including copyright & license

#+NAME: doc_header_including_copyright_and_license
#+HEADER: :noweb yes
#+BEGIN_SRC emacs-lisp
<<./sisudoc_spine_version_info_and_doc_header_including_copyright_and_license.org:spine_doc_header_including_copyright_and_license()>>
#+END_SRC

* __END__