1%D \module 2%D [ file=lang-mis, 3%D version=1997.03.20, % used to be supp-lan.tex 4%D title=\CONTEXT\ Language Macros, 5%D subtitle=Compounds, 6%D author=Hans Hagen, 7%D date=\currentdate, 8%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}] 9%C 10%C This module is part of the \CONTEXT\ macro||package and is 11%C therefore copyrighted by \PRAGMA. See mreadme.pdf for 12%C details. 13 14\writestatus{loading}{ConTeXt Language Macros / Compounds} 15 16%D More or less replaced. 17 18%D \gdef\starttest#1\stoptest{\starttabulate[|l|l|p|]#1\stoptabulate} 19%D \gdef\test #1{\NC\detokenize{#1}\NC\hyphenatedword{#1}\NC#1\NC\NR} 20 21\unprotect 22 23%D One of \TEX's strong points in building paragraphs is the way hyphenations are 24%D handled. Although for real good hyphenation of non||english languages some 25%D extensions to the program are needed, fairly good results can be reached with the 26%D standard mechanisms and an additional macro, at least in Dutch. 27%D 28%D \CONTEXT\ originates in the wish to typeset educational materials, especially in 29%D a technical environment. In production oriented environments, a lot of compound 30%D words are used. Because the Dutch language poses no limits on combining words, we 31%D often favor putting dashes between those words, because it facilitates reading, 32%D at least for those who are not that accustomed to it. 33%D 34%D In \TEX\ compound words, separated by a hyphen, are not hyphenated at all. In 35%D spite of the multiple pass paragraph typesetting this can lead to parts of words 36%D sticking into the margin. The solution lays in saying \type 37%D {spoelwater||terugwinunit} instead of \type {spoelwater-terugwinunit}. By using a 38%D one character command like \type {|}, delimited by the same character \type {|}, 39%D we get ourselves both a decent visualization (in \TEXEDIT\ and colored verbatim 40%D we color these commands yellow) and an efficient way of combining words. 41%D 42%D The sequence \type{||} simply leads to two words connected by a hyphen. Because 43%D we want to distinguish such a hyphen from the one inserted when \TEX\ hyphenates 44%D a word, we use a bit longer one. 45%D 46%D \hyphenation {spoel-wa-ter te-rug-win-unit} 47%D 48%D \starttest 49%D \test {spoelwater||terugwinunit} 50%D \stoptest 51%D 52%D As we already said, the \type{|} is a command. This commands accepts an optional 53%D argument before it's delimiter, which is also a \type{|}. 54%D 55%D \hyphenation {po-ly-meer che-mie} 56%D 57%D \starttest 58%D \test {polymeer|*|chemie} 59%D \stoptest 60%D 61%D Arguments like \type{*} are not interpreted and inserted directly, in contrary to 62%D arguments like: 63%D 64%D \starttest 65%D \test {polymeer|~|chemie} 66%D \test {|(|polymeer|)|chemie} 67%D \test {polymeer|(|chemie|)| } 68%D \stoptest 69%D 70%D Although such situations seldom occur |<|we typeset thousands of pages before we 71%D encountered one that forced us to enhance this mechanism|>| we also have to take 72%D care of comma's. 73%D 74%D \hyphenation {uit-stel-len} 75%D 76%D \starttest 77%D \test {op||, in|| en uitstellen} 78%D \stoptest 79%D 80%D The next special case (concerning quotes) was brought to my attention by Piet 81%D Tutelaers, one of the driving forces behind rebuilding hyphenation patterns for 82%D the dutch language.\footnote{In 1996 the spelling of the dutch language has been 83%D slightly reformed which made this topic actual again.} We'll also take care of 84%D this case. 85%D 86%D \starttest 87%D \test {AOW|'|er} 88%D \test {cd|'|tje} 89%D \test {ex|-|PTT|'|er} 90%D \test {rock|-|'n|-|roller} 91%D \stoptest 92%D 93%D Tobias Burnus pointed out that I should also support something like 94%D 95%D \starttest 96%D \test {well|_|known} 97%D \stoptest 98%D 99%D to stress the compoundness of hyphenated words. 100%D 101%D Of course we also have to take care of the special case: 102%D 103%D \starttest 104%D \test {text||color and ||font} 105%D \stoptest 106 107%D \macros 108%D {installdiscretionaries} 109%D 110%D The mechanism described here is one of the older inner parts of \CONTEXT. The 111%D most recent extensions concerns some special cases as well as the possibility to 112%D install other characters as delimiters. The prefered way of specifying compound 113%D words is using \type{||}, which is installed by: 114%D 115%D \starttyping 116%D \installdiscretionary | - 117%D \stoptyping 118%D 119%D Some alternative definitions are: 120%D 121%D \startbuffer 122%D \installdiscretionary * - 123%D \installdiscretionary + - 124%D \installdiscretionary / - 125%D \installdiscretionary ~ - 126%D \stopbuffer 127%D 128%D \typebuffer 129%D 130%D after which we can say: 131%D 132%D \start \getbuffer 133%D \starttest 134%D \test {test**test**test} 135%D \test {test++test++test} 136%D \test {test//test//test} 137%D \test {test~~test~~test} 138%D \stoptest 139%D \stop 140 141%D \macros 142%D {compoundhyphen} 143%D 144%D Now let's go to the macros. First we define some variables. In the main \CONTEXT\ 145%D modules these can be tuned by a setup command. Watch the (maybe) better looking 146%D compound hyphen. 147 148% hm why ex 149 150\ifx\compoundhyphen \undefined 151 \unexpanded\def\compoundhyphen {\hbox{-\kern-.10775\emwidth-}} % .25\exheight 152\fi 153 154%D The last two variables are needed for subsentences |<|like this one|>| which we 155%D did not yet mention. We want to enable breaking but at the same time don't want 156%D compound characters like |-| or || to be separated from the words. \TEX\ hackers 157%D will recognise the next two macro's: 158 159\ifx\prewordbreak \undefined \unexpanded\def\prewordbreak {\penalty\plustenthousand\hskip\zeropoint\relax} \fi 160\ifx\postwordbreak\undefined \unexpanded\def\postwordbreak {\penalty\zerocount \hskip\zeropoint\relax} \fi 161\ifx\hspaceamount \undefined \def\hspaceamount#1#2{.16667\emwidth} \fi % language specific 162 163%unexpanded\def\permithyphenation{\ifhmode\prewordbreak\fi} % doesn't remove spaces 164\unexpanded\def\permithyphenation{\ifhmode\wordboundary\fi} % doesn't remove spaces 165 166%D \macros 167%D {beginofsubsentence,endofsubsentence, 168%D beginofsubsentencespacing,endofsubsentencespacing} 169%D 170%D In the previous macros we provided two hooks which can be used to support nested 171%D sub||sentences. In \CONTEXT\ these hooks are used to insert a small space when 172%D needed. 173 174% \ifx\beginofsubsentence \undefined \unexpanded\def\beginofsubsentence{\hbox{\emdash}} \fi 175% \ifx\endofsubsentence \undefined \unexpanded\def\endofsubsentence {\hbox{\emdash}} \fi 176% \ifx\beginofsubsentencespacing\undefined \let\beginofsubsentencespacing\relax \fi 177% \ifx\endofsubsentencespacing \undefined \let\endofsubsentencespacing \relax \fi 178 179%D The following piece of code is a torture test compound handling. The \type 180%D {\relax} before the \type {\ifmmode} is needed because of the alignment scanner 181%D (in \ETEX\ this problem is not present because there a protected macro is not 182%D expanded. Thanks to Tobias Burnus for providing this example. 183%D 184%D \startformula 185%D \left|f(x_n)-{1\over2}\right| = 186%D {\cases{|{1\over2}-x_n| &for $0\le x_n < {1\over2}$\cr 187%D |x_n-{1\over2}| &for ${1\over2}<x_n\le1$ \cr}} 188%D \stopformula 189 190\installcorenamespace{discretionaryaction} 191\installcorenamespace{discretionarytext} 192\installcorenamespace{discretionarymath} 193\installcorenamespace{discretionaryboth} 194\installcorenamespace{discretionarymode} 195 196\unexpanded\def\installdiscretionary#1#2% 197 {\setevalue{\??discretionarymath\detokenize{#1}}{\detokenize{#1}}% ? 198 \setvalue {\??discretionarytext\detokenize{#1}}{#2}% 199 \setvalue {\??discretionaryboth\detokenize{#1}}{\lang_discretionaries_command#1}% 200 \scratchcounter\expandafter`\detokenize{#1}% 201 \expandafter\uedcatcodecommand\expandafter\ctxcatcodes\expandafter\scratchcounter\csname\??discretionaryboth\detokenize{#1}\endcsname} 202 203\unexpanded\def\handlemathmodediscretionary#1{\ifcsname\??discretionarymath\detokenize{#1}\endcsname\lastnamedcs} 204\unexpanded\def\handletextmodediscretionary#1{\ifcsname\??discretionarytext\detokenize{#1}\endcsname\lastnamedcs} 205 206\unexpanded\def\installdiscretionaries#1#2{\writestatus\m!system{use \string \installdiscretionary}} % obsolete 207 208\setnewconstant\discretionarymode\plusone 209 210\unexpanded\def\ignorediscretionaries{\discretionarymode\zerocount} 211\unexpanded\def\obeydiscretionaries {\discretionarymode\plusone} 212 213\def\lang_discretionaries_command 214 {% if direct if, we need \relax for lookahead in math mode 215 \csname\??discretionarymode 216 \ifcase\discretionarymode 217 n% 218 \else\ifmmode 219 m% 220 \else 221 t% 222 \fi\fi 223 \endcsname} 224 225\setvalue{\??discretionarymode n}#1% 226 {\detokenize{#1}} 227 228%D The macro \type{\lang_discretionaries_check_before} takes care of loners like 229%D \type{||word}, while it counterpart \type {\lang_discretionaries_check_after} is 230%D responsible for handling the comma. 231 232\newsignal\compoundbreakpoint 233 234\newconditional\punctafterdiscretionary 235\newconditional\spaceafterdiscretionary 236 237\def\lang_discretionaries_check_before %i sused grouped 238 {\ifvmode 239 \dontleavehmode 240 \fi 241 \ifhmode 242 %\begingroup 243 %\setbox\scratchbox\lastbox 244 %\ifzeropt\wd\scratchbox 245 % \box\scratchbox\relax 246 % \endgroup 247 % \let\postwordbreak\prewordbreak 248 %\else 249 % \box\scratchbox\relax 250 % \endgroup 251 %\fi 252 \fi} 253 254\def\lang_discretionaries_check_after 255 {\setfalse\punctafterdiscretionary 256 \setfalse\spaceafterdiscretionary 257 \ifx\blankspace\nexttoken \settrue \spaceafterdiscretionary \else 258 \ifx\space \nexttoken \settrue \spaceafterdiscretionary \else 259 \ifx .\nexttoken \settrue \punctafterdiscretionary \else 260 \ifx ,\nexttoken \settrue \punctafterdiscretionary \else 261 \ifx :\nexttoken \settrue \punctafterdiscretionary \else 262 \ifx ;\nexttoken \settrue \punctafterdiscretionary \fi\fi\fi\fi\fi\fi} 263 264\letvalue{\??discretionarymode m}\handlemathmodediscretionary 265 266\setvalue{\??discretionarymode t}#1% 267 {\bgroup 268 \let\nextnextnext\egroup 269 \def\next##1#1% 270 {\def\next{\activedododotextmodediscretionary#1{##1}}% 271 \futurelet\nexttoken\next}% 272 \next} 273 274\let\discretionarytoken \relax 275\let\textmodediscretionary\relax 276 277\unexpanded\def\activedododotextmodediscretionary#1#2% 278 {\edef\discretionarytoken{\detokenize{#2}}% 279 \def\textmodediscretionary{\handletextmodediscretionary{#1}}% 280 \lang_discretionaries_check_after 281 \ifx\discretionarytoken\empty 282 \ifx#1\nexttoken % takes care of ||| and +++ and ...... 283 \ifcsname\??discretionaryaction\string#1\endcsname 284 \lastnamedcs 285 \else\ifconditional\spaceafterdiscretionary 286 %\prewordbreak\hbox{\string#1}\relax 287 \wordboundary\hbox{\string#1}\relax 288 \else\ifconditional\punctafterdiscretionary 289 %\prewordbreak\hbox{\string#1}\relax 290 \wordboundary\hbox{\string#1}\wordboundary 291 \else 292 %\prewordbreak\hbox{\string#1}\prewordbreak 293 \wordboundary\hbox{\string#1}\wordboundary 294 \fi\fi\fi 295 \def\nextnextnext{\afterassignment\egroup\let\next=}% 296 \else 297 \lang_discretionaries_check_before 298 % the next line has been changed (20050203) 299 % \prewordbreak\hbox{\textmodediscretionary\nexttoken}\postwordbreak 300 % but an hbox blocks a possible \discretionary 301 \ifcsname\??discretionaryaction\endcsname 302 \lastnamedcs 303 \else\ifconditional\spaceafterdiscretionary 304 %\prewordbreak\textmodediscretionary\relax 305 \wordboundary\textmodediscretionary\relax 306 \else\ifconditional\punctafterdiscretionary 307 %\prewordbreak\textmodediscretionary\relax 308 \wordboundary\textmodediscretionary\relax 309 \else 310 %\prewordbreak\textmodediscretionary\prewordbreak 311 \wordboundary\textmodediscretionary\wordboundary 312 \fi\fi\fi 313 \fi 314 \else\ifcsname\??discretionaryaction\discretionarytoken\endcsname 315 \lastnamedcs 316 \else 317 \lang_discretionaries_check_before 318 \ifconditional\spaceafterdiscretionary 319 %\prewordbreak\hbox{#2}\relax 320 \wordboundary\hbox{#2}\relax 321 \else\ifconditional\punctafterdiscretionary 322 %\prewordbreak\hbox{#2}\relax 323 \wordboundary\hbox{#2}\relax 324 \else 325 %\prewordbreak\discretionary{\hbox{#2}}{}{\hbox{#2}}\postwordbreak 326 \wordboundary\discretionary{\hbox{#2}}{}{\hbox{#2}}\wordboundary 327 \fi\fi 328 \fi\fi 329 \nextnextnext} 330 331%D \macros 332%D {directdiscretionary} 333%D 334%D In those situations where the nature of characters is less predictable, we can 335%D use the more direct approach: 336 337\unexpanded\def\directdiscretionary 338 {\csname\??discretionarymode 339 \ifcase\discretionarymode 340 n% 341 \else 342 d% 343 \fi 344 \endcsname} 345 346\unexpanded\def\indirectdiscretionary 347 {\csname\??discretionarymode 348 \ifcase\discretionarymode 349 n% 350 \else 351 i% 352 \fi 353 \endcsname} 354 355\setuvalue{\??discretionarymode d}#1% 356 {\edef\discretionarytoken{\detokenize{#1}}% 357 \let\textmodediscretionary\compoundhyphen 358 \ifcsname\??discretionaryaction\discretionarytoken\endcsname 359 \expandafter\lastnamedcs 360 \else 361 \expandafter\indirectdiscretionary 362 \fi{#1}} 363 364\setuvalue{\??discretionarymode i}#1% 365 %{\prewordbreak\discretionary{\hbox{#1}}{}{\hbox{#1}}\postwordbreak} 366 {\wordboundary\discretionary{\hbox{#1}}{}{\hbox{#1}}\wordboundary} 367 368\unexpanded\def\definetextmodediscretionary #1 369 {\setvalue{\??discretionaryaction\detokenize{#1}}} 370 371% \start \hsize 1mm 372% test |||test test|||, test\blank 373% test test|-|, test|-| and test|-|test\blank 374% test test|_|, test|_| and test|_|test\blank 375% test cd|'|tje\blank 376% test |(|test test|)|, test\blank 377% test test test|x|, test\blank 378% test|~|test 379% test|^|test 380% \stop 381 382% x\discretionary{1}{2}{3}xxxxxxx 383% xxxxxxx\discretionary{1}{2}{3}x 384% 385% xxx3xxx 386% xxx1<newline>2xxx 387 388\def\lang_discretionaries_hyphen_like#1#2% 389 {\ifconditional\spaceafterdiscretionary 390 %prewordbreak\hbox{#1}\relax 391 \wordboundary\hbox{#1}\relax 392 \else\ifconditional\punctafterdiscretionary 393 %prewordbreak\hbox{#1}\relax 394 \wordboundary\hbox{#1}\relax 395 \else 396 %\prewordbreak#2\postwordbreak % was prewordbreak 397 \wordboundary#2\wordboundary 398 \fi\fi} 399 400\definetextmodediscretionary {} 401 {\lang_discretionaries_hyphen_like\textmodehyphen\textmodehyphendiscretionary} 402 403\definetextmodediscretionary - 404 {\lang_discretionaries_hyphen_like\normalhyphen\normalhyphendiscretionary} 405 406\definetextmodediscretionary _ 407 {\lang_discretionaries_hyphen_like\composedhyphen\composedhyphendiscretionary} 408 409\definetextmodediscretionary ) 410 {\lang_discretionaries_hyphen_like{)}{\discretionary{-)}{}{)}}} 411 412\definetextmodediscretionary ( 413 {\ifdim\lastskip>\zeropoint 414 %(\prewordbreak 415 (\wordboundary 416 \else 417 %\prewordbreak\discretionary{}{(-}{(}\prewordbreak 418 \wordboundary\discretionary{}{(-}{(}\wordboundary 419 \fi} 420 421\definetextmodediscretionary ~ 422 %{\prewordbreak\discretionary{-}{}{\thinspace}\postwordbreak} 423 {\wordboundary\discretionary{-}{}{\thinspace}\wordboundary} 424 425\definetextmodediscretionary ' 426 %{\prewordbreak\discretionary{-}{}{'}\postwordbreak} 427 {\wordboundary\discretionary{-}{}{'}\wordboundary} 428 429\definetextmodediscretionary ^ 430 %{\prewordbreak\discretionary{\hbox{\normalstartimath|\normalstopimath}}{}{\hbox{\normalstartimath|\normalstopimath}}% 431 % \postwordbreak} % bugged 432 {\wordboundary\discretionary{\hbox{\normalstartimath|\normalstopimath}}{}{\hbox{\normalstartimath|\normalstopimath}}% 433 \wordboundary} % bugged 434 435\definetextmodediscretionary < 436 %{\beginofsubsentence\prewordbreak\beginofsubsentencespacing 437 {\beginofsubsentence\wordboundary\beginofsubsentencespacing 438 \aftergroup\ignorespaces} % tricky, we need to go over the \nextnextnext 439 440\definetextmodediscretionary > 441 {\removeunwantedspaces 442 %\endofsubsentencespacing\prewordbreak\endofsubsentence} 443 \endofsubsentencespacing\wordboundary\endofsubsentence} 444 445\definetextmodediscretionary = 446 {\removeunwantedspaces 447 %\prewordbreak\midsentence\prewordbreak 448 \wordboundary\midsentence\wordboundary 449 \aftergroup\ignorespaces} 450 451% french 452 453%definetextmodediscretionary : {\removeunwantedspaces\prewordbreak\kern\hspaceamount\empty{:}:} 454%definetextmodediscretionary ; {\removeunwantedspaces\prewordbreak\kern\hspaceamount\empty{;};} 455%definetextmodediscretionary ? {\removeunwantedspaces\prewordbreak\kern\hspaceamount\empty{?}?} 456%definetextmodediscretionary ! {\removeunwantedspaces\prewordbreak\kern\hspaceamount\empty{!}!} 457 458\definetextmodediscretionary : {\removeunwantedspaces\wordboundary\kern\hspaceamount\empty{:}:} 459\definetextmodediscretionary ; {\removeunwantedspaces\wordboundary\kern\hspaceamount\empty{;};} 460\definetextmodediscretionary ? {\removeunwantedspaces\wordboundary\kern\hspaceamount\empty{?}?} 461\definetextmodediscretionary ! {\removeunwantedspaces\wordboundary\kern\hspaceamount\empty{!}!} 462 463%definetextmodediscretionary * {\prewordbreak\discretionary{-}{}{\kern.05\emwidth}\prewordbreak} 464\definetextmodediscretionary * {\wordboundary\discretionary{-}{}{\kern.05\emwidth}\wordboundary} 465 466% spanish 467 468%definetextmodediscretionary ?? {\prewordbreak\questiondown} 469%definetextmodediscretionary !! {\prewordbreak\exclamdown} 470 471\definetextmodediscretionary ?? {\wordboundary\questiondown} 472\definetextmodediscretionary !! {\wordboundary\exclamdown} 473 474%D \installdiscretionary | + 475%D \installdiscretionary + = 476 477\def\defaultdiscretionaryhyphen{\compoundhyphen} 478 479\installdiscretionary | \defaultdiscretionaryhyphen % installs in ctx and prt will fall back on it 480 481%D \macros 482%D {fakecompoundhyphen} 483%D 484%D In headers and footers as well as in active pieces of text we need a dirty hack. 485%D Try to imagine what is needed to savely break the next text across a line and at 486%D the same time make the words interactive. 487%D 488%D \starttyping 489%D \goto{Some||Long||Word} 490%D \stoptyping 491 492\unexpanded\def\fakecompoundhyphen 493 {\def\|{\mathortext\vert\lang_compounds_fake_hyphen}} 494 495\def\lang_compounds_fake_hyphen 496 {\def##1|% 497 {\doifelsenothing{##1}\compoundhyphen{##1}% 498 \kern\compoundbreakpoint\allowbreak}} 499 500%D \macros 501%D {midworddiscretionary} 502%D 503%D If needed, one can add a discretionary hyphen using \type 504%D {\midworddiscretionary}. This macro does the same as \PLAIN\ \TEX's \type {\-}, 505%D but, like the ones implemented earlier, this one also looks ahead for spaces and 506%D grouping tokens. 507 508\unexpanded\def\midworddiscretionary 509 {\futurelet\nexttoken\lang_discretionaries_mid_word} 510 511\def\lang_discretionaries_mid_word 512 {\ifx\nexttoken\blankspace\else 513 \ifx\nexttoken\bgroup \else 514 \ifx\nexttoken\egroup \else 515 \discretionary{-}{}{}% 516 \fi\fi\fi} 517 518% As this is rather mkii-ish we keep the mkiv definition around for educational 519% purposes but consider this feature obsolete in post mkii versions. 520 521% %D \macros 522% %D {installcompoundcharacter} 523% %D 524% %D When Tobias Burnus started translating the dutch manual of \PPCHTEX\ into german, 525% %D he suggested to let \CONTEXT\ support the \type{german.sty} method of handling 526% %D compound characters, especially the umlaut. This package is meant for use with 527% %D \PLAIN\ \TEX\ as well as \LATEX. 528% %D 529% %D I decided to implement compound character support as versatile as possible. As a 530% %D result one can define his own compound character support, like: 531% %D 532% %D \starttyping 533% %D \installcompoundcharacter "a {\"a} 534% %D \installcompoundcharacter "e {\"e} 535% %D \installcompoundcharacter "i {\"i} 536% %D \installcompoundcharacter "u {\"u} 537% %D \installcompoundcharacter "o {\"o} 538% %D \installcompoundcharacter "s {\SS} 539% %D \stoptyping 540% %D 541% %D or even 542% %D 543% %D \starttyping 544% %D \installcompoundcharacter "ck {\discretionary {k-}{k}{ck}} 545% %D \installcompoundcharacter "ff {\discretionary{ff-}{f}{ff}} 546% %D \stoptyping 547% %D 548% %D The support is not limited to alphabetic characters, so the next definition is 549% %D also valid. 550% %D 551% %D \starttyping 552% %D \installcompoundcharacter ". {.\doifnextcharelse{\spacetoken}{}{\kern.125em}} 553% %D \stoptyping 554% %D 555% %D The implementation looks familiar and uses the same tricks as mentioned earlier 556% %D in this module. We take care of two arguments, which complicates things a bit. 557% 558% \installcorenamespace{compoundnormal} 559% \installcorenamespace{compoundsingle} 560% \installcorenamespace{compoundmultiple} 561% \installcorenamespace{compounddefinition} 562% 563% %D When I started working on \MKIV\ code, we needed a different approach for 564% %D defining the active character itself. In \MKII\ as well as in \MKIV\ we now use 565% %D the catcode vectors. 566% 567% \setnewconstant\compoundcharactermode\plusone 568% 569% \newcount\c_lang_compounds_character 570% 571% \def\installcompoundcharacter #1#2#3 #4% {#4} no grouping 572% {\ifcase\compoundcharactermode 573% % ignore mode 574% \else 575% \chardef\c_lang_compounds_character`#1% 576% \expandafter\chardef\csname\??compoundnormal\string#1\endcsname\c_lang_compounds_character 577% \def\!!stringa{#3}% 578% \expandafter\def\csname\ifx\!!stringa\empty\??compoundsingle\else\??compoundmultiple\fi\detokenize{#1#2#3}\endcsname{#4}% 579% \setevalue{\??compounddefinition\detokenize{#1}}{\noexpand\lang_compounds_handle_character{\detokenize{#1}}}% beter nr's 580% \expandafter\letcatcodecommand\expandafter\ctxcatcodes\expandafter\c_lang_compounds_character\csname\??compounddefinition\detokenize{#1}\endcsname 581% \fi} 582% 583% %D We can also ignore definitions (needed in for instance \XML). Beware, this macro 584% %D is supposed to be used grouped! 585% 586% \def\ignorecompoundcharacter 587% {\compoundcharactermode\zerocount} 588 589\let\ignorecompoundcharacter\relax 590 591% %D In handling the compound characters we have to take care of \type {\bgroup} and 592% %D \type {\egroup} tokens, so we end up with a multi||step interpretation macro. We 593% %D look ahead for a \type {\bgroup}, \type {\egroup} or \type {\blankspace}. Being 594% %D no user of this mechanism, the credits for testing them goes to Tobias Burnus, 595% %D the first german user of \CONTEXT. 596% %D 597% %D We need to look into the future with \type{\futurelet} to prevent spaces from 598% %D disappearing. 599% 600% \def\lang_compounds_handle_character#1% 601% {\def\lang_compounds_handle_character_finish{\lang_compounds_handle_character_finish_indeed{#1}}% 602% \futurelet\nexttoken\xhandlecompoundcharacter} 603% 604% \def\lang_compounds_handle_character_finish_indeed 605% {\ifx\nexttoken\bgroup 606% %\expandafter\lang_compounds_handle_character_pickup % handle "{ee} -> \"ee 607% %\expandafter\gobbleoneargument % forget "{ee} -> ee 608% \expandafter\lang_compounds_handle_character_one % ignore "{ee} -> "ee 609% \else\ifx\nexttoken\egroup 610% \doubleexpandafter\lang_compounds_handle_character_normal 611% \else\ifx\nexttoken\blankspace 612% \tripleexpandafter\lang_compounds_handle_character_normal 613% \else 614% \tripleexpandafter\lang_compounds_handle_character_pickup 615% \fi\fi\fi} 616% 617% \def\lang_compounds_handle_character_normal#1% 618% {\csname\??compoundnormal\string#1\endcsname} 619% 620% \def\lang_compounds_handle_character_pickup#1#2% preserve space 621% {\def\lang_compounds_handle_character_finish{\lang_compounds_handle_character_finish_indeed#1#2}% 622% \futurelet\nexttoken\lang_compounds_handle_character_finish} 623% 624% \def\lang_compounds_handle_character_finish_indeed 625% {\ifx\nexttoken\bgroup 626% \expandafter\lang_compounds_handle_character_one 627% \else\ifx\nexttoken\egroup 628% \doubleexpandafter\lang_compounds_handle_character_one 629% \else\ifx\nexttoken\blankspace 630% \tripleexpandafter\lang_compounds_handle_character_one 631% \else 632% \tripleexpandafter\lang_compounds_handle_character_two 633% \fi\fi\fi} 634% 635% %D Besides taken care of the grouping and space tokens, we have to deal with three 636% %D situations. First we look if the next character equals the first one, if so, then 637% %D we just insert the original. Next we look if indeed a compound character is 638% %D defined. We either execute the compound character or just insert the first. So we 639% %D have 640% %D 641% %D \starttyping 642% %D <key><key> <key><known> <key><unknown> 643% %D \stoptyping 644% %D 645% %D In later modules we will see how these commands are used. 646% 647% \def\lang_compounds_handle_character_one#1#2% 648% {\if\string#1\string#2% was: \ifx#1#2% 649% %\expandafter\let\expandafter\next\csname\??compoundnormal\string#1\endcsname 650% \csname\??compoundnormal\string#1\expandafter\endcsname 651% \else\ifcsname\??compoundsingle\string#1\string#2\endcsname 652% %\expandafter\let\expandafter\next\lastnamedcs 653% \expandafter\lastnamedcs 654% \else 655% %\expandafter\let\expandafter\next\lastnamedcs 656% \expandafter\lastnamedcs 657% \fi\fi} 658% 659% \def\lang_compounds_handle_character_two#1#2#3% 660% {\if\string#1\string#2% 661% \def\next{\csname\??compoundnormal\string#1\endcsname#3}% 662% \else\ifcsname\??compoundmultiple\string#1\string#2\string#3\endcsname 663% \expandafter\let\expandafter\next\lastnamedcs 664% \else\ifcsname\??compoundsingle\string#1\string#2\endcsname 665% \expandafter\let\expandafter\next\lastnamedcs 666% \else 667% \expandafter\let\expandafter\next\lastnamedcs 668% \fi\fi\fi 669% \next} 670% 671% %D For very obscure applications (see for an application \type {lang-sla.tex}) we 672% %D provide: 673% 674% % \def\simplifiedcompoundcharacter#1#2% 675% % {\ifcsname\??compoundsingle\string#1\string#2\endcsname 676% % \doubleexpandafter\firstofoneargument\csname\??compoundsingle\string#1\string#2\endcsname 677% % \else 678% % #2% 679% % \fi} 680% 681% \def\simplifiedcompoundcharacter#1#2% 682% {\ifcsname\??compoundsingle\string#1\string#2\endcsname 683% \doubleexpandafter\firstofoneargument\lastnamedcs 684% \else 685% #2% 686% \fi} 687 688%D \macros 689%D {disablediscretionaries,disablecompoundcharacter} 690%D 691%D Occasionally we need to disable this mechanism. For the moment we assume that 692%D \type {|} is used. 693 694\let\disablediscretionaries \ignorediscretionaries 695\let\disablecompoundcharacters\ignorecompoundcharacter 696 697%D \macros 698%D {normalcompound} 699%D 700%D Handy in for instance XML. (Kind of obsolete) 701 702\ifdefined\normalcompound \else \let\normalcompound=| \fi 703 704%D \macros 705%D {compound} 706%D 707%D We will overload the already active \type {|} so we have to save its meaning in 708%D order to be able to use this handy macro. 709%D 710%D \starttyping 711%D so test\compound{}test can be used instead of test||test 712%D \stoptyping 713 714\bgroup 715 716 \catcode\barasciicode\activecatcode 717 718 \unexpanded\gdef\compound#1{|#1|} 719 720 \doglobal \appendtoks 721 \def|#1|{\ifx#1\empty\empty-\else#1\fi}% 722 \to \everysimplifycommands 723 724\egroup 725 726%D Here we hook some code into the clean up mechanism needed for verbatim data. 727 728\appendtoks 729 %\disablecompoundcharacters 730 \disablediscretionaries 731\to \everycleanupfeatures 732 733\protect \endinput 734 |