summaryrefslogtreecommitdiff
path: root/macros/luatex/optex/verbatim.opm
blob: cfd9ed43548d3287b422645969827e6bfb4fc5a2 (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
%% This is part of OpTeX project, see http://petr.olsak.net/optex

\_codedecl \begtt {Verbatim <2020-03-21>} % preloaded in format

   \_doc ----------------------------
   The internal parameters for verbatim macros are set. 
   \_cod ----------------------------

\_def\_ttskip{\_medskip}           % space above and below \begtt, \verbinput
\_mathchardef\_ttpenalty=100       % penalty between lines in \begtt, \verbinput
\_newcount\_viline                 % last line number in \verbinput
\_newread\_vifile                  % file fgiven by \verinput
\_def\_ttfont{\_tt}                % default tt font

   \_doc ----------------------------
   `\code{<text>}` expands to `\detokenize{<text>}` when `\escapechar=-1`. In
   order to do it more robust when it is used in `\write` then it expands as
   noexpanded `\code<space>` (followed by space in its csname). This macro
   does the real work.

   The `\_printinverbatim{<text>}` macro is used for `\code{<text>}` printing and for
   \code{`}<text>\code{`} printing. It is defined as `\_hbox`, so the in-verbatim <text> 
   will be never broken. But you can re-define this macro.

   When `\code` occurs in PDF outlines then it does the same as `\detokenize`.
   The macro for preparing outlines sets `\escapechar` to $-1$ and uses
   `\_regoul` token list before `\edef`.

   The `\code` is not `\_proteced` because we want that it expands to
   `\_unexpanded{\code<space>{<text>}}` in `\write` parameters. This protect the 
   expansions of the `\code` parameter (like `\\`, `\^` etc.).
   \_cod ----------------------------

\_def\_code#1{\_unexpanded\_ea{\_csname _code \_endcsname{#1}}}
\_protected\_sdef{_code }#1{{\_escapechar=-1 \_ttfont \_the\_everyintt \_relax 
   \_ea\_printinverbatim\_ea{\_detokenize{#1}}}}
\_def\_printinverbatim#1{\_leavevmode\_hbox{#1}}

\_regmacro {}{}{\_let\code=\_detokenize \_let\_code=\_detokenize}

\_public \code ;

   \_doc ----------------------------
   The `\_setverb` macro sets all catcodes to \"verbatim mode". It should be used only 
   in a group, so we prepare a new catcode table with \"verbatim" catcodes and we define
   it as `\_catcodetable\_verbatimcatcodes`. After the group is finished then
   original catcode table is restored.
   \_cod ----------------------------

\_newcatcodetable \_verbatimcatcodes
\_def\_setverb{\_begingroup
   \_def\do##1{\_catcode`##1=12 }
   \_dospecials   
   \_savecatcodetable\_verbatimcatcodes % all characters are normal
   \_endgroup
}
\_setverb
\_def\_setverb{\_catcodetable\_verbatimcatcodes }%

   \_doc ----------------------------
   `\activettchar<char>` saves original catcode of previously declared <char> (if
   such character was declared) from `\_savedttchar` and `\_savedttcharc`
   values. Then new such values are stored. The declared charater is activated
   by `\_adef` as a macro (active character) which opens a group, 
   does `\_setverb` and other settings and reads its parameter until second the same 
   character. This is done by `\_readverb` macro. Finally it prints scanned
   <text> by `\_printinverbatim` and closes group. Suppose that `\activettchar"` is
   used. Then the following work is schematically done:
   \begtt
   \_def "{\_begingroup \_setverb ... \_readverb}
   \_def \_readverb #1"{\_printinverbatim{#1}\_endgroup}
   \endtt
   Note that the second occurence of `"` is not active because `\_setverb`
   deactivates it.
   \_cod ----------------------------

\_def\_activettchar#1{%
   \_ifx\_savedttchar\_undefined\_else \_catcode\_savedttchar=\_savedttcharc \_fi
   \_chardef\_savedttchar=`#1
   \_chardef\_savedttcharc=\_catcode`#1
   \_adef{#1}{\_begingroup \_setverb \_adef{ }{\ }\_ttfont \_the\_everyintt\_relax \_readverb}%
   \_def\_readverb ##1#1{\_printinverbatim{##1}\_endgroup}%
}
\_public \activettchar ;

   \_doc ----------------------------
   `\begtt` id defined only as public. We don't need private `\_begtt` variant.
   This macro os defined by `\eoldef`, so user can put an parameter at the
   same line where `\begtt` is. This `#1` parameter is used after `\_everytt`
   parameters settings, so user can change it locally.

   The `\begtt` macro opens group, does `\_setverb` and another preprocessing, sets
   `\endlinechar` to `^^J` and reads the following text in verbatim mode 
   until `\endtt` occurs. This scanning is done by `\_startverb` macro which is
   defined as:
   \begtt
   \_def\_startverb #1\endtt #2^^J{...}
   \endtt
   We must to ensure that the backslash in `\endtt` has category 12 (this is a
   reason of the `\ea` chain in real code).
   The `#2` is something between `\endtt` and end of line and it is simply
   ignored.

   The `\startverb` puts the scanned data to `\_prepareverbdata`. It sets the data
   to `\_tmpb` without changes by default, but you should re-define it in order
   to does s special changes (for example colorization of the code), if you
   want. The scanned data have `^^J` at each end of line and all spaces are
   active characters. Other characters have nomal category 11 or 12.  

   When `\prepareverbdata` finishes then `\startverb` runs `\_printverb` loop
   over aech line of the data and does a final work: last skip plus `\noindent`
   without first indentation box. This trick keeps horizontal mode without
   indentation when the empty line after `\endtt` does not exists. But it stops
   horizontal mode without any new box in outer vertical mode if `\par` is
   processed immediately after `\endtt`.

   The `\_printverb` macro calls `\_printverbline{<line>}` to each scanned line of
   verbatim text. This macro expect that it strarts in vertical mode ant it must
   do `\par` in order to return the vertical mode. The `\_printverblinenum`
   is used here: it does nothing when `\_ttline<0` else it prints the line
   number using `\_llap`.
   \_cod ----------------------------

\_eoldef \begtt#1{\_par \_wipeepar 
   \_begingroup
   \_vskip\_parskip \_ttskip
   \_setverb 
   \_ifnum\_ttline<0 \_let\_printverblinenum=\_relax \_else \_initverblinenum \_fi
   \_adef{ }{\ }\_parindent=\_ttindent \_parskip=0pt
   \_the\_everytt \_relax #1\_relax \_ttfont
   \_endlinechar=`^^J
   \_startverb
}
\_ea\_def\_ea\_startverb \_ea#\ea1\_csstring\\endtt#2^^J{%
   \_prepareverbdata\_tmpb{#1^^J}%
   \_ea\_printverb \_tmpb\_end
   \_par\_ttskip
   \_endgroup
   \_isnextchar\_par{}{\_noindent}%
}
\_def\_printverb #1^^J#2{\_ifx\_end#2
      \_bgroup \_adef{ }{}\_if\_relax#1\_relax\_egroup \_else\_egroup \_printverbline{#1}\_fi
   \_else
      \_printverbline{#1}%
      \_ea \_printverb \_ea #2%
   \_fi
}
\_def\_prepareverbdata#1#2{\_def#1{#2}}
\_def\_printverbline#1{\_penalty \_ttpenalty \_indent \_printverblinenum #1\par}
\_def\_initverblinenum{\_tenrm \_thefontscale[700]\_ea\_let\_ea\_sevenrm\_the\_font}
\_def\_printverblinenum{\_global\_advance\_ttline by1 \_llap{\_sevenrm \_the\_ttline\_kern.9em}}

   \_doc ----------------------------
   Macro `\verbinput` uses a file read perviously or opens the given file. Then
   it runss the parameter scanning by `\_viscanparameter` and `\_viscanminus`.
   Finally the `\_doverbinput` is run. At begining of `\_doverbinput` we have
   `\_viline`= number of lines already read using previous `\verbinput`,
   `\_vinolines`= the number of lines we need to skip and `\_vidolnes`= the
   number of lines we need to print.
   After group is opened then similar preparation is done as in `\begtt`. Then
   we skip `\_nolines` lines in a loop a and we read `\_dolines` lines. The
   read data is accumulated into `\_tmpb` macro. The next steps are equal to
   the steps done in `\_startverb` macro: data are processed via
   `\_prepareverbdata` and printed via `\_printverb` loop.
   \_cod \_fin ----------------------

\_def\_verbinput (#1) #2 {\_par \_def\_tmpa{#2}%
   \_ifx\_vifilename\_tmpa \_else
      \_openin\_vifile=#2
      \_global\_viline=0 \_global\_let\_vifilename=\_tmpa
      \_ifeof\_vifile
         \_opwarning{\_noexpand\verbinput - file "#2" is unable to reading}
         \_ea\_ea\_ea\_skiptorelax
      \_fi
   \_fi
   \_viscanparameter #1+\_relax
}
\_def\_skiptorelax#1\_relax{}

\_def \_viscanparameter #1+#2\_relax{%
   \_if$#2$\_viscanminus(#1)\_else \_viscanplus(#1+#2)\_fi
}
\_def\_viscanplus(#1+#2+){%
   \_if$#1$\_tmpnum=\_viline
   \_else \_ifnum#1<0 \_tmpnum=\_viline \_advance\_tmpnum by-#1
       \_else \_tmpnum=#1
             \_advance\_tmpnum by-1
             \_ifnum\_tmpnum<0 \_tmpnum=0 \_fi % (0+13) = (1+13)
   \_fi \_fi
   \_edef\_vinolines{\_the\_tmpnum}%
   \_if$#2$\_def\_vidolines{0}\_else\_edef\_vidolines{#2}\_fi
   \_doverbinput
}
\_def\_viscanminus(#1-#2){%
   \_if$#1$\_tmpnum=0
      \_else \_tmpnum=#1 \_advance\_tmpnum by-1 \_fi
   \_ifnum\_tmpnum<0 \_tmpnum=0 \_fi  % (0-13) = (1-13)
   \_edef\_vinolines{\_the\_tmpnum}%
   \_if$#2$\_tmpnum=0
      \_else \_tmpnum=#2 \_advance\_tmpnum by-\_vinolines \_fi
   \_edef\_vidolines{\_the\_tmpnum}%
   \_doverbinput
}
\_def\_doverbinput{%
   \_tmpnum=\_vinolines
   \_advance\_tmpnum by-\_viline
   \_ifnum\_tmpnum<0
      \_openin\_vifile=\_vifilename\_space
      \_global\_viline=0
   \_else
      \_edef\_vinolines{\_the\_tmpnum}%
   \_fi
   \_vskip\_parskip \_ttskip \_wipeepar
   \_begingroup
   \_ifnum\_ttline<-1 \_let\_printverblinenum=\_relax \_else \_initverblinenum \_fi
   \_setverb \_adef{ }{\ }\_parindent=\_ttindent \_parskip=0pt
   \_the\_everytt\_relax \_ttfont
   \_endlinechar=`^^J \_tmpnum=0
   \_loop \_ifeof\_vifile \_tmpnum=\_vinolines\_space \_fi
         \_ifnum\_tmpnum<\_vinolines\_space
         \_vireadline \_advance\_tmpnum by1 \_repeat      %% skip lines
   \_edef\_ttlinesave{\_ttline=\_the\_ttline}%
   \_ifnum\_ttline=-1 \_ttline=\_viline \_fi
   \_tmpnum=0 \_def\_tmpb{}%
   \_ifnum\_vidolines=0 \_tmpnum=-1 \_fi
   \_ifeof\_vifile \_tmpnum=\_vidolines\_space \_fi
   \_loop \_ifnum\_tmpnum<\_vidolines\_space
            \_vireadline 
            \_ifnum\_vidolines=0 \_else\_advance\_tmpnum by1 \_fi
            \_ifeof\_vifile \_tmpnum=\_vidolines\_space \_else \_visaveline \_fi %% save line
            \_repeat
   \_ea\_prepareverbdata \_ea \_tmpb\_ea{\_tmpb^^J}%
   \_ea\_printverb \_tmpb\_end
   \_global\_ttlinesave
   \_par\_ttskip
   \_endgroup
   \_noindent \_setbox0=\_lastbox
}
\_def\_vireadline{\_read\_vifile to \_tmp \_global\_advance\_viline by1 }
\_def\_visaveline{\_ea\_addto\_ea\_tmpb\_ea{\_tmp}}

\_public 
   \verbinput ;

\_endcode