summaryrefslogtreecommitdiff
path: root/macros/optex/base/prefixed.opm
blob: 89aa0b4966a30065359155f855a081dc40fb1cb1 (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
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
%% This is part of the OpTeX project, see http://petr.olsak.net/optex

\_codedecl \public {Prefixing and code syntax <2024-02-02>} % preloaded in format

   \_doc ---------
   All \TeX/ primitives have alternative control sequence `\_hbox` `\_string`, ...
   \_cod ---------

\let\_directlua = \directlua
\_directlua {
    % enable all TeX primitives with _ prefix
    tex.enableprimitives('_', tex.extraprimitives('tex'))
    % enable all primitives without prefixing
    tex.enableprimitives('', tex.extraprimitives())
    % enable all primitives with _ prefix
    tex.enableprimitives('_', tex.extraprimitives())
}

   \_doc ------------------
   \`\ea` is useful shortcut for `\expandafter`. We recommend to use always the
   private form of \`\_ea`
   because there is high probability that `\ea` will be redefined by the user.
   \nl
   \`\public` `\<sequence> \<sequence> ... ;` does
   `\let \<sequence> = \_<sequence>` for all sequences.
   \nl
   \`\private` `\<sequence> \<sequence> ...;` does
   `\let \_<sequence> = \<sequence>` for all sequences.
   \nl
   \`\newpublic``<do>\<sequence>` prints warning if `\<sequence>`
   is declared already. Then runs `<do>\<sequence>`.\nl
   \`\_checkexists` `<where> {<sequence-string>}` prints error
   if the control sequence given by its name <sequence-string>
   is not declared. This check is used in `\public`, `\private`,
   `\_nspublic` and `\_nsprivate` macros in order to avoid mistakes
   in names when declaring new control sequences.
   \nl
   \`\xargs` `<what> <sequence> <sequence> ... ;`
   does `<what><sequence>` for each sequences.
   \_cod -----------------

\_let\_ea =\_expandafter  % usefull shortcut

\_long\_def \_xargs #1#2{\_ifx #2;\_else \_ea#1\_ea#2\_ea\_xargs \_ea #1\_fi}

\_def \_pkglabel{}
\_def \_public {\_xargs \_publicA}
\_def \_publicA #1{%
   \_checkexists \public {_\_csstring#1}%
   \_ea\_let \_ea#1\_csname  _\_csstring #1\_endcsname
}
\_def \_private {\_xargs \_privateA}
\_def \_privateA #1{%
   \_checkexists \private {\_csstring #1}%
   \_ea\_let \_csname  _\_csstring #1\_endcsname =#1%
}
\_def\_checkexists #1#2{\_unless \_ifcsname #2\_endcsname
   \_errmessage {\_string#1: \_bslash#2 must be declared}\_fi
}
\_def\_newpublic #1#2{\_unless\_ifx #2\_undefined
   \_opwarning{\_string#2 is redefined%
      \_ifx\_pkglabel\_empty \_else\_space by the \_ea\_ignoreit\_pkglabel\_space package\_fi}\_fi
   #1#2%
}
\_public \public \private \newpublic \xargs \ea ;

   \_doc -----------------------------
   We define the macros
   \`\_namespace` `{<pkg label>}`,  \`\_resetnamespace` `{<pkg label>}`, \`\_endnamespace`,
   \`\_pkglabel`, \`\_nspublic`, and \`\_nsprivate`
   for package writers, see section~\ref[pkg-namespace].{\hbadness=2200\par}
   \_cod -----------------------------

\_def \_pkglabel{}
\_def\_namespace #1{%
   \_ifcsname _namesp:#1\_endcsname \_errmessage
      {The name space "#1" is used already, it cannot be used twice}%
      \_endinput
   \_else
      \_ea \_gdef \_csname _namesp:#1\_endcsname {}%
      \_resetnamespace{#1}\_fi
}
\_def\_resetnamespace #1{%
   \_unless \_ifx \_pkglabel\_empty \_endnamespace \_fi
   \_gdef \_pkglabel{_#1}%
   \_directlua{
      callback.add_to_callback("process_input_buffer",
        function (str)
           return string.gsub(str, "\_nbb[.]([a-zA-Z])", "\_nbb _#1_\_pcent 1")
        end, "_namespace")
   }%
}
\_def\_endnamespace {%
   \_directlua{ callback.remove_from_callback("process_input_buffer", "_namespace") }%
   \_gdef \_pkglabel{}%
}
\_def \_nspublic {\_xargs \_nspublicA}
\_def \_nspublicA #1{%
   \_checkexists \_nspublic {\_pkglabel _\_csstring #1}%
   \_ifcsname _eol:\_ea\_ignoreit\_pkglabel _\_csstring #1\_endcsname % defined by \eoldef
      \_slet {_eol:\_csstring #1}{_eol:\_ea\_ignoreit\_pkglabel _\_csstring #1}\_fi
   \_ea\_newpublic \_ea\_let \_ea#1\_csname \_pkglabel _\_csstring #1\_endcsname
}
\_def \_nsprivate {\_xargs \_nsprivateA}
\_def \_nsprivateA #1{%
   \_checkexists \_nsprivate {\_csstring #1}%
   \_ea\_let \_csname \_pkglabel _\_csstring #1\_endcsname =#1%
}

   \_doc -----------------------
   Each macro file should begin with \`\_codedecl` `\macro {<info>}`.
   If the `\macro` is defined already then the `\endpinput` protects to read
   such file more than once. Else the <info> is printed to the terminal
   and the file is read.
   The {\`\_endcode`} is defined as `\endinput` in the `optex.ini` file.
   \`\wterm` `{<text>}` prints the `<text>` to the terminal and to the `.log` file,
   \`\wlog` `{<text>}` prints the `<text>` only to the `.log` file (as in plain \TeX)
   \_cod -----------------------

\_def \_codedecl #1#2{%
   \_ifx #1\_undefined \_wlog{@:[\_basefilename\_currfile] #2}%
   \_else \_ea \_endinput \_fi
}
\_def \_wterm {\_immediate \_write16 }
\_def \_wlog {\_immediate\_write-1 } % write on log file (only)

\_public \wterm \wlog ;

   \_doc -----------------------------
   \`\currfile` returns the name of the current input file including its path.\nl
   \`\basefilename``\currfile` returns base name of
   the current file, without its path and extension.\nl
   \`\_nofilepath` `<text>/<with>/<slashes>/\_fin` expands to the last segment
   separated by slashes.\nl
   \`\_nofileext` `<filename>.\_fin` expands to the file name without extension.
   \_cod -----------------------------

\_def\_currfile{\_directlua{tex.print(status.filename)}}
\_def\_basefilename #1{\_ea\_nofileext\_expanded{\_ea\_ea\_ea\_nofilepath#1/\_fin}.\_fin}
\_def\_nofilepath #1/#2{\ifx#2\_fin #1\_else \_ea\_nofilepath \_ea#2\_fi}
\_def\_nofileext #1.#2\_fin{#1}

\_public \currfile \basefilename ;

   \_doc ------------------------------
   We define \`\_fin` as a useless macro. Suppose that its meaning will be never
   used for another control sequence. You can use `\_fin` as a final delimiter
   of a list of tokens and your macro can ask `\ifx\_fin#1` in order to
   decide that the list of tokens is finalized.
   \_cod ------------------------------

\_protected\_long \_def \_fin \_fin {}

\_endcode %----------------------------------------------------


\sec[basic-code] Basic principles of \OpTeX/ sources

\secc[namespaces] Concept of namespaces of control sequences

\OpTeX/ sets the category code of the \"`_`" character to 11 (letter)
and it is never changed.\fnote
{This is only singular exception form category codes given by plain \TeX.}
So, we can always construct multiletter control sequence names from letters
`A`--`Z`, `a`--`z`, and `_`. The \"letter `_`" works in math mode as a subscript
constructor because it is set as math active character (see section~\ref[math-macros]).

We distinguish following namespaces for multiletter control sequences:
\begitems
* Only alphabetical names are in the {\em public namespace}. They are intended
  for end users when creating a document. Sometimes it is called {\em user
  namespace} too. For example `\hbox`, `\fontfam`, `\MyMacro`.
* Only alphabetical lowercase names prefixed by single \"`_`" are in the
  {\em private namespace}. It is used in \OpTeX/ internal macros.
  For example `\_hbox`, `\_fontsel`.
* Names in the form `\_<pkg>_<name>` are in the {\em package namespace},
  see section~\ref[pkg-namespace]. For example `\_qr_size`, `\_math_alist`.
* Names starting with two \"`_`" are in the {\em reserved namespace}. They can be
  used for internal control sequences in font family files or in similar cases.
* Other names which include \"`_`" but not as the first character can be used
  too, but with care, see the end of this section.
\enditems

All \TeX/ primitives are initialized with two control sequences with the
same meaning: {\em prefixed} control sequence
(in private namespace, for example `\_hbox`)
and {\em unprefixed} control sequence (in public namespace, for example `\hbox`).
All \OpTeX/ macros intended for end users are initialized in these two forms
too, for example `\_ref` and `\ref`.

Users can declare any control sequences in the public namespace without worrying
that \OpTeX/ behavior is changed. This is because \OpTeX/ uses exclusively
prefixed control sequences in its macros. For example, a user can declare
`\def\fi{finito}` and nothing bad happens, if the user doesn't use `\fi` in
its original primitive meaning. You don't have to know all \TeX/ primitives
and \OpTeX/ macros, you can declare control sequences for your use in the
public namespace without limitations and nothing bad will happen.

You can use control sequences from private or package namespace in
a \"read-only manner" without changing \OpTeX/ behavior too.
On the other hand, if you re-define a control sequence in the private name
space, the \OpTeX/ behavior can be changed. You can do it
but we suppose that you know what you are doing and what \OpTeX/
behavior is changed.

All multiletter control sequences declared by \OpTeX/ are defined in the private
namespace first (`\_def\_macro{...}`). If the declared control sequences are
intended for end users too then they are exported to the public namespace
after that. It is done by the \^`\public` macro:
\begtt \catcode`\<=13
\public <list of control sequences> ;
\endtt
For example \^`\public`` \foo \bar ;` does `\let\foo=\_foo`, `\let\bar=\_bar`.

There is an exception of the above mentioned principle. Control sequences
which are alternatives to math characters (`\alpha`, `\forall`, `\subset` etc.)
are declared only in public name space if they are not used in any internal
\OpTeX/ macros.

The macro \^`\private` does the reverse job of \^`\public` with the same syntax.
For example `\private \foo \bar ;` does `\let\_foo=\foo`, `\let\_bar=\bar`.
This should be used when an unprefixed variant of a control sequence is declared
already but we need the prefixed variant too.

In this documentation: if both variants of a control sequence are declared
(prefixed and unprefixed), then the accompanying text mentions only
the unprefixed variant. The code typically defines the prefixed variant
and then the \^`\public` (or `\_public`) macro is used.

The single-letter control sequences like `\%`, `\$`, `\^` etc. are not used
in internal macros. Users can redefine them, but (of course) some classical
features can be lost (printing percent character by `\%` for example).

It is very tempting to use control sequence names with `_` in order to
distinguish more words in the sequence name. If the first character isn't
`_` then such a name is outside private and package namespaces, so they can
be used for various purposes. For example `\my_control_sequence`. But there
is an exception: control sequences in the form `\<word>_` or `\<word>_<one-letter>`,
where <word> is a sequence of letters, are inaccessible, because they
are interpreted as `\<word>` followed by `_` or as `\<word>` followed by
`_<one-letter>`. This feature is activated because we want to write math
formulae as in plain \TeX, for example:
\begtt
  \int_a^b    ... is interpreted as \int _a^b
  \max_M      ... is interpreted as \max _M
  \alpha_{ij} ... is interpreted as \alpha _{ij}
\endtt
It is implemented using Lua code at input processor level, see
the section~\ref[math-macros] for more details. You can deactivate this feature by
\^`\mathsboff`. After this, you can still write
`$`$\int$`_a^b$` (Unicode) or `$\int _a^b$` % $∫_a^b$ (Unicode) or $\int _a^b$
without problems but `\int``_a^b` yields to undefined control sequence
`\int``_a`. You can activate this feature again by \^`\mathsbon`. The
effect will take shape from next line read from input file.


\secc Macro files syntax

Segments of \OpTeX/ macros or external macro packages
are stored in files with `.opm` extension
(means OPtex Macros). Your local macros should be in a normal `*.tex` file.

The code in macro files starts by \^`\_codedecl` and ends by \^`\_endcode`.
The \^`\_endcode` is equivalent for `\endinput`, so documentation can follow.
The \^`\_codedecl` has syntax:

\begtt \catcode`<=13 \adef!{\string}
\_codedecl \sequence {<short title> !<<version>>}
\endtt

If the mentioned `\sequence` is undefined then \^`\_codedecl` prints the message
\begtt  \catcode`<=13 \adef!{\string}
@:[<file name>] <short title> !<<version>>
\endtt
to the log file and \TeX/ continues with reading the following macros.
If the `\sequence` is defined, then \^`\_codedecl` acts like
`\endinput`: this protects from reading the file twice. We suppose, that
`\sequence` is defined in the macro file.

It is possible to use the \^`\_doc` ... \^`\_cod` pair between the macro
definitions. The documentation text should be here.
It is ignored when macros are read.

The \^`\_doc` ... \^`\_cod` parts can be printed after \^`\load[doc]`
using \~`\printdoc` macro, see section~\ref[doc].
If you have created a documented macro file `pkgname.opm` then you can
put macros for creating your documentation between
first pair of \^`\_doc` ... \^`\_cod` used after \^`\_endcode`.
These macros should \^`\load[doc]` and must be finished by \^`\bye`.
Then you have code+documentation together in a single file and
user can generate the documentation of your package by
\^`\docgen` used at command line:
\begtt
optex -jobname pkgname-doc '\docgen pkgname'
\endtt
Example of a  \^`\_doc` ... \^`\_cod` code used for creating the
documentation using \^`\docgen` can be found in the `math.opm` file. You can see
\ulink[https://petr.olsak.net/ftp/olsak/optex/math-doc.pdf]{its documentation}, especially
\ulink[https://petr.olsak.net/ftp/olsak/optex/math-doc.pdf\#ref:pkgtemplate]
{section about creating packages}.

\secc[pkg-namespace] Name spaces for package writers

Package writer should use internal names in the form `\_<pgk>_<sequence>`,
where `<pkg>` is a package label. For example:
`\_qr_utfstring` from `qrcode.opm` package.

The package writer does not need to write repeatedly `\_pkg_foo` `\_pkg_bar`
etc.\ again and again in the macro file.\fnote
{We have not adopted the idea from expl3 language:)}
When the \^`\_namespace` `{<pkg>}`
is declared at the beginning of the macro file then all occurrences of
`\.foo` will be replaced by `\_<pkg>_foo` at the input processor level.
The macro writer can write (and backward can read his/her code) simply with
`\.foo`, `\.bar` control sequences and `\_<pkg>_foo`, `\_<pkg>_bar`
control sequences are processed internally.
The scope of the \^`\_namespace` command ends at the \^`\_endnamespace` command
or when another \^`\_namespace` is used. This command checks
if the same package label is not declared by the \^`\_namespace` twice.

\^`\_nspublic` `<list of sequences> ;`
does `\let\foo = \_<pkg>_foo` for each given sequence when
\^`\_namespace{<pkg>}` is declared. Moreover, it prints a warning if `\foo` is
defined already. The \^`\_nsprivate` macro does reverse
operation to it without warnings. Example: you can define `\def\.macro{...}` and then
set it to the public namespace by `\_nspublic \macro;`.

It could happen that a package writer needs to declare a control sequence
(say `\foo`) directly without setting it in `\_<pkg>_foo` namespace
followed by using \^`\_nspublic`. The \^`\newpublic` prefix should be used in this
case, for example `\_newpublic\_def\foo` or `\_newpublic\_chardef\foo` or
`\_newpublic{\_long\_def}\foo`. The \^`\newpublic``<do>\<sequence>` prints
a warning if the declared `\<sequence>` is defined already and then runs
`<do>\<sequence>`. The reason of the warning is the same as when
\^`\_nspublic` warns about doing re-declaration of control sequences already
declared.

Don't load other packages (which are using their own namespace) inside your
namespace. Do load them before your \^`\_namespace`~`{<pkg>}` is
initialized. Or close your namespace by \^`\_endnamespace` and open it again
(after other packages are loaded) by \^`\_resetnamespace`~`{<pkg>}`.

If the package writer needs to declare a control
sequence by \^`\newif`, then there is an exception of the rule described above. Use
\^`\_newifi\_if<pkg>_bar`, for example `\_newifi\_ifqr_incorner`.
Then the control sequences `\_qr_incornertrue` and
`\_qr_incornerfalse` can be used (or the sequences `\.incornertrue`
and `\.incornerfalse` when `\_namespace{qr}` is used).


\secc Summary about rules for external macro files published for \OpTeX/

If you are writing a macro file that is intended to be published for
\OpTeX/, then you are greatly welcome. You should follow these rules:

\begitems
* Don't use control sequences from the public namespace in the macro
  bodies if there is no explicit and documented reason to do this.
* Don't declare control sequences in the public namespace if there are no
  explicit and documented reasons to do this.
* Use control sequences from \OpTeX/ and primitive namespace
  in read-only mode, if there is not an explicit and documented reason to
  redefine them.
* Use `\_<pkg>_<name>` for your internal macros or `\.<name>` if the
  \^`\_namespace{<pkg>}` is declared. See section~\ref[pkg-namespace].
* Use \^`\load` (or better: `\_load`) for loading more external macros
  if you need them. Don't use `\_input` explicitly in such cases.
  The reason is: the external macro file is not loaded
  twice if another macro or the user needs it explicitly too.
* Use \^`\_codedecl` as your first command in the macro file and
  \^`\_endcode` to close the text of macros.
* Use \^`\_doc` ... \^`\_cod` pairs for documenting the code pieces.
* You can write more documentation after the \^`\_endcode` command.
* The \OpTeX/ catcodes are set when \^`\load` your package (i.e. plain \TeX/
  catcodes plus catcode of `_` is 11). If a catcode is changed during
  loading your package then it is forgot because \^`\load` returns to catcodes
  used before loading package. If you want to offer a catcode changing for
  users then insert it to a macro which can be used after loading.
\enditems

If the macro file accepts these recommendations then it should be
named by `<filename>.opm` where `<filename>` differs from file names
used directly in \OpTeX/ and from other published macros.
This extension `.opm` has precedence before `.tex` when
the \^`\load` macro is used.

The `math.opm` is a good example of how an external macro file for \OpTeX/
can look like. Another good and short example is
\ulink[https://tex.stackexchange.com/questions/684406\#684406]{here}.

\endinput

2024-02-02 \_nspublicA bug correction (#1 may be set as \outer)
2024-01-18 \_nspublic modified in order to \eoldef+\bracedparam
2023-01-30 doc. about namespaces rewritten
2022-11-25 \_resetnamespace: moved \gdef\_namesp:#1 {} to \_namespace
2022-11-24 \newpublic introduced, \_checkexists with only two parameters.
2022-11-22 \currfile introduced and used in \_codedecl
2022-11-13 \_resetnamespace corrected
2021-08-16 \_wlog moved from basic macros, \_codedecl uses \_wlog only.
2021-04-25 \_checkexists introduced
2021-02-15 \_expandafter -> \_ea in \_codedecl
2020-02-14 released