%% 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` `\ \ ... ;` does `\let \ = \_` for all sequences. \nl \`\private` `\ \ ...;` does `\let \_ = \` for all sequences. \nl \`\newpublic``\` prints warning if `\` is declared already. Then runs `\`.\nl \`\_checkexists` ` {}` prints error if the control sequence given by its name 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` ` ... ;` does `` for each sequences. \_cod ----------------- \_let\_ea =\_expandafter % useful 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` `{}`, \`\_resetnamespace` `{}`, \`\_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 {}`. If the `\macro` is defined already then the `\endpinput` protects to read such file more than once. Else the is printed to the terminal and the file is read. The {\`\_endcode`} is defined as `\endinput` in the `optex.ini` file. \`\wterm` `{}` prints the `` to the terminal and to the `.log` file, \`\wlog` `{}` prints the `` 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` `///\_fin` expands to the last segment separated by slashes.\nl \`\_nofileext` `.\_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 `\__` 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 ; \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 `\_` or `\_`, where is a sequence of letters, are inaccessible, because they are interpreted as `\` followed by `_` or as `\` followed by `_`. 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 { !<>} \endtt If the mentioned `\sequence` is undefined then \^`\_codedecl` prints the message \begtt \catcode`<=13 \adef!{\string} @:[] !<> \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 `\__`, where `` 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` `{}` is declared at the beginning of the macro file then all occurrences of `\.foo` will be replaced by `\__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 `\__foo`, `\__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` ` ;` does `\let\foo = \__foo` for each given sequence when \^`\_namespace{}` 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 `\__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``\` prints a warning if the declared `\` is defined already and then runs `\`. 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`~`{}` is initialized. Or close your namespace by \^`\_endnamespace` and open it again (after other packages are loaded) by \^`\_resetnamespace`~`{}`. 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_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 `\__` for your internal macros or `\.` if the \^`\_namespace{}` 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 `.opm` where `` 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