diff options
103 files changed, 16322 insertions, 645 deletions
diff --git a/doc/context/documents/general/manuals/cld-mkiv.pdf b/doc/context/documents/general/manuals/cld-mkiv.pdf Binary files differnew file mode 100644 index 000000000..5dfa14a4a --- /dev/null +++ b/doc/context/documents/general/manuals/cld-mkiv.pdf diff --git a/doc/context/documents/general/manuals/luatex.pdf b/doc/context/documents/general/manuals/luatex.pdf Binary files differindex 43a4cf660..32d761a5e 100644 --- a/doc/context/documents/general/manuals/luatex.pdf +++ b/doc/context/documents/general/manuals/luatex.pdf diff --git a/doc/context/documents/general/manuals/workflows-mkiv.pdf b/doc/context/documents/general/manuals/workflows-mkiv.pdf Binary files differindex e156a2efc..b0af6d56e 100644 --- a/doc/context/documents/general/manuals/workflows-mkiv.pdf +++ b/doc/context/documents/general/manuals/workflows-mkiv.pdf diff --git a/doc/context/documents/general/qrcs/setup-cs.pdf b/doc/context/documents/general/qrcs/setup-cs.pdf Binary files differindex f88bb3867..27503d751 100644 --- a/doc/context/documents/general/qrcs/setup-cs.pdf +++ b/doc/context/documents/general/qrcs/setup-cs.pdf diff --git a/doc/context/documents/general/qrcs/setup-de.pdf b/doc/context/documents/general/qrcs/setup-de.pdf Binary files differindex bb8eb1917..60ed45aed 100644 --- a/doc/context/documents/general/qrcs/setup-de.pdf +++ b/doc/context/documents/general/qrcs/setup-de.pdf diff --git a/doc/context/documents/general/qrcs/setup-en.pdf b/doc/context/documents/general/qrcs/setup-en.pdf Binary files differindex 365dc0f01..42aaf874c 100644 --- a/doc/context/documents/general/qrcs/setup-en.pdf +++ b/doc/context/documents/general/qrcs/setup-en.pdf diff --git a/doc/context/documents/general/qrcs/setup-fr.pdf b/doc/context/documents/general/qrcs/setup-fr.pdf Binary files differindex de24997f2..14c3836a6 100644 --- a/doc/context/documents/general/qrcs/setup-fr.pdf +++ b/doc/context/documents/general/qrcs/setup-fr.pdf diff --git a/doc/context/documents/general/qrcs/setup-it.pdf b/doc/context/documents/general/qrcs/setup-it.pdf Binary files differindex 2423aa558..ae7ac6615 100644 --- a/doc/context/documents/general/qrcs/setup-it.pdf +++ b/doc/context/documents/general/qrcs/setup-it.pdf diff --git a/doc/context/documents/general/qrcs/setup-nl.pdf b/doc/context/documents/general/qrcs/setup-nl.pdf Binary files differindex 424862260..4c758ad3c 100644 --- a/doc/context/documents/general/qrcs/setup-nl.pdf +++ b/doc/context/documents/general/qrcs/setup-nl.pdf diff --git a/doc/context/documents/general/qrcs/setup-ro.pdf b/doc/context/documents/general/qrcs/setup-ro.pdf Binary files differindex be691d19e..617df4672 100644 --- a/doc/context/documents/general/qrcs/setup-ro.pdf +++ b/doc/context/documents/general/qrcs/setup-ro.pdf diff --git a/doc/context/sources/general/manuals/cld/cld-abitoflua.tex b/doc/context/sources/general/manuals/cld/cld-abitoflua.tex new file mode 100644 index 000000000..5716be6d6 --- /dev/null +++ b/doc/context/sources/general/manuals/cld/cld-abitoflua.tex @@ -0,0 +1,840 @@ +% language=uk + +\startcomponent cld-abitoflua + +\environment cld-environment + +\startchapter[title=A bit of Lua] + +\startsection[title=The language] + +\index[lua]{\LUA} + +Small is beautiful and this is definitely true for the programming language \LUA\ +(moon in Portuguese). We had good reasons for using this language in \LUATEX: +simplicity, speed, syntax and size to mention a few. Of course personal taste +also played a role and after using a couple of scripting languages extensively +the switch to \LUA\ was rather pleasant. + +As the \LUA\ reference manual is an excellent book there is no reason to discuss +the language in great detail: just buy \quote {Programming in \LUA} by the \LUA\ +team. Nevertheless I will give a short summary of the important concepts but +consult the book if you want more details. + +\stopsection + +\startsection[title=Data types] + +\index{functions} +\index{variables} +\index{strings} +\index{numbers} +\index{booleans} +\index{tables} + +The most basic data type is \type {nil}. When we define a variable, we don't need +to give it a value: + +\starttyping +local v +\stoptyping + +Here the variable \type {v} can get any value but till that +happens it equals \type {nil}. There are simple data types like +\type {numbers}, \type {booleans} and \type {strings}. Here are +some numbers: + +\starttyping +local n = 1 + 2 * 3 +local x = 2.3 +\stoptyping + +Numbers are always floats \footnote {This is true for all versions upto 5.2 but +following version can have a more hybrid model.} and you can use the normal +arithmetic operators on them as well as functions defined in the math library. +Inside \TEX\ we have only integers, although for instance dimensions can be +specified in points using floats but that's more syntactic sugar. One reason for +using integers in \TEX\ has been that this was the only way to guarantee +portability across platforms. However, we're 30 years along the road and in \LUA\ +the floats are implemented identical across platforms, so we don't need to worry +about compatibility. + +Strings in \LUA\ can be given between quotes or can be so called long strings +forced by square brackets. + +\starttyping +local s = "Whatever" +local t = s .. ' you want' +local u = t .. [[ to know]] .. [[--[ about Lua!]--]] +\stoptyping + +The two periods indicate a concatenation. Strings are hashed, so when you say: + +\starttyping +local s = "Whatever" +local t = "Whatever" +local u = t +\stoptyping + +only one instance of \type {Whatever} is present in memory and this fact makes +\LUA\ very efficient with respect to strings. Strings are constants and therefore +when you change variable \type {s}, variable \type {t} keeps its value. When you +compare strings, in fact you compare pointers, a method that is really fast. This +compensates the time spent on hashing pretty well. + +Booleans are normally used to keep a state or the result from an expression. + +\starttyping +local b = false +local c = n > 10 and s == "whatever" +\stoptyping + +The other value is \type {true}. There is something that you need +to keep in mind when you do testing on variables that are yet +unset. + +\starttyping +local b = false +local n +\stoptyping + +The following applies when \type {b} and \type {n} are defined this way: + +\starttabulate[|Tl|Tl|] +\NC b == false \NC true \NC \NR +\NC n == false \NC false \NC \NR +\NC n == nil \NC true \NC \NR +\NC b == nil \NC false \NC \NR +\NC b == n \NC false \NC \NR +\NC n == nil \NC true \NC \NR +\stoptabulate + +Often a test looks like: + +\starttyping +if somevar then + ... +else + ... +end +\stoptyping + +In this case we enter the else branch when \type {somevar} is either \type {nil} +or \type {false}. It also means that by looking at the code we cannot beforehand +conclude that \type {somevar} equals \type {true} or something else. If you want +to really distinguish between the two cases you can be more explicit: + +\starttyping +if somevar == nil then + ... +elseif somevar == false then + ... +else + ... +end +\stoptyping + +or + +\starttyping +if somevar == true then + ... +else + ... +end +\stoptyping + +but such an explicit test is seldom needed. + +There are a few more data types: tables and functions. Tables are very important +and you can recognize them by the same curly braces that make \TEX\ famous: + +\starttyping +local t = { 1, 2, 3 } +local u = { a = 4, b = 9, c = 16 } +local v = { [1] = "a", [3] = "2", [4] = false } +local w = { 1, 2, 3, a = 4, b = 9, c = 16 } +\stoptyping + +The \type {t} is an indexed table and \type {u} a hashed table. Because the +second slot is empty, table \type {v} is partially indexed (slot 1) and partially +hashed (the others). There is a gray area there, for instance, what happens when +you nil a slot in an indexed table? In practice you will not run into problems as +you will either use a hashed table, or an indexed table (with no holes), so table +\type {w} is not uncommon. + +We mentioned that strings are in fact shared (hashed) but that an assignment of a +string to a variable makes that variable behave like a constant. Contrary to +that, when you assign a table, and then copy that variable, both variables can be +used to change the table. Take this: + +\starttyping +local t = { 1, 2, 3 } +local u = t +\stoptyping + +We can change the content of the table as follows: + +\starttyping +t[1], t[3] = t[3], t[1] +\stoptyping + +Here we swap two cells. This is an example of a parallel assigment. However, the +following does the same: + +\starttyping +t[1], t[3] = u[3], u[1] +\stoptyping + +After this, both \type {t} and \type {u} still share the same table. This kind of +behaviour is quite natural. Keep in mind that expressions are evaluated first, so + +\starttyping +t[#t+1], t[#t+1] = 23, 45 +\stoptyping + +Makes no sense, as the values end up in the same slot. There is no gain in speed +so using parallel assignments is mostly a convenience feature. + +There are a few specialized data types in \LUA, like \type {coroutines} (built +in), \type {file} (when opened), \type {lpeg} (only when this library is linked +in or loaded). These are called \quote {userdata} objects and in \LUATEX\ we have +more userdata objects as we will see in later chapters. Of them nodes are the +most noticeable: they are the core data type of the \TEX\ machinery. Other +libraries, like \type {math} and \type {bit32} are just collections of functions +operating on numbers. + +Functions look like this: + +\starttyping +function sum(a,b) + print(a, b, a + b) +end +\stoptyping + +or this: + +\starttyping +function sum(a,b) + return a + b +end +\stoptyping + +There can be many arguments of all kind of types and there can be multiple return +values. A function is a real type, so you can say: + +\starttyping +local f = function(s) print("the value is: " .. s) end +\stoptyping + +In all these examples we defined variables as \type {local}. This is a good +practice and avoids clashes. Now watch the following: + +\starttyping +local n = 1 + +function sum(a,b) + n = n + 1 + return a + b +end + +function report() + print("number of summations: " .. n) +end +\stoptyping + +Here the variable \type {n} is visible after its definition and accessible for +the two global functions. Actually the variable is visible to all the code +following, unless of course we define a new variable with the same name. We can +hide \type {n} as follows: + +\starttyping +do + local n = 1 + + sum = function(a,b) + n = n + 1 + return a + b + end + + report = function() + print("number of summations: " .. n) + end +end +\stoptyping + +This example also shows another way of defining the function: by assignment. + +The \typ {do ... end} creates a so called closure. There are many places where +such closures are created, for instance in function bodies or branches like \typ +{if ... then ... else}. This means that in the following snippet, variable \type +{b} is not seen after the end: + +\starttyping +if a > 10 then + local b = a + 10 + print(b*b) +end +\stoptyping + +When you process a blob of \LUA\ code in \TEX\ (using \type {\directlua} or \type +{\latelua}) it happens in a closure with an implied \typ {do ... end}. So, \type +{local} defined variables are really local. + +\stopsection + +\startsection[title=\TEX's data types] + +We mentioned \type {numbers}. At the \TEX\ end we have counters as well as +dimensions. Both are numbers but dimensions are specified differently + +\starttyping +local n = tex.count[0] +local m = tex.dimen.lineheight +local o = tex.sp("10.3pt") -- sp or 'scaled point' is the smallest unit +\stoptyping + +The unit of dimension is \quote {scaled point} and this is a pretty small unit: +10 points equals to 655360 such units. + +Another accessible data type is tokens. They are automatically converted to +strings and vice versa. + +\starttyping +tex.toks[0] = "message" +print(tex.toks[0]) +\stoptyping + +Be aware of the fact that the tokens are letters so the following will come out +as text and not issue a message: + +\starttyping +tex.toks[0] = "\message{just text}" +print(tex.toks[0]) +\stoptyping + +\stopsection + +\startsection[title=Control structures] + +\index{loops} + +Loops are not much different from other languages: we have \typ {for ... do}, +\typ {while ... do} and \typ {repeat ... until}. We start with the simplest case: + +\starttyping +for index=1,10 do + print(index) +end +\stoptyping + +You can specify a step and go downward as well: + +\starttyping +for index=22,2,-2 do + print(index) +end +\stoptyping + +Indexed tables can be traversed this way: + +\starttyping +for index=1,#list do + print(index, list[index]) +end +\stoptyping + +Hashed tables on the other hand are dealt with as follows: + +\starttyping +for key, value in next, list do + print(key, value) +end +\stoptyping + +Here \type {next} is a built in function. There is more to say about this +mechanism but the average user will use only this variant. Slightly less +efficient is the following, more readable variant: + +\starttyping +for key, value in pairs(list) do + print(key, value) +end +\stoptyping + +and for an indexed table: + +\starttyping +for index, value in ipairs(list) do + print(index, value) +end +\stoptyping + +The function call to \type {pairs(list)} returns \typ {next, list} so there is an +(often neglectable) extra overhead of one function call. + +The other two loop variants, \type {while} and \type {repeat}, are similar. + +\starttyping +i = 0 +while i < 10 do + i = i + 1 + print(i) +end +\stoptyping + +This can also be written as: + +\starttyping +i = 0 +repeat + i = i + 1 + print(i) +until i = 10 +\stoptyping + +Or: + +\starttyping +i = 0 +while true do + i = i + 1 + print(i) + if i = 10 then + break + end +end +\stoptyping +\stopsection + +Of course you can use more complex expressions in such constructs. + +\startsection[title=Conditions] + +\index{expressions} + +Conditions have the following form: + +\starttyping +if a == b or c > d or e then + ... +elseif f == g then + ... +else + ... +end +\stoptyping + +Watch the double \type {==}. The complement of this is \type {~=}. Precedence is +similar to other languages. In practice, as strings are hashed. Tests like + +\starttyping +if key == "first" then + ... +end +\stoptyping + +and + +\starttyping +if n == 1 then + ... +end +\stoptyping + +are equally efficient. There is really no need to use numbers to identify states +instead of more verbose strings. + +\stopsection + +\startsection[title=Namespaces] + +\index{namespaces} + +Functionality can be grouped in libraries. There are a few default libraries, +like \type {string}, \type {table}, \type {lpeg}, \type {math}, \type {io} and +\type {os} and \LUATEX\ adds some more, like \type {node}, \type {tex} and \type +{texio}. + +A library is in fact nothing more than a bunch of functionality organized using a +table, where the table provides a namespace as well as place to store public +variables. Of course there can be local (hidden) variables used in defining +functions. + +\starttyping +do + mylib = { } + + local n = 1 + + function mylib.sum(a,b) + n = n + 1 + return a + b + end + + function mylib.report() + print("number of summations: " .. n) + end +end +\stoptyping + +The defined function can be called like: + +\starttyping +mylib.report() +\stoptyping + +You can also create a shortcut, This speeds up the process because there are less +lookups then. In the following code multiple calls take place: + +\starttyping +local sum = mylib.sum + +for i=1,10 do + for j=1,10 do + print(i, j, sum(i,j)) + end +end + +mylib.report() +\stoptyping + +As \LUA\ is pretty fast you should not overestimate the speedup, especially not +when a function is called seldom. There is an important side effect here: in the +case of: + +\starttyping + print(i, j, sum(i,j)) +\stoptyping + +the meaning of \type {sum} is frozen. But in the case of + +\starttyping + print(i, j, mylib.sum(i,j)) +\stoptyping + +The current meaning is taken, that is: each time the interpreter will access +\type {mylib} and get the current meaning of \type {sum}. And there can be a good +reason for this, for instance when the meaning is adapted to different +situations. + +In \CONTEXT\ we have quite some code organized this way. Although much is exposed +(if only because it is used all over the place) you should be careful in using +functions (and data) that are still experimental. There are a couple of general +libraries and some extend the core \LUA\ libraries. You might want to take a look +at the files in the distribution that start with \type {l-}, like \type +{l-table.lua}. These files are preloaded.\footnote {In fact, if you write scripts +that need their functionality, you can use \type {mtxrun} to process the script, +as \type {mtxrun} has the core libraries preloaded as well.} For instance, if you +want to inspect a table, you can say: + +\starttyping +local t = { "aap", "noot", "mies" } +table.print(t) +\stoptyping + +You can get an overview of what is implemented by running the following command: + +\starttyping +context s-tra-02 --mode=tablet +\stoptyping + +{\em todo: add nice synonym for this module and also add helpinfo at the to so +that we can do \type {context --styles}} + +\stopsection + +\startsection[title=Comment] + +\index{comment} + +You can add comments to your \LUA\ code. There are basically two methods: one +liners and multi line comments. + +\starttyping +local option = "test" -- use this option with care + +local method = "unknown" --[[comments can be very long and when entered + this way they and span multiple lines]] +\stoptyping + +The so called long comments look like long strings preceded by \type {--} and +there can be more complex boundary sequences. + +\stopsection + +\startsection[title=Pitfalls] + +Sometimes \type {nil} can bite you, especially in tables, as they have a dual nature: +indexed as well as hashed. + +\startbuffer +\startluacode +local n1 = # { nil, 1, 2, nil } -- 3 +local n2 = # { nil, nil, 1, 2, nil } -- 0 + +context("n1 = %s and n2 = %s",n1,n2) +\stopluacode +\stopbuffer + +\typebuffer + +results in: \getbuffer + +So, you cannot really depend on the length operator here. On the other hand, with: + +\startbuffer +\startluacode +local function check(...) + return select("#",...) +end + +local n1 = check ( nil, 1, 2, nil ) -- 4 +local n2 = check ( nil, nil, 1, 2, nil ) -- 5 + +context("n1 = %s and n2 = %s",n1,n2) +\stopluacode +\stopbuffer + +\typebuffer + +we get: \getbuffer, so the \type {select} is quite useable. However, that function also +has its specialities. The following example needs some close reading: + +\startbuffer +\startluacode +local function filter(n,...) + return select(n,...) +end + +local v1 = { filter ( 1, 1, 2, 3 ) } +local v2 = { filter ( 2, 1, 2, 3 ) } +local v3 = { filter ( 3, 1, 2, 3 ) } + +context("v1 = %+t and v2 = %+t and v3 = %+t",v1,v2,v3) +\stopluacode +\stopbuffer + +\typebuffer + +We collect the result in a table and show the concatination: + +\getbuffer + +So, what you effectively get is the whole list starting with the given offset. + +\startbuffer +\startluacode +local function filter(n,...) + return (select(n,...)) +end + +local v1 = { filter ( 1, 1, 2, 3 ) } +local v2 = { filter ( 2, 1, 2, 3 ) } +local v3 = { filter ( 3, 1, 2, 3 ) } + +context("v1 = %+t and v2 = %+t and v3 = %+t",v1,v2,v3) +\stopluacode +\stopbuffer + +\typebuffer + +Now we get: \getbuffer. The extra \type {()} around the result makes sure that +we only get one return value. + +Of course the same effect can be achieved as follows: + +\starttyping +local function filter(n,...) + return select(n,...) +end + +local v1 = filter ( 1, 1, 2, 3 ) +local v2 = filter ( 2, 1, 2, 3 ) +local v3 = filter ( 3, 1, 2, 3 ) + +context("v1 = %s and v2 = %s and v3 = %s",v1,v2,v3) +\stoptyping + +\stopsection + +\startsection[title={A few suggestions}] + +You can wrap all kind of functionality in functions but sometimes it makes no +sense to add the overhead of a call as the same can be done with hardly any code. + +If you want a slice of a table, you can copy the range needed to a new table. A +simple version with no bounds checking is: + +\starttyping +local new = { } for i=a,b do new[#new+1] = old[i] end +\stoptyping + +Another, much faster, variant is the following. + +\starttyping +local new = { unpack(old,a,b) } +\stoptyping + +You can use this variant for slices that are not extremely large. The function +\type {table.sub} is an equivalent: + +\starttyping +local new = table.sub(old,a,b) +\stoptyping + +An indexed table is empty when its size equals zero: + +\starttyping +if #indexed == 0 then ... else ... end +\stoptyping + +Sometimes this is better: + +\starttyping +if indexed and #indexed == 0 then ... else ... end +\stoptyping + +So how do we test if a hashed table is empty? We can use the +\type {next} function as in: + +\starttyping +if hashed and next(indexed) then ... else ... end +\stoptyping + +Say that we have the following table: + +\starttyping +local t = { a=1, b=2, c=3 } +\stoptyping + +The call \type {next(t)} returns the first key and value: + +\starttyping +local k, v = next(t) -- "a", 1 +\stoptyping + +The second argument to \type {next} can be a key in which case the +following key and value in the hash table is returned. The result +is not predictable as a hash is unordered. The generic for loop +uses this to loop over a hashed table: + +\starttyping +for k, v in next, t do + ... +end +\stoptyping + +Anyway, when \type {next(t)} returns zero you can be sure that the table is +empty. This is how you can test for exactly one entry: + +\starttyping +if t and not next(t,next(t)) then ... else ... end +\stoptyping + +Here it starts making sense to wrap it into a function. + +\starttyping +function table.has_one_entry(t) + t and not next(t,next(t)) +end +\stoptyping + +On the other hand, this is not that usefull, unless you can spent the runtime on +it: + +\starttyping +function table.is_empty(t) + return not t or not next(t) +end +\stoptyping + +\stopsection + +\startsection[title=Interfacing] + +We have already seen that you can embed \LUA\ code using commands like: + +\starttyping +\startluacode + print("this works") +\stopluacode +\stoptyping + +This command should not be confused with: + +\starttyping +\startlua + print("this works") +\stoplua +\stoptyping + +The first variant has its own catcode regime which means that tokens between the start +and stop command are treated as \LUA\ tokens, with the exception of \TEX\ commands. The +second variant operates under the regular \TEX\ catcode regime. + +Their short variants are \type {\ctxluacode} and \type {\ctxlua} as in: + +\starttyping +\ctxluacode{print("this works")} +\ctxlua{print("this works")} +\stoptyping + +In practice you will probably use \type {\startluacode} when using or defining % \stopluacode +a blob of \LUA\ and \type {\ctxlua} for inline code. Keep in mind that the +longer versions need more initialization and have more overhead. + +There are some more commands. For instance \type {\ctxcommand} can be used as +an efficient way to access functions in the \type {commands} namespace. The +following two calls are equivalent: + +\starttyping +\ctxlua {commands.thisorthat("...")} +\ctxcommand {thisorthat("...")} +\stoptyping + +There are a few shortcuts to the \type {context} namespace. Their use can best be +seen from their meaning: + +\starttyping +\cldprocessfile#1{\directlua{context.runfile("#1")}} +\cldloadfile #1{\directlua{context.loadfile("#1")}} +\cldcontext #1{\directlua{context(#1)}} +\cldcommand #1{\directlua{context.#1}} +\stoptyping + +Each time a call out to \LUA\ happens the argument eventually gets parsed, converted +into tokens, then back into a string, compiled to bytecode and executed. The next +example code shows a mechanism that avoids this: + +\starttyping +\startctxfunction MyFunctionA + context(" A1 ") +\stopctxfunction + +\startctxfunctiondefinition MyFunctionB + context(" B2 ") +\stopctxfunctiondefinition +\stoptyping + +The first command associates a name with some \LUA\ code and that code can be +executed using: + +\starttyping +\ctxfunction{MyFunctionA} +\stoptyping + +The second definition creates a command, so there we do: + +\starttyping +\MyFunctionB +\stoptyping + +There are some more helpers but for use in document sources they make less sense. You +can always browse the source code for examples. + +\stopsection + +\stopchapter + +\stopcomponent diff --git a/doc/context/sources/general/manuals/cld/cld-afewdetails.tex b/doc/context/sources/general/manuals/cld/cld-afewdetails.tex new file mode 100644 index 000000000..6c0cf3afa --- /dev/null +++ b/doc/context/sources/general/manuals/cld/cld-afewdetails.tex @@ -0,0 +1,398 @@ +% language=uk + +\startcomponent cld-afewdetails + +\environment cld-environment + +\startchapter[title=A few Details] + +\startsection[title=Variables] + +\index{user interface} + +Normally it makes most sense to use the English version of \CONTEXT. The +advantage is that you can use English keywords, as in: + +\starttyping +context.framed( { + frame = "on", + }, + "some text" +) +\stoptyping + +If you use the Dutch interface it looks like this: + +\starttyping +context.omlijnd( { + kader = "aan", + }, + "wat tekst" +) +\stoptyping + +A rather neutral way is: + +\starttyping +context.framed( { + frame = interfaces.variables.on, + }, + "some text" +) +\stoptyping + +But as said, normally you will use the English user interface so you can forget +about these matters. However, in the \CONTEXT\ core code you will often see the +variables being used this way because there we need to support all user +interfaces. + +\stopsection + +\startsection[title=Modes] + +\index{modes} +\index{systemmodes} +\index{constants} + +Context carries a concept of modes. You can use modes to create conditional +sections in your style (and|/|or content). You can control modes in your styles +or you can set them at the command line or in job control files. When a mode test +has to be done at processing time, then you need constructs like the following: + +\starttyping +context.doifmodeelse( "screen", + function() + ... -- mode == screen + end, + function() + ... -- mode ~= screen + end +) +\stoptyping + +However, often a mode does not change during a run, and then we can use the +following method: + +\starttyping +if tex.modes["screen"] then + ... +else + ... +end +\stoptyping + +Watch how the \type {modes} table lives in the \type {tex} namespace. We also +have \type {systemmodes}. At the \TEX\ end these are mode names preceded by a +\type {*}, so the following code is similar: + +\starttyping +if tex.modes["*mymode"] then + -- this is the same +elseif tex.systemmodes["mymode"] then + -- test as this +else + -- but not this +end +\stoptyping + +Inside \CONTEXT\ we also have so called constants, and again these can be +consulted at the \LUA\ end: + +\starttyping +if tex.constants["someconstant'] then + ... +else + ... +end +\stoptyping + +But you will hardly need these and, as they are often not public, their +meaning can change, unless of course they {\em are} documented as public. + +\stopsection + +\startsection[title={Token lists}] + +\index{tokens} + +There is normally no need to mess around with nodes and tokens at the \LUA\ end +yourself. However, if you do, then you might want to flush them as well. Say that +at the \TEX\ end we have said: + +\startbuffer +\toks0 = {Don't get \inframed{framed}!} +\stopbuffer + +\typebuffer \getbuffer + +Then at the \LUA\ end you can say: + +\startbuffer +context(tex.toks[0]) +\stopbuffer + +\typebuffer + +and get: \ctxluabuffer\ In fact, token registers are exposed as strings so here, +register zero has type \type {string} and is treated as such. + +\startbuffer +context("< %s >",tex.toks[0]) +\stopbuffer + +\typebuffer + +This gives: \ctxluabuffer. But beware, if you go the reverse way, you don't get +what you might expect: + +\startbuffer +tex.toks[0] = [[\framed{oeps}]] +\stopbuffer + +\typebuffer \ctxluabuffer + +If we now say \type{\the\toks0} we will get {\tttf \the\toks0} as +all tokens are considered to be letters. + +\stopsection + +\startsection[title={Node lists}] + +\index{nodes} + +If you're not deep into \TEX\ you will never feel the need to manipulate node +lists yourself, but you might want to flush boxes. As an example we put something +in box zero (one of the scratch boxes). + +\startbuffer +\setbox0 = \hbox{Don't get \inframed{framed}!} +\stopbuffer + +\typebuffer \getbuffer + +At the \TEX\ end you can flush this box (\type {\box0}) or take a copy +(\type{\copy0}). At the \LUA\ end you would do: + +\starttyping +context.copy() +context.direct(0) +\stoptyping + +or: + +\starttyping +context.copy(false,0) +\stoptyping + +but this works as well: + +\startbuffer +context(node.copy_list(tex.box[0])) +\stopbuffer + +\typebuffer + +So we get: \ctxluabuffer\ If you do: + +\starttyping +context(tex.box[0]) +\stoptyping + +you also need to make sure that the box is freed but let's not go into those +details now. + +Here is an example if messing around with node lists that get seen before a +paragraph gets broken into lines, i.e.\ when hyphenation, font manipulation etc +take place. First we define some colors: + +\startbuffer +\definecolor[mynesting:0][r=.6] +\definecolor[mynesting:1][g=.6] +\definecolor[mynesting:2][r=.6,g=.6] +\stopbuffer + +\typebuffer \getbuffer + +Next we define a function that colors nodes in such a way that we can see the +different processing stages. + +\startbuffer +\startluacode +local enabled = false +local count = 0 +local setcolor = nodes.tracers.colors.set + +function userdata.processmystuff(head) + if enabled then + local color = "mynesting:" .. (count % 3) + -- for n in node.traverse(head) do + for n in node.traverse_id(nodes.nodecodes.glyph,head) do + setcolor(n,color) + end + count = count + 1 + return head, true + end + return head, false +end + +function userdata.enablemystuff() + enabled = true +end + +function userdata.disablemystuff() + enabled = false +end +\stopluacode +\stopbuffer + +\typebuffer \getbuffer + +We hook this function into the normalizers category of the processor callbacks: + +\startbuffer +\startluacode +nodes.tasks.appendaction("processors", "normalizers", "userdata.processmystuff") +\stopluacode +\stopbuffer + +\typebuffer \getbuffer + +We now can enable this mechanism and show an example: + +\startbuffer +\startbuffer +Node lists are processed \hbox {nested from \hbox{inside} out} which is not +what you might expect. But, \hbox{coloring} does not \hbox {happen} really +nested here, more \hbox {in} \hbox {the} \hbox {order} \hbox {of} \hbox +{processing}. +\stopbuffer + +\ctxlua{userdata.enablemystuff()} +\par \getbuffer \par +\ctxlua{userdata.disablemystuff()} +\stopbuffer + +\typebuffer + +The \type {\par} is needed because otherwise the processing is already disabled +before the paragraph gets seen by \TEX. + +\blank \getbuffer \blank + +\startbuffer +\startluacode +nodes.tasks.disableaction("processors", "userdata.processmystuff") +\stopluacode +\stopbuffer + +\typebuffer + +Instead of using an boolean to control the state, we can also do this: + +\starttyping +\startluacode +local count = 0 +local setcolor = nodes.tracers.colors.set + +function userdata.processmystuff(head) + count = count + 1 + local color = "mynesting:" .. (count % 3) + for n in node.traverse_id(nodes.nodecodes.glyph,head) do + setcolor(n,color) + end + return head, true +end + +nodes.tasks.appendaction("processors", "after", "userdata.processmystuff") +\stopluacode +\stoptyping + +\startbuffer +\startluacode +nodes.tasks.disableaction("processors", "userdata.processmystuff") +\stopluacode +\stopbuffer + +Disabling now happens with: + +\typebuffer \getbuffer + +As you might want to control these things in more details, a simple helper +mechanism was made: markers. The following example code shows the way: + +\startbuffer +\definemarker[mymarker] +\stopbuffer + +\typebuffer \getbuffer + +Again we define some colors: + +\startbuffer +\definecolor[mymarker:1][r=.6] +\definecolor[mymarker:2][g=.6] +\definecolor[mymarker:3][r=.6,g=.6] +\stopbuffer + +\typebuffer \getbuffer + +The \LUA\ code like similar to the code presented before: + +\startbuffer +\startluacode +local setcolor = nodes.tracers.colors.setlist +local getmarker = nodes.markers.get +local hlist_code = nodes.codes.hlist +local traverse_id = node.traverse_id + +function userdata.processmystuff(head) + for n in traverse_id(hlist_code,head) do + local m = getmarker(n,"mymarker") + if m then + setcolor(n.list,"mymarker:" .. m) + end + end + return head, true +end + +nodes.tasks.appendaction("processors", "after", "userdata.processmystuff") +nodes.tasks.disableaction("processors", "userdata.processmystuff") +\stopluacode +\stopbuffer + +\typebuffer \getbuffer + +This time we disabled the processor (if only because in this document we don't +want the overhead. + +\startbuffer +\startluacode +nodes.tasks.enableaction("processors", "userdata.processmystuff") +\stopluacode + +Node lists are processed \hbox \boxmarker{mymarker}{1} {nested from \hbox{inside} +out} which is not what you might expect. But, \hbox {coloring} does not \hbox +{happen} really nested here, more \hbox {in} \hbox \boxmarker{mymarker}{2} {the} +\hbox {order} \hbox {of} \hbox \boxmarker{mymarker}{3} {processing}. + +\startluacode +nodes.tasks.disableaction("processors", "userdata.processmystuff") +\stopluacode +\stopbuffer + +\typebuffer + +The result looks familiar: + +\getbuffer + +% We don't want the burden of this demo to cary on: + +% {\em If there's enough interest I will expand this section with some basic +% information on what nodes are.} + +\stopsection + +\stopchapter + +\stopcomponent diff --git a/doc/context/sources/general/manuals/cld/cld-backendcode.tex b/doc/context/sources/general/manuals/cld/cld-backendcode.tex new file mode 100644 index 000000000..9c1284baa --- /dev/null +++ b/doc/context/sources/general/manuals/cld/cld-backendcode.tex @@ -0,0 +1,388 @@ +% language=uk + +\startcomponent cld-backendcode + +\environment cld-environment + +% derived from hybrid + +\startchapter[title={Backend code}] + +\startsection [title={Introduction}] + +In \CONTEXT\ we've always separated the backend code in so called driver files. +This means that in the code related to typesetting only calls to the \API\ take +place, and no backend specific code is to be used. Currently a \PDF\ backend is +supported as well as an \XML\ export. \footnote {This chapter is derived from an +article on these matters. You can find nore information in \type {hybrid.pdf}.} + +Some \CONTEXT\ users like to add their own \PDF\ specific code to their styles or +modules. However, such extensions can interfere with existing code, especially +when resources are involved. Therefore the construction of \PDF\ data structures +and resources is rather controlled and has to be done via the official helper +macros. + +\stopsection + +\startsection [title={Structure}] + +A \PDF\ file is a tree of indirect objects. Each object has a number and the file +contains a table (or multiple tables) that relates these numbers to positions in +a file (or position in a compressed object stream). That way a file can be viewed +without reading all data: a viewer only loads what is needed. + +\starttyping +1 0 obj << + /Name (test) /Address 2 0 R +>> +2 0 obj [ + (Main Street) (24) (postal code) (MyPlace) +] +\stoptyping + +For the sake of the discussion we consider strings like \type {(test)} also to be +objects. In the next table we list what we can encounter in a \PDF\ file. There +can be indirect objects in which case a reference is used (\type{2 0 R}) and +direct ones. + +It all starts in the document's root object. From there we access the page tree +and resources. Each page carries its own resource information which makes random +access easier. A page has a page stream and there we find the to be rendered +content as a mixture of (\UNICODE) strings and special drawing and rendering +operators. Here we will not discuss them as they are mostly generated by the +engine itself or dedicated subsystems like the \METAPOST\ converter. There we use +literal or \type {\latelua} whatsits to inject code into the current stream. + +\stopsection + +\startsection [title={Data types}] + +There are several datatypes in \PDF\ and we support all of them one way or the +other. + +\starttabulate[|l|l|p|] +\FL +\NC \bf type \NC \bf form \NC \bf meaning \NC \NR +\TL +\NC constant \NC \type{/...} \NC A symbol (prescribed string). \NC \NR +\NC string \NC \type{(...)} \NC A sequence of characters in pdfdoc + encoding \NC \NR +\NC unicode \NC \type{<...>} \NC A sequence of characters in utf16 + encoding \NC \NR +\NC number \NC \type{3.1415} \NC A number constant. \NC \NR +\NC boolean \NC \type{true/false} \NC A boolean constant. \NC \NR +\NC reference \NC \type{N 0 R} \NC A reference to an object \NC \NR +\NC dictionary \NC \type{<< ... >>} \NC A collection of key value pairs + where the value itself is an (indirect) object. + \NC \NR +\NC array \NC \type{[ ... ]} \NC A list of objects or references to + objects. \NC \NR +\NC stream \NC \NC A sequence of bytes either or not packaged with + a dictionary that contains descriptive data. \NC \NR +\NC xform \NC \NC A special kind of object containing an reusable + blob of data, for example an image. \NC \NR +\LL +\stoptabulate + +While writing additional backend code, we mostly create dictionaries. + +\starttyping +<< /Name (test) /Address 2 0 R >> +\stoptyping + +In this case the indirect object can look like: + +\starttyping +[ (Main Street) (24) (postal code) (MyPlace) ] +\stoptyping + +The \LUATEX\ manual mentions primitives like \type {\pdfobj}, \type {\pdfannot}, +\type {\pdfcatalog}, etc. However, in \MKIV\ no such primitives are used. You can +still use many of them but those that push data into document or page related +resources are overloaded to do nothing at all. + +In the \LUA\ backend code you will find function calls like: + +\starttyping +local d = lpdf.dictionary { + Name = lpdf.string("test"), + Address = lpdf.array { + "Main Street", "24", "postal code", "MyPlace", + } +} +\stoptyping + +Equaly valid is: + +\starttyping +local d = lpdf.dictionary() +d.Name = "test" +\stoptyping + +Eventually the object will end up in the file using calls like: + +\starttyping +local r = lpdf.immediateobject(tostring(d)) +\stoptyping + +or using the wrapper (which permits tracing): + +\starttyping +local r = lpdf.flushobject(d) +\stoptyping + +The object content will be serialized according to the formal specification so +the proper \type {<< >>} etc.\ are added. If you want the content instead you can +use a function call: + +\starttyping +local dict = d() +\stoptyping + +An example of using references is: + +\starttyping +local a = lpdf.array { + "Main Street", "24", "postal code", "MyPlace", +} +local d = lpdf.dictionary { + Name = lpdf.string("test"), + Address = lpdf.reference(a), +} +local r = lpdf.flushobject(d) +\stoptyping + +\stopsection + +We have the following creators. Their arguments are optional. + +\starttabulate[|l|p|] +\FL +\NC \bf function \NC \bf optional parameter \NC \NR +\TL +\NC \type{lpdf.null} \NC \NC \NR +\NC \type{lpdf.number} \NC number \NC \NR +\NC \type{lpdf.constant} \NC string \NC \NR +\NC \type{lpdf.string} \NC string \NC \NR +\NC \type{lpdf.unicode} \NC string \NC \NR +\NC \type{lpdf.boolean} \NC boolean \NC \NR +\NC \type{lpdf.array} \NC indexed table of objects \NC \NR +\NC \type{lpdf.dictionary} \NC hash with key/values \NC \NR +%NC \type{lpdf.stream} \NC indexed table of operators \NC \NR +\NC \type{lpdf.reference} \NC string \NC \NR +\NC \type{lpdf.verbose} \NC indexed table of strings \NC \NR +\LL +\stoptabulate + +\ShowLuaExampleString{tostring(lpdf.null())} +\ShowLuaExampleString{tostring(lpdf.number(123))} +\ShowLuaExampleString{tostring(lpdf.constant("whatever"))} +\ShowLuaExampleString{tostring(lpdf.string("just a string"))} +\ShowLuaExampleString{tostring(lpdf.unicode("just a string"))} +\ShowLuaExampleString{tostring(lpdf.boolean(true))} +\ShowLuaExampleString{tostring(lpdf.array { 1, lpdf.constant("c"), true, "str" })} +\ShowLuaExampleString{tostring(lpdf.dictionary { a=1, b=lpdf.constant("c"), d=true, e="str" })} +%ShowLuaExampleString{tostring(lpdf.stream("whatever"))} +\ShowLuaExampleString{tostring(lpdf.reference(123))} +\ShowLuaExampleString{tostring(lpdf.verbose("whatever"))} + +\stopsection + +\startsection[title={Managing objects}] + +Flushing objects is done with: + +\starttyping +lpdf.flushobject(obj) +\stoptyping + +Reserving object is or course possible and done with: + +\starttyping +local r = lpdf.reserveobject() +\stoptyping + +Such an object is flushed with: + +\starttyping +lpdf.flushobject(r,obj) +\stoptyping + +We also support named objects: + +\starttyping +lpdf.reserveobject("myobject") + +lpdf.flushobject("myobject",obj) +\stoptyping + +A delayed object is created with: + +\starttyping +local ref = pdf.delayedobject(data) +\stoptyping + +The data will be flushed later using the object number that is returned (\type +{ref}). When you expect that many object with the same content are used, you can +use: + +\starttyping +local obj = lpdf.shareobject(data) +local ref = lpdf.shareobjectreference(data) +\stoptyping + +This one flushes the object and returns the object number. Already defined +objects are reused. In addition to this code driven optimization, some other +optimization and reuse takes place but all that happens without user +intervention. Only use this when it's really needed as it might consume more +memory and needs more processing time. + +\startsection [title={Resources}] + +While \LUATEX\ itself will embed all resources related to regular typesetting, +\MKIV\ has to take care of embedding those related to special tricks, like +annotations, spot colors, layers, shades, transparencies, metadata, etc. Because +third party modules (like tikz) also can add resources we provide some macros +that makes sure that no interference takes place: + +\starttyping +\pdfbackendsetcatalog {key}{string} +\pdfbackendsetinfo {key}{string} +\pdfbackendsetname {key}{string} + +\pdfbackendsetpageattribute {key}{string} +\pdfbackendsetpagesattribute{key}{string} +\pdfbackendsetpageresource {key}{string} + +\pdfbackendsetextgstate {key}{pdfdata} +\pdfbackendsetcolorspace {key}{pdfdata} +\pdfbackendsetpattern {key}{pdfdata} +\pdfbackendsetshade {key}{pdfdata} +\stoptyping + +One is free to use the \LUA\ interface instead, as there one has more +possibilities but when code is shared with other macro packages the macro +interface makes more sense. The names of the \LUA\ functions are similar, like: + +\starttyping +lpdf.addtoinfo(key,anything_valid_pdf) +\stoptyping + +Currently we expose a bit more of the backend code than we like and +future versions will have a more restricted access. The following +function will stay public: + +\starttyping +lpdf.addtopageresources (key,value) +lpdf.addtopageattributes (key,value) +lpdf.addtopagesattributes(key,value) + +lpdf.adddocumentextgstate(key,value) +lpdf.adddocumentcolorspac(key,value) +lpdf.adddocumentpattern (key,value) +lpdf.adddocumentshade (key,value) + +lpdf.addtocatalog (key,value) +lpdf.addtoinfo (key,value) +lpdf.addtonames (key,value) +\stoptyping + +\stopsection + +\startsection [title={Annotations}] + +You can use the \LUA\ functions that relate to annotations etc.\ but normally you +will use the regular \CONTEXT\ user interface. You can look into some of the +\type {lpdf-*} modules to see how special annotations can be dealt with. + +\stopsection + +\startsection [title={Tracing}] + +There are several tracing options built in and some more will be added in due +time: + +\starttyping +\enabletrackers + [backend.finalizers, + backend.resources, + backend.objects, + backend.detail] +\stoptyping + +As with all trackers you can also pass them on the command line, for example: + +\starttyping +context --trackers=backend.* yourfile +\stoptyping + +The reference related backend mechanisms have their own trackers. When you write +code that generates \PDF, it also helps to look in the \PDF\ file so see if +things are done right. In that case you need to disable compression: + +\starttyping +\nopdfcompression +\stoptyping + +\stopsection + +\startsection[title={Analyzing}] + +The \type {epdf} library that comes with \LUATEX\ offers a userdata interface to +\PDF\ files. On top of that \CONTEXT\ provides a more \LUA-ish access, using +tables. You can open a \PDF\ file with: + +\starttyping +local mypdf = lpdf.epdf.load(filename) +\stoptyping + +When opening is successful, you have access to a couple of tables: + +\starttyping +\NC \type{pages} \NC indexed \NC \NR +\NC \type{destinations} \NC hashed \NC \NR +\NC \type{javascripts} \NC hashed \NC \NR +\NC \type{widgets} \NC hashed \NC \NR +\NC \type{embeddedfiles} \NC hashed \NC \NR +\NC \type{layers} \NC indexed \NC \NR +\stoptyping + +These provide efficient access to some data that otherwise would take a bit of +code to deal with. Another top level table is the for \PDF\ characteristic \type +{Catalog}. Watch the capitalization: as with other native \PDF\ data structures, +keys are case sensitive and match the standard. + +Here is an example of usage: + +\starttyping +local MyDocument = lpdf.epdf.load("somefile.pdf") + +context.starttext() + + local pages = MyDocument.pages + local nofpages = pages.n + + context.starttabulate { "|c|c|c|" } + + context.NC() context("page") + context.NC() context("width") + context.NC() context("height") context.NR() + + for i=1, nofpages do + local page = pages[i] + local bbox = page.CropBox or page.MediaBox + context.NC() context(i) + context.NC() context(bbox[4]-bbox[2]) + context.NC() context(bbox[3]-bbox[1]) context.NR() + end + + context.stoptabulate() + +context.stoptext() +\stoptyping + +\stopsection + +\stopchapter + +\stopcomponent diff --git a/doc/context/sources/general/manuals/cld/cld-callbacks.tex b/doc/context/sources/general/manuals/cld/cld-callbacks.tex new file mode 100644 index 000000000..c449af864 --- /dev/null +++ b/doc/context/sources/general/manuals/cld/cld-callbacks.tex @@ -0,0 +1,240 @@ +% language=uk + +\startcomponent cld-callbacks + +\environment cld-environment + +\startchapter[title={Callbacks}] + +\startsection [title={Introduction}] + +\index {callbacks} + +The \LUATEX\ engine provides the usual basic \TEX\ functionality plus a bit more. +It is a deliberate choice not to extend the core engine too much. Instead all +relevant processes can be overloaded by new functionality written in \LUA. In +\CONTEXT\ callbacks are wrapped in a protective layer: on the one hand there is +extra functionality (usually interfaced through macros) and on the other hand +users can pop in their own handlers using hooks. Of course a plugged in function +has to do the right thing and not mess up the data structures. In this chapter +the layer on top of callbacks is described. + +\stopsection + +\startsection [title={Actions}] + +\index {nodelists} + +Nearly all callbacks in \LUATEX\ are used in \CONTEXT. In the following list the +callbacks tagged with \type {enabled} are used and frozen, the ones tagged \type +{disabled} are blocked and never used, while the ones tagged \type {undefined} +are yet unused. + +% \ctxlua{callbacks.table()} % \ctxlua{callbacks.report()} +\ctxcommand{showcallbacks()} + +Eventually all callbacks will be used so don't rely on undefined callbacks not +being protected. Some callbacks are only set when certain functionality is +enabled. + +It may sound somewhat harsh but if users kick in their own code, we cannot +guarantee \CONTEXT's behaviour any more and support becomes a pain. If you really +need to use a callback yourself, you should use one of the hooks and make sure +that you return the right values. + +All callbacks related to file handling, font definition and housekeeping are +frozen and cannot be overloaded. A reason for this are that we need some kind of +protection against misuse. Another reason is that we operate in a well defined +environment, the so called \TEX\ directory structure, and we don't want to mess +with that. And of course, the overloading permits \CONTEXT\ to provide extensions +beyond regular engine functionality. + +So as a fact we only open up some of the node list related callbacks and these +are grouped as follows: + +\starttabulate[|l|l|p|] +\FL +\NC \bf category \NC \bf callback \NC \bf usage \NC \NR +\TL +\NC \type{processors} \NC \type{pre_linebreak_filter} \NC called just before the paragraph is broken into lines \NC \NR +\NC \NC \type{hpack_filter} \NC called just before a horizontal box is constructed \NC \NR +\NC \type{finalizers} \NC \type{post_linebreak_filter} \NC called just after the paragraph has been broken into lines \NC \NR +\NC \type{shipouts} \NC \type{no callback yet} \NC applied to the box (or xform) that is to be shipped out \NC \NR +\NC \type{mvlbuilders} \NC \type{buildpage_filter} \NC called after some material has been added to the main vertical list \NC \NR +\NC \type{vboxbuilders} \NC \type{vpack_filter} \NC called when some material is added to a vertical box \NC \NR +%NC \type{parbuilders} \NC \type{linebreak_filter} \NC called when a paragraph is to be broken into lines \NC \NR +%NC \type{pagebuilders} \NC \type{pre_output_filter} \NC called when a page it fed into the output routing \NC \NR +\NC \type{math} \NC \type{mlist_to_hlist} \NC called just after the math list is created, before it is turned into an horizontal list \NC \NR +\BL +\stoptabulate + +Each category has several subcategories but for users only two make sense: \type +{before} and \type {after}. Say that you want to hook some tracing into the \type +{mvlbuilder}. This is how it's done: + +\starttyping +function third.mymodule.myfunction(where) + nodes.show_simple_list(tex.lists.contrib_head) +end + +nodes.tasks.appendaction("processors", "before", "third.mymodule.myfunction") +\stoptyping + +As you can see, in this case the function gets no \type {head} passed (at least +not currently). This example also assumes that you know how to access the right +items. The arguments and return values are given below. \footnote {This interface +might change a bit in future versions of \CONTEXT. Therefore we will not discuss +the few more optional arguments that are possible.} + +\starttabulate[|l|l|p|] +\FL +\NC \bf category \NC \bf arguments \NC \bf return value \NC \NR +\TL +\NC \type{processors} \NC \type{head, ...} \NC \type{head, done} \NC \NR +\NC \type{finalizers} \NC \type{head, ...} \NC \type{head, done} \NC \NR +\NC \type{shipouts} \NC \type{head} \NC \type{head, done} \NC \NR +\NC \type{mvlbuilders} \NC \NC \type{done} \NC \NR +\NC \type{vboxbuilders} \NC \type{head, ...} \NC \type{head, done} \NC \NR +\NC \type{parbuilders} \NC \type{head, ...} \NC \type{head, done} \NC \NR +\NC \type{pagebuilders} \NC \type{head, ...} \NC \type{head, done} \NC \NR +\NC \type{math} \NC \type{head, ...} \NC \type{head, done} \NC \NR +\LL +\stoptabulate + +\stopsection + +\startsection [title={Tasks}] + +\index {tasks} + +In the previous section we already saw that the actions are in fact tasks and +that we can append (and therefore also prepend) to a list of tasks. The \type +{before} and \type {after} task lists are valid hooks for users contrary to the +other tasks that can make up an action. However, the task builder is generic +enough for users to be used for individual tasks that are plugged into the user +hooks. + +Of course at some point, too many nested tasks bring a performance penalty with +them. At the end of a run \MKIV\ reports some statistics and timings and these +can give you an idea how much time is spent in \LUA. + +The following tables list all the registered tasks for the processors actions: + +\ctxlua{nodes.tasks.table("processors")} + +Some of these do have subtasks and some of these even more, so you can imagine +that quite some action is going on there. + +The finalizer tasks are: + +\ctxlua{nodes.tasks.table("finalizers")} + +Shipouts concern: + +\ctxlua{nodes.tasks.table("shipouts")} + +There are not that many mvlbuilder tasks currently: + +\ctxlua{nodes.tasks.table("mvlbuilders")} + +The vboxbuilder perform similar tasks: + +\ctxlua{nodes.tasks.table("vboxbuilders")} + +In the future we expect to have more parbuilder tasks. Here again there are +subtasks that depend on the current typesetting environment, so this is the right +spot for language specific treatments. + +\ctxlua{nodes.tasks.table("parbuilders")} + +The following actions are applied just before the list is passed on the the +output routine. The return value is a vlist. + +\ctxlua{nodes.tasks.table("pagebuilders")} + +{\em Both the parbuilders and pagebuilder tasks are unofficial and not yet meant +for users.} + +Finally, we have tasks related to the math list: + +\ctxlua{nodes.tasks.table("math")} + +As \MKIV\ is developed in sync with \LUATEX\ and code changes from experimental +to more final and reverse, you should not be too surprised if the registered +function names change. + +You can create your own task list with: + +\starttyping +nodes.tasks.new("mytasks",{ "one", "two" }) +\stoptyping + +After that you can register functions. You can append as well as prepend them +either or not at a specific position. + +\starttyping +nodes.tasks.appendaction ("mytask","one","bla.alpha") +nodes.tasks.appendaction ("mytask","one","bla.beta") + +nodes.tasks.prependaction("mytask","two","bla.gamma") +nodes.tasks.prependaction("mytask","two","bla.delta") + +nodes.tasks.appendaction ("mytask","one","bla.whatever","bla.alpha") +\stoptyping + +Functions can also be removed: + +\starttyping +nodes.tasks.removeaction("mytask","one","bla.whatever") +\stoptyping + +As removal is somewhat drastic, it is also possible to enable and disable +functions. From the fact that with these two functions you don't specify a +category (like \type {one} or \type {two}) you can conclude that the function +names need to be unique within the task list or else all with the same name +within this task will be disabled. + +\starttyping +nodes.tasks.enableaction ("mytask","bla.whatever") +nodes.tasks.disableaction("mytask","bla.whatever") +\stoptyping + +The same can be done with a complete category: + +\starttyping +nodes.tasks.enablegroup ("mytask","one") +nodes.tasks.disablegroup("mytask","one") +\stoptyping + +There is one function left: + +\starttyping +nodes.tasks.actions("mytask",2) +\stoptyping + +This function returns a function that when called will perform the tasks. In this +case the function takes two extra arguments in addition to \type {head}. +\footnote {Specifying this number permits for some optimization but is not really +needed} + +Tasks themselves are implemented on top of sequences but we won't discuss them +here. + +\stopsection + +\startsection [title={Paragraph and page builders}] + +Building paragraphs and pages is implemented differently and has no user hooks. +There is a mechanism for plugins but the interface is quite experimental. + +\stopsection + +\startsection [title={Some examples}] + +{\em todo} + +\stopsection + +\stopchapter + +\stopcomponent diff --git a/doc/context/sources/general/manuals/cld/cld-contents.tex b/doc/context/sources/general/manuals/cld/cld-contents.tex new file mode 100644 index 000000000..132da7dff --- /dev/null +++ b/doc/context/sources/general/manuals/cld/cld-contents.tex @@ -0,0 +1,11 @@ +\startcomponent cld-contents + +\environment cld-environment + +\starttitle[title=Contents] + + \placelist[chapter,section][criterium=text,aligntitle=yes] + +\stoptitle + +\stopcomponent diff --git a/doc/context/sources/general/manuals/cld/cld-ctxfunctions.tex b/doc/context/sources/general/manuals/cld/cld-ctxfunctions.tex new file mode 100644 index 000000000..f71030e50 --- /dev/null +++ b/doc/context/sources/general/manuals/cld/cld-ctxfunctions.tex @@ -0,0 +1,782 @@ +% language=uk + +\startcomponent cld-ctxfunctions + +\environment cld-environment + +\startchapter[title={The \LUA\ interface code}] + +\startsection[title={Introduction}] + +There is a lot of \LUA\ code in \MKIV. Much is not exposed and a lot of what is +exposed is not meant to be used directly at the \LUA\ end. But there is also +functionality and data that can be accessed without side effects. + +In the following sections a subset of the built in functionality is discussed. +There are often more functions alongside those presented but they might change or +disappear. So, if you use undocumented features, be sure to tag them somehow in +your source code so that you can check them out when there is an update. Best +would be to have more functionality defined local so that it is sort of hidden +but that would be unpractical as for instance functions are often used in other +modules and or have to be available at the \TEX\ end. + +It might be tempting to add your own functions to namespaces created by \CONTEXT\ +or maybe overload some existing ones. Don't do this. First of all, there is no +guarantee that your code will not interfere, nor that it overloads future +functionality. Just use your own namespace. Also, future versions of \CONTEXT\ +might have a couple of protection mechanisms built in. Without doubt the +following sections will be extended as soon as interfaces become more stable. + +\stopsection + +\startsection[title={Characters}] + +% not discussed: +% +% characters.filters.utf.addgrapheme() +% characters.filters.utf.collapse() +% characters.getrange() +% characters.bidi[] +% tex.uprint() +% utf.string() +% characters.flush() + +There are quite some data tables defined but the largest is the character +database. You can consult this table any time you want but you're not supposed to +add or change its content if only because changes will be overwritten when you +update \CONTEXT. Future versions may carry more information. The table can be +accessed using an unicode number. A relative simple entry looks as follows: + +\ShowLuaExampleTableHex{characters.data[0x00C1]} + +Much of this is rather common information but some of it is specific for use with +\CONTEXT. Some characters have even more information, for instance those that +deal with mathematics: + +\ShowLuaExampleTableHex{characters.data[0x2190]} + +Not all characters have a real entry. For instance most \CJK\ characters are +virtual and share the same data: + +\ShowLuaExampleTableHex{characters.data[0x3456]} + +You can also access the table using \UTF\ characters: + +\ShowLuaExampleTable{characters.data["ä"]} + +A more verbose string access is also supported: + +\ShowLuaExampleTableHex{characters.data["U+0070"]} + +Another (less usefull) table contains information about ranges in this character +table. You can access this table using rather verbose names, or you can use +collapsed lowercase variants. + +\ShowLuaExampleTableHex{characters.blocks["CJK Compatibility Ideographs"]} + +\ShowLuaExampleTableHex{characters.blocks["hebrew"]} + +\ShowLuaExampleTableHex{characters.blocks["combiningdiacriticalmarks"]} + +Some fields can be accessed using functions. This can be handy when you need that +information for tracing purposes or overviews. There is some overhead in the +function call, but you get some extra testing for free. You can use characters as +well as numbers as index. + +\ShowLuaExampleString{characters.contextname("ä")} +\ShowLuaExampleString{characters.adobename(228)} +\ShowLuaExampleString{characters.description("ä")} + +The category is normally a two character tag, but you can also ask for a more +verbose variant: + +\ShowLuaExampleString{characters.category(228)} +\ShowLuaExampleString{characters.category(228,true)} + +The more verbose category tags are available in a table: + +\ShowLuaExampleString{characters.categorytags["lu"]} + +There are several fields in a character entry that help us to remap a character. +The \type {lccode} indicates the lowercase code point and the \type {uccode} to +the uppercase code point. The \type {shcode} refers to one or more characters +that have a similar shape. + +\ShowLuaExampleString{characters.shape ("ä")} +\ShowLuaExampleString{characters.uccode("ä")} +\ShowLuaExampleString{characters.lccode("ä")} + +\ShowLuaExampleString{characters.shape (100)} +\ShowLuaExampleString{characters.uccode(100)} +\ShowLuaExampleString{characters.lccode(100)} + +You can use these function or access these fields directly in an +entry, but we also provide a few virtual tables that avoid +accessing the whole entry. This method is rather efficient. + +\ShowLuaExampleString{characters.lccodes["ä"]} +\ShowLuaExampleString{characters.uccodes["ä"]} +\ShowLuaExampleString{characters.shcodes["ä"]} +\ShowLuaExampleString{characters.lcchars["ä"]} +\ShowLuaExampleString{characters.ucchars["ä"]} +\ShowLuaExampleString{characters.shchars["ä"]} + +As with other tables, you can use a number instead of an \UTF\ character. Watch +how we get a table for multiple shape codes but a string for multiple shape +characters. + +\ShowLuaExampleString{characters.lcchars[0x00C6]} +\ShowLuaExampleString{characters.ucchars[0x00C6]} +\ShowLuaExampleString{characters.shchars[0x00C6]} +\ShowLuaExampleTable {characters.shcodes[0x00C6]} + +These codes are used when we manipulate strings. Although there +are \type {upper} and \type {lower} functions in the \type +{string} namespace, the following ones are the real ones to be +used in critical situations. + +\ShowLuaExampleString{characters.lower("ÀÁÂÃÄÅàáâãäå")} +\ShowLuaExampleString{characters.upper("ÀÁÂÃÄÅàáâãäå")} +\ShowLuaExampleString{characters.shaped("ÀÁÂÃÄÅàáâãäå")} + +A rather special one is the following: + +\ShowLuaExampleString{characters.lettered("Only 123 letters + count!")} + +With the second argument is true, spaces are kept and collapsed. Leading and +trailing spaces are stripped. + +\ShowLuaExampleString{characters.lettered("Only 123 letters + count!",true)} + +Access to tables can happen by number or by string, although there are some +limitations when it gets too confusing. Take for instance the number \type {8} +and string \type {"8"}: if we would interpret the string as number we could never +access the entry for the character eight. However, using more verbose hexadecimal +strings works okay. The remappers are also available as functions: + +\ShowLuaExampleString{characters.tonumber("a")} +\ShowLuaExampleString{characters.fromnumber(100)} +\ShowLuaExampleString{characters.fromnumber(0x0100)} +\ShowLuaExampleString{characters.fromnumber("0x0100")} +\ShowLuaExampleString{characters.fromnumber("U+0100")} + +In addition to the already mentioned category information you can also use a more +direct table approach: + +\ShowLuaExampleString{characters.categories["ä"]} +\ShowLuaExampleString{characters.categories[100]} + +In a similar fashion you can test if a given character is in a specific category. +This can save a lot of tests. + +\ShowLuaExampleBoolean{characters.is_character[characters.categories[67]]} +\ShowLuaExampleBoolean{characters.is_character[67]} +\ShowLuaExampleBoolean{characters.is_character[characters.data[67].category]} +\ShowLuaExampleBoolean{characters.is_letter[characters.data[67].category]} +\ShowLuaExampleBoolean{characters.is_command[characters.data[67].category]} + +Another virtual table is the one that provides access to special information, for +instance about how a composed character is made up of components. + +\ShowLuaExampleString{characters.specialchars["ä"]} +\ShowLuaExampleString{characters.specialchars[100]} + +The outcome is often similar to output that uses the shapecode information. + +Although not all the code deep down in \CONTEXT\ is meant for use at the user +level, it sometimes can eb tempting to use data and helpers that are available as +part of the general housekeeping. The next table was used when looking into +sorting Korean. For practical reasons we limit the table to ten entries; +otherwise we would have ended up with hundreds of pages. + +\startbuffer +\startluacode +local data = characters.data +local map = characters.hangul.remapped + +local first, last = characters.getrange("hangulsyllables") + +last = first + 9 -- for now + +context.start() + +context.definedfont { "file:unbatang" } + +context.starttabulate { "|T||T||T||T||T|" } +for unicode = first, last do + local character = data[unicode] + local specials = character.specials + if specials then + context.NC() + context.formatted("%04V",unicode) + context.NC() + context.formatted("%c",unicode) + for i=2,4 do + local chr = specials[i] + if chr then + chr = map[chr] or chr + context.NC() + context.formatted("%04V",chr) + context.NC() + context.formatted("%c",chr) + else + context.NC() + context.NC() + end + end + context.NC() + context(character.description) + context.NC() + context.NR() + end +end +context.stoptabulate() + +context.stop() +\stopluacode +\stopbuffer + +\getbuffer \typebuffer + +\stopsection + +\startsection[title={Fonts}] + +% not discussed (as not too relevant for users): +% +% cache cache_version +% nomath +% units units_per_em +% direction embedding encodingbytes +% boundarychar boundarychar_label +% has_italic has_math +% tounicode sub +% colorscheme (will probably become a hash) +% language script +% spacer +% MathConstants and a few split_names +% +% tables.baselines + +There is a lot of code that deals with fonts but most is considered to be a black +box. When a font is defined, its data is collected and turned into a form that +\TEX\ likes. We keep most of that data available at the \LUA\ end so that we can +later use it when needed. In this chapter we discuss some of the possibilities. +More details can be found in the font manual(s) so we don't aim for completeness +here. + +A font instance is identified by its id, which is a number where zero is reserved +for the so called \type {nullfont}. The current font id can be requested by the +following function. + +\ShowLuaExampleString{fonts.currentid()} + +The \type {fonts.current()} call returns the table with data related to the +current id. You can access the data related to any id as follows: + +\starttyping +local tfmdata = fonts.identifiers[number] +\stoptyping + +Not all entries in the table make sense for the user as some are just meant to +drive the font initialization at the \TEX\ end or the backend. The next table +lists the most important ones. Some of the tables are just shortcuts to en entry +in one of the \type {shared} subtables. + +\starttabulate[|l|Tl|p|] +\NC \type{ascender} \NC number \NC the height of a line conforming the font \NC \NR +\NC \type{descender} \NC number \NC the depth of a line conforming the font \NC \NR +\NC \type{italicangle} \NC number \NC the angle of the italic shapes (if present) \NC \NR +\NC \type{designsize} \NC number \NC the design size of the font (if known) \NC \NR +\ML +\NC \type{size} \NC number \NC the size in scaled points if the font instance \NC \NR +\NC \type{factor} \NC number \NC the multiplication factor for unscaled dimensions \NC \NR +\NC \type{hfactor} \NC number \NC the horizontal multiplication factor \NC \NR +\NC \type{vfactor} \NC number \NC the vertical multiplication factor \NC \NR +\NC \type{extend} \NC number \NC the horizontal scaling to be used by the backend \NC \NR +\NC \type{slant} \NC number \NC the slanting to be applied by the backend \NC \NR +\ML +\NC \type{characters} \NC table \NC the scaled character (glyph) information (tfm) \NC \NR +\NC \type{descriptions} \NC table \NC the original unscaled glyph information (otf, afm, tfm) \NC \NR +\NC \type{indices} \NC table \NC the mapping from unicode slot to glyph index \NC \NR +\NC \type{unicodes} \NC table \NC the mapoing from glyph names to unicode \NC \NR +\NC \type{marks} \NC table \NC a hash table with glyphs that are marks as entry \NC \NR +\NC \type{parameters} \NC table \NC the font parameters as \TEX\ likes them \NC \NR +\NC \type{mathconstants} \NC table \NC the \OPENTYPE\ math parameters \NC \NR +\NC \type{mathparameters} \NC table \NC a reference to the \type {MathConstants} table \NC \NR +\NC \type{shared} \NC table \NC a table with information shared between instances \NC \NR +\NC \type{unique} \NC table \NC a table with information unique for this instance \NC \NR +\NC \type{unscaled} \NC table \NC the unscaled (intermediate) table \NC \NR +\NC \type{goodies} \NC table \NC the \CONTEXT\ specific extra font information \NC \NR +\NC \type{fonts} \NC table \NC the table with references to other fonts \NC \NR +\NC \type{cidinfo} \NC table \NC a table with special information for the backend \NC \NR +\ML +\NC \type{filename} \NC string \NC the full path of the loaded font \NC \NR +\NC \type{fontname} \NC string \NC the font name as specified in the font (limited in size) \NC \NR +\NC \type{fullname} \NC string \NC the complete font name as specified in the font \NC \NR +\NC \type{name} \NC string \NC the (short) name of the font \NC \NR +\NC \type{psname} \NC string \NC the (unique) name of the font as used by the backend \NC \NR +\ML +\NC \type{hash} \NC string \NC the hash that makes this instance unique \NC \NR +\NC \type{id} \NC number \NC the id (number) that \TEX\ will use for this instance \NC \NR +\ML +\NC \type{type} \NC string \NC an idicator if the font is \type {virtual} or \type {real} \NC \NR +\NC \type{format} \NC string \NC a qualification for this font, e.g.\ \type {opentype} \NC \NR +\NC \type{mode} \NC string \NC the \CONTEXT\ processing mode, \type {node} or \type {base} \NC \NR +\ML +\stoptabulate + +The \type {parameters} table contains variables that are used by \TEX\ itself. +You can use numbers as index and these are equivalent to the so called \type +{\fontdimen} variables. More convenient is is to access by name: + +\starttabulate[|l|p|] +\NC \type{slant} \NC the slant per point (seldom used) \NC \NR +\NC \type{space} \NC the interword space \NC \NR +\NC \type{spacestretch} \NC the interword stretch \NC \NR +\NC \type{spaceshrink} \NC the interword shrink \NC \NR +\NC \type{xheight} \NC the x|-|height (not per se the heigth of an x) \NC \NR +\NC \type{quad} \NC the so called em|-|width (often the width of an emdash)\NC \NR +\NC \type{extraspace} \NC additional space added in specific situations \NC \NR +\stoptabulate + +The math parameters are rather special and explained in the \LUATEX\ manual. +Quite certainly you never have to touch these parameters at the \LUA\ end. + +En entry in the \type {characters} table describes a character if we have entries +within the \UNICODE\ range. There can be entries in the private area but these +are normally variants of a shape or special math glyphs. + +\starttabulate[|l|p|] +\NC \type{name} \NC the name of the character \NC \NR +\NC \type{index} \NC the index in the raw font table \NC \NR +\NC \type{height} \NC the scaled height of the character \NC \NR +\NC \type{depth} \NC the scaled depth of the character \NC \NR +\NC \type{width} \NC the scaled height of the character \NC \NR +\NC \type{tounicode} \NC a \UTF-16 string representing the conversion back to unicode \NC \NR +\NC \type{expansion_factor} \NC a multiplication factor for (horizontal) font expansion \NC \NR +\NC \type{left_protruding} \NC a multiplication factor for left side protrusion \NC \NR +\NC \type{right_protruding} \NC a multiplication factor for right side protrusion \NC \NR +\NC \type{italic} \NC the italic correction \NC \NR +\NC \type{next} \NC a pointer to the next character in a math size chain \NC \NR +\NC \type{vert_variants} \NC a pointer to vertical variants conforming \OPENTYPE\ math \NC \NR +\NC \type{horiz_variants} \NC a pointer to horizontal variants conforming \OPENTYPE\ math \NC \NR +\NC \type{top_accent} \NC information with regards to math top accents \NC \NR +\NC \type{mathkern} \NC a table describing stepwise math kerning (following the shape) \NC \NR +\NC \type{kerns} \NC a table with intercharacter kerning dimensions \NC \NR +\NC \type{ligatures} \NC a (nested) table describing ligatures that start with this character \NC \NR +\NC \type{commands} \NC a table with commands that drive the backend code for a virtual shape \NC \NR +\stoptabulate + +Not all entries are present for each character. Also, in so called \type {node} +mode, the \type {ligatures} and \type {kerns} tables are empty because in that +case they are dealt with at the \LUA\ end and not by \TEX. + +% \startluacode +% local tfmdata = fonts.current() +% context.starttabulate{ "|l|pl|" } +% for k, v in table.sortedhash(tfmdata) do +% local tv = type(v) +% if tv == "string" or tv == "number" or tv == "boolean" then +% context.NC() +% string.tocontext(k) +% context.NC() +% string.tocontext(tostring(v)) +% context.NC() +% context.NR() +% end +% end +% context.stoptabulate() +% \stopluacode + +% \ShowLuaExampleTable{table.sortedkeys(fonts.current())} + +Say that you run into a glyph node and want to access the data related to that +glyph. Given that variable \type {n} points to the node, the most verbose way of +doing that is: + +\starttyping +local g = fonts.identifiers[n.id].characters[n.char] +\stoptyping + +Given the speed of \LUATEX\ this is quite fast. Another method is the following: + +\starttyping +local g = fonts.characters[n.id][n.char] +\stoptyping + +For some applications you might want faster access to critical +parameters, like: + +\starttyping +local quad = fonts.quads [n.id][n.char] +local xheight = fonts.xheights[n.id][n.char] +\stoptyping + +but that only makes sense when you don't access more than one such variable at +the same time. + +Among the shared tables is the feature specification: + +\ShowLuaExampleTable{fonts.current().shared.features} + +As features are a prominent property of \OPENTYPE\ fonts, there are a few +datatables that can be used to get their meaning. + +\ShowLuaExampleString{fonts.handlers.otf.tables.features['liga']} +\ShowLuaExampleString{fonts.handlers.otf.tables.languages['nld']} +\ShowLuaExampleString{fonts.handlers.otf.tables.scripts['arab']} + +There is a rather extensive font database built in but discussing its interface +does not make much sense. Most usage happens automatically when you use the \type +{name:} and \type {spec:} methods of defining fonts and the \type {mtx-fonts} +script is built on top of it. + +\ctxlua{fonts.names.load()} % could be metatable driven + +\ShowLuaExampleTable{table.sortedkeys(fonts.names.data)} + +You can load the database (if it's not yet loaded) with: + +\starttyping +names.load(reload,verbose) +\stoptyping + +When the first argument is true, the database will be rebuild. The second +arguments controls verbosity. + +Defining a font normally happens at the \TEX\ end but you can also do it in \LUA. + +\starttyping +local id, fontdata = fonts.definers.define { + lookup = "file", -- use the filename (file spec name) + name = "pagella-regular", -- in this case the filename + size = 10*65535, -- scaled points + global = false, -- define the font globally + cs = "MyFont", -- associate the name \MyFont + method = "featureset", -- featureset or virtual (* or @) + sub = nil, -- no subfont specifier + detail = "whatever", -- the featureset (or whatever method applies) +} +\stoptyping + +In this case the \type {detail} variable defines what featureset has to be +applied. You can define such sets at the \LUA\ end too: + +\starttyping +fonts.definers.specifiers.presetcontext ( + "whatever", + "default", + { + mode = "node", + dlig = "yes", + } +) +\stoptyping + +The first argument is the name of the featureset. The second argument can be an +empty string or a reference to an existing featureset that will be taken as +starting point. The final argument is the featureset. This can be a table or a +string with a comma separated list of key|/|value pairs. + +\stopsection + +\startsection[title={Nodes}] + +Nodes are the building blocks that make a document reality. Nodes are linked into +lists and at various moments in the typesetting process you can manipulate them. +Deep down in \CONTEXT\ we use quite some \LUA\ magic to manipulate lists of +nodes. Therefore it is no surprise that we have some tracing available. Take the +following box. + +\startbuffer +\setbox0\hbox{It's in \hbox{\bf all} those nodes.} +\stopbuffer + +\typebuffer \getbuffer + +This box contains characters and glue between the words. The box is already +constructed. There can also be kerns between characters, but of course only if +the font provides such a feature. Let's inspect this box: + +\ShowLuaExampleString{nodes.toutf(tex.box[0])} +\ShowLuaExampleString{nodes.toutf(tex.box[0].list)} + +This tracer returns the text and spacing and recurses into nested lists. The next +tracer does not do this and marks non glyph nodes as \type {[-]}: + +\ShowLuaExampleString{nodes.listtoutf(tex.box[0])} +\ShowLuaExampleString{nodes.listtoutf(tex.box[0].list)} + +A more verbose tracer is the next one. It does show a bit more detailed +information about the glyphs nodes. + +\ShowLuaExampleString{nodes.tosequence(tex.box[0])} +\ShowLuaExampleString{nodes.tosequence(tex.box[0].list)} + +The fourth tracer does not show that detail and collapses sequences of similar +node types. + +\ShowLuaExampleString{nodes.idstostring(tex.box[0])} +\ShowLuaExampleString{nodes.idstostring(tex.box[0].list)} + +The number of nodes in a list is identified with the \type {count} function. +Nested nodes are counted too. + +\ShowLuaExampleString{nodes.count(tex.box[0])} +\ShowLuaExampleString{nodes.count(tex.box[0].list)} + +There are functions to check node types and node id's: + +\starttyping +local str = node.type(1) +local num = node.id("vlist") +\stoptyping + +These are basic \LUATEX\ functions. In addition to those we also provide a few +mapping tables. There are two tables that map node id's to strings and backwards: + +\starttabulate +\NC \type{nodes.nodecodes} \NC regular nodes, some fo them are sort of private to the engine \NC \NR +\NC \type{nodes.noadcodes} \NC math nodes that later on are converted into regular nodes \NC \NR +\stoptabulate + +Nodes can have subtypes. Again we have tables that map the subtype numbers onto +meaningfull names and reverse. + +\starttabulate +\NC \type{nodes.listcodes} \NC subtypes of \type {hlist} and \type {vlist} nodes \NC \NR +\NC \type{nodes.kerncodes} \NC subtypes of \type {kern} nodes \NC \NR +\NC \type{nodes.gluecodes} \NC subtypes of \type {glue} nodes (skips) \NC \NR +\NC \type{nodes.glyphcodes} \NC subtypes of \type {glyph} nodes, the subtype can change \NC \NR +\NC \type{nodes.mathcodes} \NC math specific subtypes \NC \NR +\NC \type{nodes.fillcodes} \NC these are not really subtypes but indicate the strength of the filler \NC \NR +\NC \type{nodes.whatsitcodes} \NC subtypes of a rather large group of extension nodes \NC \NR +\stoptabulate + +Some of the names of types and subtypes have underscores but you can omit them +when you use these tables. You can use tables like this as follows: + +\starttyping +local glyph_code = nodes.nodecodes.glyph +local kern_code = nodes.nodecodes.kern +local glue_code = nodes.nodecodes.glue + +for n in nodes.traverse(list) do + local id == n.id + if id == glyph_code then + ... + elseif id == kern_code then + ... + elseif id == glue_code then + ... + else + ... + end +end +\stoptyping + +You only need to use such temporary variables in time critical code. In spite of +what you might think, lists are not that long and given the speed of \LUA\ (and +successive optimizations in \LUATEX) looping over a paragraphs is rather fast. + +Nodes are created using \type {node.new}. If you study the \CONTEXT\ code you +will notice that there are quite some functions in the \type {nodes.pool} +namespace, like: + +\starttyping +local g = nodes.pool.glyph(fnt,chr) +\stoptyping + +Of course you need to make sure that the font id is valid and that the referred +glyph in in the font. You can use the allocators but don't mess with the code in +the \type {pool} namespace as this might interfere with its usage all over +\CONTEXT. + +The \type {nodes} namespace provides a couple of helpers and some of them are +similar to ones provided in the \type {node} namespace. This has practical as +well as historic reasons. For instance some were prototypes functions that were +later built in. + +\starttyping +local head, current = nodes.before (head, current, new) +local head, current = nodes.after (head, current, new) +local head, current = nodes.delete (head, current) +local head, current = nodes.replace(head, current, new) +local head, current, old = nodes.remove (head, current) +\stoptyping + +Another category deals with attributes: + +\starttyping +nodes.setattribute (head, attribute, value) +nodes.unsetattribute (head, attribute) +nodes.setunsetattribute (head, attribute, value) +nodes.setattributes (head, attribute, value) +nodes.unsetattributes (head, attribute) +nodes.setunsetattributes(head, attribute, value) +nodes.hasattribute (head, attribute, value) +\stoptyping + +% context(typesetters.hpack("Hello World!")) +% context(typesetters.hpack("Hello World!",1,100*1024*10)) + +% nodes.firstchar +% nodes.firstcharinbox + +% maybe node-tst +% tasks and so +% number.points (to numbers) + +\stopsection + +% \startsection[title={Core}] +% {\em todo} +% \stopsection + +\startsection[title={Resolvers}] + +All \IO\ is handled by functions in the \type {resolvers} namespace. Most of the +code that you find in the \type {data-*.lua} files is of litle relevance for +users, especially at the \LUA\ end, so we won't discuss it here in great detail. + +The resolver code is modelled after the \KPSE\ library that itself implements the +\TEX\ Directory Structure in combination with a configuration file. However, we +go a bit beyond this structure, for instance in integrating support for other +resources that file systems. We also have our own configuration file. But +important is that we still support a similar logic too so that regular +configurations are dealt with. + +During a run \LUATEX\ needs files of a different kind: source files, font files, +images, etc. In practice you will probably only deal with source files. The most +fundamental function is \type {findfile}. The first argument is the filename to +be found. A second optional argument indicates the file type. + +The following table relates so called formats to suffixes and variables in the +configuration file. + +\startluacode +context.starttabulate { "|lp|lp|l|" } +context.NC() context.bold("variable") +context.NC() context.bold("format") +context.NC() context.bold("suffix") +context.NC() context.NR() +context.ML() +for k, v in table.sortedpairs(resolvers.relations.core) do + local names = v.names + local variable = v.variable + local suffixes = v.suffixes + context.NC() + if variable then + context.type(variable) + end + context.NC() + if names then + for i=1,#names do + context.type(names[i]) + context.par() + end + end + context.NC() + if suffixes then + context.type(table.concat(suffixes, " ")) + end + context.NC() + context.NR() +end +context.stoptabulate() +\stopluacode + +There are a couple of more formats but these are not that relevant in the +perspective of \CONTEXT. + +When a lookup takes place, spaces are ignored and formats are normalized to +lowercase. + +\ShowLuaExampleString{file.strip(resolvers.findfile("context.tex"),"tex/")} +\ShowLuaExampleString{file.strip(resolvers.findfile("context.mkiv"),"tex/")} +\ShowLuaExampleString{file.strip(resolvers.findfile("context"),"tex/")} +\ShowLuaExampleString{file.strip(resolvers.findfile("data-res.lua"),"tex/")} +\ShowLuaExampleString{file.strip(resolvers.findfile("lmsans10-bold"),"tex/")} +\ShowLuaExampleString{file.strip(resolvers.findfile("lmsans10-bold.otf"),"tex/")} +\ShowLuaExampleString{file.strip(resolvers.findfile("lmsans10-bold","otf"),"tex/")} +\ShowLuaExampleString{file.strip(resolvers.findfile("lmsans10-bold","opentype"),"tex/")} +\ShowLuaExampleString{file.strip(resolvers.findfile("lmsans10-bold","opentypefonts"),"tex/")} +\ShowLuaExampleString{file.strip(resolvers.findfile("lmsans10-bold","opentype fonts"),"tex/")} + +The plural variant of this function returns one or more matches. + +\ShowLuaExampleTable{resolvers.findfiles("texmfcnf.lua","cnf")} +\ShowLuaExampleTable{resolvers.findfiles("context.tex","")} + +% table.print(resolvers.instance.environment) +% table.print(resolvers.instance.variables) +% table.print(resolvers.instance.expansions) +% +% resolvers.expandbraces +% resolvers.expandpath +% resolvers.expandvar +% resolvers.showpath +% resolvers.var_value +% +% resolvers.getenv +% resolvers.variable() +% resolvers.expansion() +% resolvers.is_variable +% resolvers.is_expansion +% +% resolvers.unexpandedpathlist(str) +% resolvers.unexpandedpath(str) +% resolvers.cleanpathlist +% resolvers.expandpath +% resolvers.expandedpath +% resolvers.expandedpathlistfromvariable +% resolvers.expandpathfromvariable +% resolvers.expandbraces +% +% resolvers.findpath +% resolvers.findgivenfiles +% resolvers.findgivenfile +% resolvers.findwildcardfiles +% resolvers.findwildcardfile +% resolvers.showpath + +% data-tre as example +% schemes (data-she) +% caching (containers) +% findbinfile (open|load) +% variables / environment +% findtexfile opentexfile loadtexfile +% file:// + +% supp + +\stopsection + +\startsection[title={Mathematics (math)}] + {\em todo} +\stopsection + +\startsection[title={Graphics (grph)}] + {\em is a separate chapter} +\stopsection + +\startsection[title={Languages (lang)}] + {\em todo} +\stopsection + +\startsection[title={MetaPost (mlib)}] + {\em todo} +\stopsection + +\startsection[title={Lua\TeX\ (luat)}] + {\em todo} +\stopsection + +\startsection[title={Tracing (trac)}] + {\em todo} +\stopsection + +\stopchapter + +\stopcomponent diff --git a/doc/context/sources/general/manuals/cld/cld-environment.tex b/doc/context/sources/general/manuals/cld/cld-environment.tex new file mode 100644 index 000000000..1355110bd --- /dev/null +++ b/doc/context/sources/general/manuals/cld/cld-environment.tex @@ -0,0 +1,224 @@ +% language=uk + +\startenvironment cld-environment + +\usemodule[abr-04] + +\setuplayout + [width=middle, + height=middle, + backspace=2cm, + topspace=1cm, + footer=0pt, + bottomdistance=1cm, + bottom=1cm, + bottomspace=2cm] + +\setuppagenumbering + [alternative=doublesided] + +\definecolor[darkred] [r=.5] +\definecolor[darkgreen][g=.5] +\definecolor[darkblue] [b=.5] + +\definecolor[red] [darkred] +\definecolor[green][darkgreen] +\definecolor[blue] [darkblue] + +\definetype + [boldtypebig] + [style=\ttbfa] + +\definetype + [boldtype] + [style=\ttbf] + +\definetyping + [smalltyping] + [bodyfont=small] + +\setuptype + [color=blue] + +\setuptyping + [color=blue] + +\setupbodyfont + [palatino,11pt] + +\setuphead + [chapter] + [style=\bfc, + color=blue] + +\setuphead + [section] + [style=\bfb, + color=blue] + +\definehead + [summary] + [subsubsubsubject] + +\setuphead + [summary] + [style=, + deeptextcommand=\boldtypebig, + color=blue] + +\definehead + [subsummary] + [subsubsubsubsubject] + +\setuphead + [subsummary] + [style=, + before=\blank, + after=\blank, + deeptextcommand=\type, + command=\MySubSummaryHead, + color=blue] + +\unexpanded\def\MySummaryHead#1#2% + {\framed + [frame=off, + bottomframe=on, + offset=0cm] + {#2}} + +\unexpanded\def\MySubSummaryHead#1#2% + {\framed + [frame=off, + bottomframe=on, + offset=0cm] + {#2}} + +\setupwhitespace + [big] + +\setupheadertexts + [] + +\setupheadertexts + [] + [{\getmarking[chapter]\quad\pagenumber}] + [{\pagenumber\quad\getmarking[chapter]}] + [] + +\setupheader + [color=darkblue] + +\setuplist + [chapter,title] + [color=darkblue, + style=bold] + +\setupbottom + [style=\bfx, + color=darkred] + +\setupbottomtexts + [preliminary, uncorrected version -- \currentdate] + +% special functions + +\unexpanded\def\ShowLuaExampleOne#1#2#3% + {\bgroup + \obeyluatokens + \startsubsummary[title={#1.#2(#3)}] + \ctxlua{table.tocontext(#3)} + \stopsubsummary + \egroup} + +\unexpanded\def\ShowLuaExampleTwo#1#2#3% + {\bgroup + \obeyluatokens + \startsubsummary[title={#1.#2(#3)}] + \ctxlua{table.tocontext(#1.#2(#3))} + \stopsubsummary + \egroup} + +\unexpanded\def\ShowLuaExampleThree#1#2#3% + {\bgroup + \obeyluatokens + \startsubsummary[title={#1.#2(#3)}] + \ctxlua{string.tocontext(tostring(#1.#2(#3)))} + \stopsubsummary + \egroup} + +\unexpanded\def\ShowLuaExampleFour#1#2#3#4% + {\bgroup + \obeyluatokens + \startsubsummary[title={t=#3 #1.#2(t#4)}] + \ctxlua{local t = #3 #1.#2(t#4) table.tocontext(t)} + \stopsubsummary + \egroup} + +\unexpanded\def\ShowLuaExampleFive#1#2% + {\bgroup + \obeyluatokens + \startsubsummary[title={#1.#2}] + \ctxlua{string.tocontext(tostring(#1.#2))} + \stopsubsummary + \egroup} + +\unexpanded\def\ShowLuaExampleSix#1#2#3% + {\bgroup + \obeyluatokens + \startsubsummary[title={#1.#2(#3)}] + \ctxlua{string.tocontext(#1.#2(#3))} + \stopsubsummary + \egroup} + +\unexpanded\def\ShowLuaExampleSeven#1#2#3% + {\bgroup + \obeyluatokens + \startsubsummary[title={#1.#2(#3)}] + \ctxlua{string.tocontext(table.concat({#1.#2(#3)}," "))} + \stopsubsummary + \egroup} + +\unexpanded\def\ShowLuaExampleTable#1% + {\bgroup + \obeyluatokens + \startsubsummary[title={#1}] + \ctxlua{table.tocontext(#1,false)} + \stopsubsummary + \egroup} + +\unexpanded\def\ShowLuaExampleTableHex#1% + {\bgroup + \obeyluatokens + \startsubsummary[title={#1}] + \ctxlua{table.tocontext(#1,false,false,true,true)} % name, reduce, noquotes, hex + \stopsubsummary + \egroup} + +\unexpanded\def\ShowLuaExampleString#1% + {\bgroup + \obeyluatokens + \startsubsummary[title={#1}] + \ctxlua{string.tocontext(#1)} + \stopsubsummary + \egroup} + +\unexpanded\def\ShowLuaExampleBoolean#1% + {\bgroup + \obeyluatokens + \startsubsummary[title={#1}] + \ctxlua{boolean.tocontext(#1)} + \stopsubsummary + \egroup} + +% interaction + +\setupinteraction + [state=start, + color=, + contrastcolor=] + +\setuplist + [chapter,section] + [interaction=all] + +\stopenvironment diff --git a/doc/context/sources/general/manuals/cld/cld-files.tex b/doc/context/sources/general/manuals/cld/cld-files.tex new file mode 100644 index 000000000..38a7322b1 --- /dev/null +++ b/doc/context/sources/general/manuals/cld/cld-files.tex @@ -0,0 +1,78 @@ +% language=uk + +\startcomponent cld-macros + +\environment cld-environment + +\startchapter[title=Files] + +\startsection[title={Preprocessing}] + +Although this option must be used with care, it is possible to preprocess files +before they enter \TEX. The following example shows this. + +\starttyping +local function showline(str,filename,linenumber,noflines) + logs.simple("[lc] file: %s, line: %s of %s, length: %s", + file.basename(filename),linenumber,noflines,#str) +end + +local function showfile(str,filename) + logs.simple("[fc] file: %s, length: %s", + file.basename(filename),#str) +end + +resolvers.installinputlinehandler(showline) +resolvers.installinputfilehandler(showfile) +\stoptyping + +Preprocessors like this are rather innocent. If you want to manipulate the +content you need to be aware of the fact that modules and such also pass your +code, and manipulating them can give unexpected side effects. So, the following +code will not make \CONTEXT\ happy. + +\starttyping +local function foo() + return "bar" +end + +resolvers.installinputlinehandler(foo) +\stoptyping + +But, as we pass the filename, you can base your preprocessing on names. + +There can be multiple handlers active at the same time, and although more +detailed control is possible, the current interface does not provide that, simply +because having too many handlers active is asking for trouble anyway. What you +can do, is putting your handler in front or after the built in handlers. + +\starttyping +resolvers.installinputlinehandler("before",showline) +resolvers.installinputfilehandler("after", showfile) +\stoptyping + +Of course you can also preprocess files outside this mechanism, which in most +cases might be a better idea. However, the following example code is quite +efficient and robust. + +\starttyping +local function MyHandler(str,filename) + if file.suffix(filename) == "veryspecial" then + logs.simple("preprocessing file '%s',filename) + return MyConverter(str) + else + return str + end +end + +resolvers.installinputfilehandler("before",MyHandler) +\stoptyping + +In this case only files that have a suffix \type {.veryspecial} will get an extra +treatment. + +\stopsection + +\stopchapter + +\stopcomponent diff --git a/doc/context/sources/general/manuals/cld/cld-gettingstarted.tex b/doc/context/sources/general/manuals/cld/cld-gettingstarted.tex new file mode 100644 index 000000000..5c7e1c263 --- /dev/null +++ b/doc/context/sources/general/manuals/cld/cld-gettingstarted.tex @@ -0,0 +1,437 @@ +% language=uk + +\startcomponent cld-gettingstarted + +\environment cld-environment + +\startchapter[title=Getting started] + +\startsection[title=Some basics] + +\index{processing} + +I assume that you have either the so called \CONTEXT\ standalone (formerly known +as minimals) installed or \TEXLIVE. You only need \LUATEX\ and can forget about +installing \PDFTEX\ or \XETEX, which saves you some megabytes and hassle. Now, +from the users perspective a \CONTEXT\ run goes like: + +\starttyping +context yourfile +\stoptyping + +and by default a file with suffix \type {tex}, \type {mkvi} or \type {mkvi} will +be processed. There are however a few other options: + +\starttyping +context yourfile.xml +context yourfile.rlx --forcexml +context yourfile.lua +context yourfile.pqr --forcelua +context yourfile.cld +context yourfile.xyz --forcecld +context yourfile.mp +context yourfile.xyz --forcemp +\stoptyping + +When processing a \LUA\ file the given file is loaded and just processed. This +options will seldom be used as it is way more efficient to let \type {mtxrun} +process that file. However, the last two variants are what we will discuss here. +The suffix \type {cld} is a shortcut for \CONTEXT\ \LUA\ Document. + +A simple \type {cld} file looks like this: + +\starttyping +context.starttext() +context.chapter("Hello There!") +context.stoptext() +\stoptyping + +So yes, you need to know the \CONTEXT\ commands in order to use this mechanism. +In spite of what you might expect, the codebase involved in this interface is not +that large. If you know \CONTEXT, and if you know how to call commands, you +basically can use this \LUA\ method. + +The examples that I will give are either (sort of) standalone, i.e.\ they are +dealt with from \LUA, or they are run within this document. Therefore you will +see two patterns. If you want to make your own documentation, then you can use +this variant: + +\starttyping +\startbuffer +context("See this!") +\stopbuffer + +\typebuffer \ctxluabuffer +\stoptyping + +I use anonymous buffers here but you can also use named ones. The other variant +is: + +\starttyping +\startluacode +context("See this!") +\stopluacode +\stoptyping + +This will process the code directly. Of course we could have encoded this +document completely in \LUA\ but that is not much fun for a manual. + +\stopsection + +\startsection[title=The main command] + +There are a few rules that you need to be aware of. First of all no syntax +checking is done. Second you need to know what the given commands expects in +terms of arguments. Third, the type of your arguments matters: + +\starttabulate[|||] +\NC \type{nothing} \EQ just the command, no arguments \NC \NR +\NC \type{string} \EQ an argument with curly braces \NC \NR +\NC \type{array} \EQ a list between square backets (sometimes optional) \NC \NR +\NC \type{hash} \EQ an assignment list between square brackets \NC \NR +\NC \type{boolean} \EQ when \type {true} a newline is inserted \NC \NR +\NC \EQ when \type {false}, omit braces for the next argument \NC \NR +\stoptabulate + +In the code above you have seen examples of this but here are some more: + +\starttyping +context.chapter("Some title") +context.chapter({ "first" }, "Some title") +context.startchapter({ title = "Some title", label = "first" }) +\stoptyping + +This blob of code is equivalent to: + +\starttyping +\chapter{Some title} +\chapter[first]{Some title} +\startchapter[title={Some title},label=first] +\stoptyping + +You can simplify the third line of the \LUA\ code to: + +\starttyping +context.startchapter { title = "Some title", label = "first" } +\stoptyping + +In case you wonder what the distinction is between square brackets and curly +braces: the first category of arguments concerns settings or lists of options or +names of instances while the second category normally concerns some text to be +typeset. + +Strings are interpreted as \TEX\ input, so: + +\starttyping +context.mathematics("\\sqrt{2^3}") +\stoptyping + +and if you don't want to escape: + +\starttyping +context.mathematics([[\sqrt{2^3}]]) +\stoptyping + +are both correct. As \TEX\ math is a language in its own and a de-facto standard +way of inputting math this is quite natural, even at the \LUA\ end. + +\stopsection + +\startsection[title=Spaces and Lines] + +\index{spaces} +\index{lines} + +In a regular \TEX\ file, spaces and newline characters are collapsed into one +space. At the \LUA\ end the same happens. Compare the following examples. First +we omit spaces: + +\startbuffer +context("left") +context("middle") +context("right") +\stopbuffer + +\typebuffer \ctxluabuffer + +Next we add spaces: + +\startbuffer +context("left") +context(" middle ") +context("right") +\stopbuffer + +\typebuffer \ctxluabuffer + +We can also add more spaces: + +\startbuffer +context("left ") +context(" middle ") +context(" right") +\stopbuffer + +\typebuffer \ctxluabuffer + +In principle all content becomes a stream and after that the \TEX\ parser will do +its normal work: collapse spaces unless configured to do otherwise. Now take the +following code: + +\startbuffer +context("before") +context("word 1") +context("word 2") +context("word 3") +context("after") +\stopbuffer + +\typebuffer \ctxluabuffer + +Here we get no spaces between the words at all, which is what we expect. So, how +do we get lines (or paragraphs)? + +\startbuffer +context("before") +context.startlines() +context("line 1") +context("line 2") +context("line 3") +context.stoplines() +context("after") +\stopbuffer + +\typebuffer \ctxluabuffer + +This does not work out well, as again there are no lines seen at the \TEX\ end. +Newline tokens are injected by passing \type {true} to the \type {context} +command: + +\startbuffer +context("before") +context.startlines() +context("line 1") context(true) +context("line 2") context(true) +context("line 3") context(true) +context.stoplines() +context("after") +\stopbuffer + +\typebuffer \ctxluabuffer + +Don't confuse this with: + +\startbuffer +context("before") context.par() +context("line 1") context.par() +context("line 2") context.par() +context("line 3") context.par() +context("after") context.par() +\stopbuffer + +\typebuffer \ctxluabuffer + +There we use the regular \type {\par} command to finish the current paragraph and +normally you will use that method. In that case, when set, whitespace will be +added between paragraphs. + +This newline issue is a somewhat unfortunate inheritance of traditional \TEX, +where \type {\n} and \type {\r} mean something different. I'm still not sure if +the \CLD\ do the right thing as dealing with these tokens also depends on the +intended effect. Catcodes as well as the \LUATEX\ input parser also play a role. +Anyway, the following also works: + +\startbuffer +context.startlines() +context("line 1\n") +context("line 2\n") +context("line 3\n") +context.stoplines() +\stopbuffer + +\typebuffer + +\stopsection + +\startsection[title=Direct output] + +\index{direct output} +\index{verbose} + +The \CONTEXT\ user interface is rather consistent and the use of special input +syntaxes is discouraged. Therefore, the \LUA\ interface using tables and strings +works quite well. However, imagine that you need to support some weird macro (or +a primitive) that does not expect its argument between curly braces or brackets. +The way out is to precede an argument by another one with the value \type +{false}. We call this the direct interface. This is demonstrated in the following +example. + +\startbuffer +\unexpanded\def\bla#1{[#1]} + +\startluacode +context.bla(false,"***") +context.par() +context.bla("***") +\stopluacode +\stopbuffer + +\typebuffer + +This results in: + +\getbuffer + +Here, the first call results in three \type {*} being passed, and \type {#1} +picks up the first token. The second call to \type {bla} gets \type {{***}} +passed so here \type {#1} gets the triplet. In practice you will seldom need the +direct interface. + +In \CONTEXT\ for historical reasons, combinations accept the following syntax: + +\starttyping +\startcombination % optional specification, like [2*3] + {\framed{content one}} {caption one} + {\framed{content two}} {caption two} +\stopcombination +\stoptyping + +You can also say: + +\starttyping +\startcombination + \combination {\framed{content one}} {caption one} + \combination {\framed{content two}} {caption two} +\stopcombination +\stoptyping + +When coded in \LUA, we can feed the first variant as follows: + +\startbuffer +context.startcombination() + context.direct("one","two") + context.direct("one","two") +context.stopcombination() +\stopbuffer + +\typebuffer + +To give you an idea what this looks like, we render it: + +\startlinecorrection[blank] +\ctxluabuffer +\stoplinecorrection + +So, the \type {direct} function is basically a no|-|op and results in nothing by +itself. Only arguments are passed. An equivalent but bit more ugly looking is: + +\starttyping +context.startcombination() + context(false,"one","two") + context(false,"one","two") +context.stopcombination() +\stoptyping + +\stopsection + +\startsection[title=Catcodes] + +\index{catcodes} + +If you are familiar with the inner working of \TEX, you will know that characters +can have special meanings. This meaning is determined by their catcodes. + +\startbuffer +context("$x=1$") +\stopbuffer + +\typebuffer + +This gives: \ctxluabuffer\ because the dollar tokens trigger inline math mode. If +you think that this is annoying, you can do the following: + +\startbuffer +context.pushcatcodes("text") +context("$x=1$") +context.popcatcodes() +\stopbuffer + +\typebuffer + +Now we get: \ctxluabuffer. There are several catcode regimes of +which only a few make sense in the perspective of the cld +interface. + +\starttabulate[|Tl|l|] +\NC ctx, ctxcatcodes, context \NC the normal \CONTEXT\ catcode regime \NC \NR +\NC prt, prtcatcodes, protect \NC the \CONTEXT\ protected regime, used for modules \NC \NR +\NC tex, texcatcodes, plain \NC the traditional (plain) \TEX\ regime \NC \NR +\NC txt, txtcatcodes, text \NC the \CONTEXT\ regime but with less special characters \NC \NR +\NC vrb, vrbcatcodes, verbatim \NC a regime specially meant for verbatim \NC \NR +\NC xml, xmlcatcodes \NC a regime specially meant for \XML\ processing \NC \NR +\stoptabulate + +In the second case you can still get math: + +\starttyping +context.pushcatcodes("text") +context.mathematics("x=1") +context.popcatcodes() +\stoptyping + +When entering a lot of math you can also consider this: + +\starttyping +context.startimath() +context("x") +context("=") +context("1") +context.stopimath() +\stoptyping + +Module writers of course can use \type {unprotect} and \type {protect} as they do +at the \TEX\ end. + +As we've seen, a function call to \type {context} acts like a print, as in: + +\startbuffer +context("test ") +context.bold("me") +context(" first") +\stopbuffer + +\typebuffer \ctxluabuffer + +When more than one argument is given, the first argument is considered a format +conforming the \type {string.format} function. + +\startbuffer +context.startimath() +context("%s = %0.5f",utf.char(0x03C0),math.pi) +context.stopimath() +\stopbuffer + +\typebuffer \ctxluabuffer + +This means that when you say: + +\starttyping +context(a,b,c,d,e,f) +\stoptyping + +the variables \type {b} till \type {f} are passed to the format and when the +format does not use them, they will not end up in your output. + +\starttyping +context("%s %s %s",1,2,3) +context(1,2,3) +\stoptyping + +The first line results in the three numbers being typeset, but in the second case +only the number~1 is typeset. + +\stopsection + +\stopchapter + +\stopcomponent diff --git a/doc/context/sources/general/manuals/cld/cld-goodies.tex b/doc/context/sources/general/manuals/cld/cld-goodies.tex new file mode 100644 index 000000000..d5b4b5c9c --- /dev/null +++ b/doc/context/sources/general/manuals/cld/cld-goodies.tex @@ -0,0 +1,621 @@ +% language=uk + +\startcomponent cld-macros + +% \usemodule[man-01] +% \setvariables[document][title=Font Goodies, author=Hans Hagen] +% \setups[titlepage] + +\environment cld-environment + +\startchapter[title=Font goodies] + +\startsection[title=Introduction] + +One of the interesting aspects of \TEX\ is that it provides control over fonts +and \LUATEX\ provides quite some. In \CONTEXT\ we support basic functionality, +like \OPENTYPE\ features, as well as some extra functionality. We also have a +mechanism for making virtual fonts which is mostly used for the transition from +\TYPEONE\ math fonts to \OPENTYPE\ math fonts. Instead of hard coding specific +details in the core \LUA\ code, we use so called \LUA\ Font Goodies to control +them. These goodies are collected in tables and live in files. When a font is +loaded, one or more such goodie files can be loaded alongside. + +In the following typescript we load a goodies file that defines a virtual Lucida +math font. The goodie file is loaded immediately and some information in the +table is turned into a form that permits access later on: the virtual font id +\type {lucida-math} that is used as part of the font specification. + +\starttyping +\starttypescript [math] [lucida] + \loadfontgoodies[lucida-math] + \definefontsynonym[MathRoman][lucidamath@lucida-math] +\stoptypescript +\stoptyping + +Not all information is to be used directly. Some can be accessed when needed. In +the following case the file \type {dingbats.lfg} gets loaded (only once) when the +font is actually used. In that file, there is information that is used by the +\type {unicoding} feature. + +\starttyping +\definefontfeature + [dingbats] + [mode=base, + goodies=dingbats, + unicoding=yes] + +\definefont[dingbats][file:dingbats][features=dingbats] +\stoptyping + +In the following sections some aspects of goodies are discussed. We don't go into +details of what these goodies are, but just stick to the \LUA\ side of the +specification. + +\stopsection + +\startsection[title=Virtual math fonts] + +A virtual font is defined using the \type {virtuals} entry in the \type +{mathematics} subtable. As \TYPEONE\ fonts are used, an additional table \type +{mapfiles} is needed to specify the files that map filenames onto real files. + +\startsmalltyping +return { + name = "px-math", + version = "1.00", + comment = "Goodies that complement px math.", + author = "Hans Hagen", + copyright = "ConTeXt development team", + mathematics = { + mapfiles = { + "mkiv-px.map", + }, + virtuals = { + ["px-math"] = { + { name = "texgyrepagella-regular.otf", features = "virtualmath", main = true }, + { name = "rpxr.tfm", vector = "tex-mr" } , + { name = "rpxmi.tfm", vector = "tex-mi", skewchar=0x7F }, + { name = "rpxpplri.tfm", vector = "tex-it", skewchar=0x7F }, + { name = "pxsy.tfm", vector = "tex-sy", skewchar=0x30, parameters = true } , + { name = "pxex.tfm", vector = "tex-ex", extension = true } , + { name = "pxsya.tfm", vector = "tex-ma" }, + { name = "pxsyb.tfm", vector = "tex-mb" }, + { name = "texgyrepagella-bold.otf", vector = "tex-bf" } , + { name = "texgyrepagella-bolditalic.otf", vector = "tex-bi" } , + { name = "lmsans10-regular.otf", vector = "tex-ss", optional=true }, + { name = "lmmono10-regular.otf", vector = "tex-tt", optional=true }, + }, + } + } +} +\stopsmalltyping + +Here the \type {px-math} virtual font is defined. A series of fonts is loaded and +combined into one. The \type {vector} entry is used to tell the builder how to +map the glyphs onto \UNICODE. Additional vectors can be defined, for instance: + +\starttyping +fonts.encodings.math["mine"] = { + [0x1234] = 0x56, +} +\stoptyping + +Eventually these specifications wil be replaced by real \OPENTYPE\ fonts, but +even then we will keep the virtual definitions around. + +\startsection[title=Math alternates] + +In addition to the official \type {ssty} feature for enforcing usage of script +and scriptscript glyphs, some stylistic alternates can be present. + +\startsmalltyping +return { + name = "xits-math", + version = "1.00", + comment = "Goodies that complement xits (by Khaled Hosny).", + author = "Hans Hagen", + copyright = "ConTeXt development team", + mathematics = { + alternates = { + cal = { + feature = 'ss01', + value = 1, + comment = "Mathematical Calligraphic Alphabet" + }, + greekssup = { + feature = 'ss02', + value = 1, + comment = "Mathematical Greek Sans Serif Alphabet" + }, + greekssit = { + feature = 'ss03', + value = 1, + comment = "Mathematical Italic Sans Serif Digits" + }, + monobfnum = { + feature = 'ss04', + value = 1, + comment = "Mathematical Bold Monospace Digits" + }, + mathbbbf = { + feature = 'ss05', + value = 1, + comment = "Mathematical Bold Double-Struck Alphabet" + }, + mathbbit = { + feature = 'ss06', + value = 1, + comment = "Mathematical Italic Double-Struck Alphabet" + }, + mathbbbi = { + feature = 'ss07', + value = 1, + comment = "Mathematical Bold Italic Double-Struck Alphabet" + }, + upint = { + feature = 'ss08', + value = 1, + comment = "Upright Integrals" + }, + } + } +} +\stopsmalltyping + +These can be activated (in math mode) with the \type {\mathalternate} command +like: + +\starttyping +$\mathalternate{cal}Z$ +\stoptyping + +\stopsection + +\startsection[title=Math parameters] + +Another goodie related to math is the overload of some parameters (part of the +font itself) and variables (used in making virtual shapes). + +\startsmalltyping +return { + name = "lm-math", + version = "1.00", + comment = "Goodies that complement latin modern math.", + author = "Hans Hagen", + copyright = "ConTeXt development team", + mathematics = { + mapfiles = { + "lm-math.map", + "lm-rm.map", + "mkiv-base.map", + }, + virtuals = { + ["lmroman5-math"] = five, + ["lmroman6-math"] = six, + ["lmroman7-math"] = seven, + ["lmroman8-math"] = eight, + ["lmroman9-math"] = nine, + ["lmroman10-math"] = ten, + ["lmroman10-boldmath"] = ten_bold, + ["lmroman12-math"] = twelve, + ["lmroman17-math"] = seventeen, + }, + variables = { + joinrelfactor = 3, -- default anyway + }, + parameters = { -- test values + -- FactorA = 123.456, + -- FactorB = false, + -- FactorC = function(value,target,original) return 7.89 * target.factor end, + -- FactorD = "Hi There!", + }, + } +} +\stopsmalltyping + +In this example you see several virtuals defined which is due to the fact that +Latin Modern has design sizes. The values (like \type {twelve} are tables defined +before the return happens and are not shown here. The variables are rather +\CONTEXT\ specific, and the parameters are those that come with regular +\OPENTYPE\ math fonts (so the example names are invalid). + +In the following example we show two wasy to change parameters. In this case we +have a regular \OPENTYPE\ math font. First we install a patch to the font itself. +That change will be cached. We could also have changed that parameter using the +goodies table. The first method is the oldest. + +\startsmalltyping +local patches = fonts.handlers.otf.enhancers.patches + +local function patch(data,filename,threshold) + local m = data.metadata.math + if m then + local d = m.DisplayOperatorMinHeight or 0 + if d < threshold then + patches.report("DisplayOperatorMinHeight(%s -> %s)",d,threshold) + m.DisplayOperatorMinHeight = threshold + end + end +end + +patches.register( + "after", + "check math parameters", + "asana", + function(data,filename) + patch(data,filename,1350) + end +) + +local function less(value,target,original) + return 0.25 * value +end + +return { + name = "asana-math", + version = "1.00", + comment = "Goodies that complement asana.", + author = "Hans Hagen", + copyright = "ConTeXt development team", + mathematics = { + parameters = { + StackBottomDisplayStyleShiftDown = less, + StackBottomShiftDown = less, + StackDisplayStyleGapMin = less, + StackGapMin = less, + StackTopDisplayStyleShiftUp = less, + StackTopShiftUp = less, + StretchStackBottomShiftDown = less, + StretchStackGapAboveMin = less, + StretchStackGapBelowMin = less, + StretchStackTopShiftUp = less, + } + } +} +\stopsmalltyping + +We use a function so that the scaling is taken into account as the values passed +are those resulting from the scaling of the font to the requested size. + +\stopsection + +\startsection[title=Unicoding] + +We still have to deal with existing \TYPEONE\ fonts, and some of them have an +encoding that is hard to map onto \UNICODE\ without additional information. The +following goodie does that. The keys in the \type {unicodes} table are the glyph +names. Keep in mind that this only works with simple fonts. The \CONTEXT\ code +takes care of kerns but that's about it. + +\startsmalltyping +return { + name = "dingbats", + version = "1.00", + comment = "Goodies that complement dingbats (funny names).", + author = "Hans Hagen", + copyright = "ConTeXt development team", + remapping = { + tounicode = true, + unicodes = { + a1 = 0x2701, + a10 = 0x2721, + a100 = 0x275E, + a101 = 0x2761, + ............. + a98 = 0x275C, + a99 = 0x275D, + }, + }, +} +\stopsmalltyping + +The \type {tounicode} option makes sure that additional information ends ip in +the output so that cut|-|and|-|paste becomes more trustworthy. + +\stopsection + +\startsection[title=Typescripts] + +Some font collections, like antykwa, come with so many variants that defining +them all in typescripts becomes somewhat of a nuisance. While a regular font has +a typescript of a few lines, antykwa needs way more lines. This is why we provide +a nother way as well, using goodies. + +\startsmalltyping +return { + name = "antykwapoltawskiego", + version = "1.00", + comment = "Goodies that complement Antykwa Poltawskiego", + author = "Hans & Mojca", + copyright = "ConTeXt development team", + files = { + name = "antykwapoltawskiego", -- shared + list = { + ["AntPoltLtCond-Regular.otf"] = { + -- name = "antykwapoltawskiego", + weight = "light", + style = "regular", + width = "condensed", + }, + ["AntPoltLtCond-Italic.otf"] = { + weight = "light", + style = "italic", + width = "condensed", + }, + ["AntPoltCond-Regular.otf"] = { + weight = "normal", + style = "regular", + width = "condensed", + }, + + ....... + + + ["AntPoltExpd-BoldItalic.otf"] = { + weight = "bold", + style = "italic", + width = "expanded", + }, + }, + }, + typefaces = { -- for Mojca (experiment, names might change) + ["antykwapoltawskiego-light"] = { + shortcut = "rm", + shape = "serif", + fontname = "antykwapoltawskiego", + normalweight = "light", + boldweight = "medium", + width = "normal", + size = "default", + features = "default", + }, + + ....... + + }, +} +\stopsmalltyping + +This is a typical example of when a goodies file is loaded directly: + +\starttyping +\loadfontgoodies[antykwapoltawskiego] +\stoptyping + +A bodyfont is now defined by choosing from the defined combinations: + +\starttyping +\definetypeface + [name=mojcasfavourite, + preset=antykwapoltawskiego, + normalweight=light, + boldweight=bold, + width=expanded] + +\setupbodyfont + [mojcasfavourite] +\stoptyping + +This mechanism is a follow up on a discussion at a \CONTEXT\ conference, still +somewhat experimental, and a playground for Mojca. + +\stopsection + +\startsection[title=Font strategies] + +This goodie is closely related to the Oriental \TEX\ project where a dedicated +paragraph optimizer can be used. A rather advanced font is used (husayni) and its +associated goodie file is rather extensive. It defines stylistic features, +implements a couple of feature sets, provides colorschemes and most of all, +defines some strategies for making paragraphs look better. Some of the goodie +file is shown here. + +\startsmalltyping +local yes = "yes" + +local basics = { + analyze = yes, + mode = "node", + language = "dflt", + script = "arab", +} + +local analysis = { + ccmp = yes, + init = yes, medi = yes, fina = yes, +} + +local regular = { + rlig = yes, calt = yes, salt = yes, anum = yes, + ss01 = yes, ss03 = yes, ss07 = yes, ss10 = yes, ss12 = yes, ss15 = yes, ss16 = yes, + ss19 = yes, ss24 = yes, ss25 = yes, ss26 = yes, ss27 = yes, ss31 = yes, ss34 = yes, + ss35 = yes, ss36 = yes, ss37 = yes, ss38 = yes, ss41 = yes, ss42 = yes, ss43 = yes, + js16 = yes, +} + +local positioning = { + kern = yes, curs = yes, mark = yes, mkmk = yes, +} + +local minimal_stretching = { + js11 = yes, js03 = yes, +} + +local medium_stretching = { + js12=yes, js05=yes, +} + +local maximal_stretching= { + js13 = yes, js05 = yes, js09 = yes, +} + +local wide_all = { + js11 = yes, js12 = yes, js13 = yes, js05 = yes, js09 = yes, +} + +local shrink = { + flts = yes, js17 = yes, ss05 = yes, ss11 = yes, ss06 = yes, ss09 = yes, +} + +local default = { + basics, analysis, regular, positioning, -- xxxx = yes, yyyy = 2, +} + +return { + name = "husayni", + version = "1.00", + comment = "Goodies that complement the Husayni font by Idris Samawi Hamid.", + author = "Idris Samawi Hamid and Hans Hagen", + featuresets = { -- here we don't have references to featuresets + default = { + default, + }, + minimal_stretching = { + default, + js11 = yes, js03 = yes, + }, + medium_stretching = { + default, + js12=yes, js05=yes, + }, + maximal_stretching= { + default, + js13 = yes, js05 = yes, js09 = yes, + }, + wide_all = { + default, + js11 = yes, js12 = yes, js13 = yes, js05 = yes, js09 = yes, + }, + shrink = { + default, + flts = yes, js17 = yes, ss05 = yes, ss11 = yes, ss06 = yes, ss09 = yes, + }, + }, + solutions = { -- here we have references to featuresets, so we use strings! + experimental = { + less = { + "shrink" + }, + more = { + "minimal_stretching", + "medium_stretching", + "maximal_stretching", + "wide_all" + }, + }, + }, + stylistics = { + ...... + ss03 = "level-1 stack over Jiim, initial entry only", + ss04 = "level-1 stack over Jiim, initial/medial entry", + ...... + ss54 = "chopped finals", + ss55 = "idgham-tanwin", + ...... + js11 = "level-1 stretching", + js12 = "level-2 stretching", + ...... + js21 = "Haa.final_alt2", + }, + colorschemes = { + default = { + [1] = { + "Onedotabove", "Onedotbelow", ... + }, + [2] = { + "Fathah", "Dammah", "Kasrah", ... + }, + [3] = { + "Ttaa.waqf", "SsLY.waqf", "QLY.waqf", ... + }, + [4] = { + "ZeroArabic.ayah", "OneArabic.ayah", "TwoArabic.ayah", ... + }, + [5] = { + "Ayah", "Ayah.alt1", "Ayah.alt2", ... + } + } + } +} +\stopmalltyping + +Discussion of these goodies is beyond this document and happens elsewhere. + +\stopsection + +\startsection[title=Composition] + +The \type {compose} features extends a font with additional (virtual) shapes. +This is mostly used with \TYPEONE\ fonts that lack support for eastern european +languages. The type {compositions} subtable is used to control placement of +accents. This can be done per font. + +\startmalltyping +local defaultunits = 193 - 30 + +-- local compose = { +-- DY = defaultunits, +-- [0x010C] = { DY = defaultunits }, -- Ccaron +-- [0x02C7] = { DY = defaultunits }, -- textcaron +-- } + +-- fractions relative to delta(X_height - x_height) + +local defaultfraction = 0.85 + +local compose = { + DY = defaultfraction, -- uppercase compensation +} + +return { + name = "lucida-one", + version = "1.00", + comment = "Goodies that complement lucida.", + author = "Hans and Mojca", + copyright = "ConTeXt development team", + compositions = { + ["lbr"] = compose, + ["lbi"] = compose, + ["lbd"] = compose, + ["lbdi"] = compose, + } +} +\stopsmalltyping + +\stopsection + +\startsection[title=Postprocessing] + +You can hook postprocessors into the scaler. Future versions might provide more +control over where this happens. + +\startsmalltyping +local function statistics(tfmdata) + commands.showfontparameters(tfmdata) +end + +local function squeeze(tfmdata) + for k, v in next, tfmdata.characters do + v.height = 0.75 * (v.height or 0) + v.depth = 0.75 * (v.depth or 0) + end +end + +return { + name = "demo", + version = "1.00", + comment = "An example of goodies.", + author = "Hans Hagen", + postprocessors = { + statistics = statistics, + squeeze = squeeze, + }, +} +\stopsmalltyping + +\stopsection + +\stopchapter + +\stopcomponent diff --git a/doc/context/sources/general/manuals/cld/cld-graphics.tex b/doc/context/sources/general/manuals/cld/cld-graphics.tex new file mode 100644 index 000000000..93ab80c2c --- /dev/null +++ b/doc/context/sources/general/manuals/cld/cld-graphics.tex @@ -0,0 +1,342 @@ +% language=uk + +\startcomponent cld-graphics + +\environment cld-environment + +\startchapter[title=Graphics] + +\startsection[title=The regular interface] + +If you are familiar with \CONTEXT, which by now probably is the case, you will +have noticed that it integrates the \METAPOST\ graphic subsystem. Drawing a +graphic is not that complex: + +\startbuffer +context.startMPcode() +context [[ + draw + fullcircle scaled 1cm + withpen pencircle scaled 1mm + withcolor .5white + dashed dashpattern (on 2mm off 2mm) ; + ]] +context.stopMPcode() +\stopbuffer + +\typebuffer + +We get a gray dashed circle rendered with an one millimeter thick line: + +\startlinecorrection +\ctxluabuffer +\stoplinecorrection + +So, we just use the regular commands and pass the drawing code as strings. +Although \METAPOST\ is a rather normal language and therefore offers loops and +conditions and the lot, you might want to use \LUA\ for anything else than the +drawing commands. Of course this is much less efficient, but it could be that you +don't care about speed. The next example demonstrates the interface for building +graphics piecewise. + +\startbuffer +context.resetMPdrawing() + +context.startMPdrawing() +context([[fill fullcircle scaled 5cm withcolor (0,0,.5) ;]]) +context.stopMPdrawing() + +context.MPdrawing("pickup pencircle scaled .5mm ;") +context.MPdrawing("drawoptions(withcolor white) ;") + +for i=0,50,5 do + context.startMPdrawing() + context("draw fullcircle scaled %smm ;",i) + context.stopMPdrawing() +end + +for i=0,50,5 do + context.MPdrawing("draw fullsquare scaled " .. i .. "mm ;") +end + +context.MPdrawingdonetrue() + +context.getMPdrawing() +\stopbuffer + +\typebuffer + +This gives: + +\startlinecorrection +\ctxluabuffer +\stoplinecorrection + +I the first loop we can use the format options associated with the simple \type +{context} call. This will not work in the second case. Even worse, passing more +than one argument will definitely give a faulty graphic definition. This is why +we have a special interface for \METAFUN. The code above can also be written as: + +\startbuffer +local metafun = context.metafun + +metafun.start() + +metafun("fill fullcircle scaled 5cm withcolor %s ;", + metafun.color("darkblue")) + +metafun("pickup pencircle scaled .5mm ;") +metafun("drawoptions(withcolor white) ;") + +for i=0,50,5 do + metafun("draw fullcircle scaled %smm ;",i) +end + +for i=0,50,5 do + metafun("draw fullsquare scaled %smm ;",i) +end + +metafun.stop() +\stopbuffer + +\typebuffer + +Watch the call to \type {color}, this will pass definitions at the \TEX\ end to +\METAPOST. Of course you really need to ask yourself \quotation {Do I want to use +\METAPOST\ this way?}. Using \LUA\ loops instead of \METAPOST\ ones makes much +more sense in the following case: + +\startbuffer +local metafun = context.metafun + +function metafun.barchart(t) + metafun.start() + local t = t.data + for i=1,#t do + metafun("draw unitsquare xyscaled(%s,%s) shifted (%s,0);", + 10, t[i]*10, i*10) + end + metafun.stop() +end + +local one = { 1, 4, 6, 2, 3, } +local two = { 8, 1, 3, 5, 9, } + +context.startcombination() + context.combination(metafun.delayed.barchart { data = one }, "one") + context.combination(metafun.delayed.barchart { data = two }, "two") +context.stopcombination() +\stopbuffer + +\typebuffer + +We get two barcharts alongside: + +\startlinecorrection +\ctxluabuffer +\stoplinecorrection + +\startbuffer +local template = [[ + path p, q ; color c[] ; + c1 := \MPcolor{darkblue} ; + c2 := \MPcolor{darkred} ; + p := fullcircle scaled 50 ; + l := length p ; + n := %s ; + q := subpath (0,%s/n*l) of p ; + draw q withcolor c2 withpen pencircle scaled 1 ; + fill fullcircle scaled 5 shifted point length q of q withcolor c1 ; + setbounds currentpicture to unitsquare shifted (-0.5,-0.5) scaled 60 ; + draw boundingbox currentpicture withcolor c1 ; + currentpicture := currentpicture xsized(1cm) ; +]] + +local function steps(n) + for i=0,n do + context.metafun.start() + context.metafun(template,n,i) + context.metafun.stop() + if i < n then + context.quad() + end + end +end + +context.hbox(function() steps(10) end) +\stopbuffer + +\typebuffer + +\startlinecorrection +\ctxluabuffer +\stoplinecorrection + +Using a template is quite convenient but at some point you can loose track of the +replacement values. Also, adding an extra value can force you to adapt the +following ones which enlarges the change for making an error. An alternative is +to use the template mechanism. Although this mechanism was originally made for +other purposes, you can use it for whatever you like. + +\startbuffer +local template = [[ + path p ; p := fullcircle scaled 4cm ; + draw p withpen pencircle scaled .5mm withcolor red ; + freedotlabel ("%lefttop%", point 1 of p,origin) ; + freedotlabel ("%righttop%", point 3 of p,origin) ; + freedotlabel ("%leftbottom%", point 5 of p,origin) ; + freedotlabel ("%rightbottom%",point 7 of p,origin) ; +]] + +local variables = { + lefttop = "one", + righttop = "two", + leftbottom = "three", + rightbottom = "four" , +} + +context.metafun.start() + context.metafun(utilities.templates.replace(template,variables)) +context.metafun.stop() +\stopbuffer + +\typebuffer + +Here we use named placeholders and pass a table with associated values to the +replacement function. Apart from convenience it's also more readable. And the +overhead is rather minimal. + +\startlinecorrection +\ctxluabuffer +\stoplinecorrection + +To some extent we fool ourselves with this kind of \LUA fication of \METAPOST\ +code. Of course we can make a nice \METAPOST\ library and put the code in a macro +instead. In that sense, doing this in \CONTEXT\ directly often gives better and +more efficient code. + +Of course you can use all relevant commands in the \LUA\ interface, like: + +\starttyping +context.startMPpage() + context("draw origin") + for i=0,100,10 do + context("..{down}(%d,0)",i) + end + context(" withcolor \\MPcolor{darkred} ;") +context.stopMPpage() +\stoptyping + +to get a graphic that has its own page. Don't use the \type {metafun} namespace +here, as it will not work here. This drawing looks like: + +\startlinecorrection +\startluacode +context.startMPcode() + context("draw origin") + for i=0,100,10 do + context("..{down}(%d,0)",i) + end + context(" withcolor red ;") +context.stopMPcode() +\stopluacode +\stoplinecorrection + +\stopsection + +\startsection[title=The \LUA\ interface] + +Messing around with graphics is normally not needed and if you do it, you'd +better know what you're doing. For \TEX\ a graphic is just a black box: a +rectangle with dimensions. You specify a graphic, in a format that the backend +can deal with, either or not apply some scaling and from then on a reference to +that graphic, normally wrapped in a normal \TEX\ box, enters the typesetting +machinery. Because the backend, the part that is responsible for translating +typeset content onto a viewable or printable format like \PDF, is built into +\LUATEX, at some point the real image has to be injected and the backend can only +handle a few image formats: \PNG, \JPG, \JBIG\ and \PDF. + +In \CONTEXT\ some more image formats are supported but in practice this boils +down to converting the image to a format that the backend can handle. Such a +conversion depends on an external programs and in order not to redo the +conversion each run \CONTEXT\ keeps track of the need to redo it. + +Some converters are built in, for example one that deals with \GIF\ images. This +is normally not a preferred format, but it happens that we have to deal with it +in cases where organizations use that format (if only because they use the web). +Here is how this works at the \LUA\ end: + +\starttyping +figures.converters.gif = { + pdf = function(oldname,newname) + os.execute(string.format("gm convert %s %s",oldname,newname)) + end +} +\stoptyping + +We use \type {gm} (Graphic Magic) for the conversion and pass the old and new +names. Given this definition at the \TEX\ end we can say: + +\starttyping +\externalfigure[whatever.gif][width=4cm] +\stoptyping + +Here is a another one: + +\starttyping +figures.converters.bmp = { + pdf = function(oldname,newname) + os.execute(string.format("gm convert %s %s",oldname,newname)) + end +} +\stoptyping + +In both examples we convert to \PDF\ because including this filetype is quite +fast. But you can also go to other formats: + +\starttyping +figures.converters.png = { + png = function(oldname,newname,resolution) + local command = string.format('gm convert -depth 1 "%s" "%s"',oldname,newname) + logs.report(string.format("running command %s",command)) + os.execute(command) + end +} +\stoptyping + +Instead of directly defining such a table, you can better do this: + +\starttyping +figures.converters.png = figures.converters.png or { } + +figures.converters.png.png = function(oldname,newname,resolution) + local command = string.format('gm convert -depth 1 "%s" "%s"',oldname,newname) + logs.report(string.format("running command %s",command)) + os.execute(command) +end +\stoptyping + +Here we check if a table exists and if not we extend the table. Such converters +work out of the box if you specify the suffix, but you can also opt for a simple: + +\starttyping +\externalfigure[whatever][width=4cm] +\stoptyping + +In this case \CONTEXT\ will check for all known supported formats, which is not +that efficient when no graphic can be found. In order to let for instance files +with suffix \type {bmp} can be included you have to register it as follows. The +second argument is the target. + +\starttyping +figures.registersuffix("bmp","bmp") +\stoptyping + +At some point more of the graphic inclusion helpers will be opened up for general +use but for now this is what you have available. + +\stopsection + +\stopchapter + +\stopcomponent diff --git a/doc/context/sources/general/manuals/cld/cld-introduction.tex b/doc/context/sources/general/manuals/cld/cld-introduction.tex new file mode 100644 index 000000000..82fcb8007 --- /dev/null +++ b/doc/context/sources/general/manuals/cld/cld-introduction.tex @@ -0,0 +1,55 @@ +% language=uk + +\startcomponent cld-introduction + +\environment cld-environment + +\startchapter[title=Introduction] + +Sometimes you hear folks complain about the \TEX\ input language, i.e.\ the +backslashed commands that determine your output. Of course, when alternatives are +being discussed every one has a favourite programming language. In practice +coding a document in each of them triggers similar sentiments with regards to +coding as \TEX\ itself does. + +So, just for fun, I added a couple of commands to \CONTEXT\ \MKIV\ that permit +coding a document in \LUA. In retrospect it has been surprisingly easy to +implement a feature like this using metatables. Of course it's a bit slower than +using \TEX\ as input language but sometimes the \LUA\ interface is more readable +given the problem at hand. + +After a while I decided to use that interface in non|-|critical core \CONTEXT\ +code and in styles (modules) and solutions for projects. Using the \LUA\ approach +is sometimes more convenient, especially if the code mostly manipulates data. For +instance, if you process \XML\ files of database output you can use the interface +that is available at the \TEX\ end, or you can use \LUA\ code to do the work, or +you can use a combination. So, from now on, in \CONTEXT\ you can code your style +and document source in (a mixture of) \TEX, \XML, \METAPOST\ and in \LUA. + +In the following chapters I will introduce typesetting in \LUA, but as we rely on +\CONTEXT\ it is unavoidable that some regular \CONTEXT\ code shows up. The fact +that you can ignore backslashes does not mean that you can do without knowledge +of the underlying system. I expect that the user is somewhat familiar with this +macro package. Some chapters are follow ups on articles or earlier publications. + +Some information (and mechanism) show up in more than one chapter. This is a side +effect of \LUA\ being integrated in many places, so an isolated discussion is a +bit hard. + +In the meantime most of the code is rather stable and proven. However, this +manual will never be complete. You can find examples all over the code base, and +duplicating everything here makes no sense. If you find errors, please let me +know. If you think that something is missing, you can try to convince me to add +it. It's hard to keep up with what gets added so input is welcome. + +\blank[2*big] + +\startlines +Hans Hagen +Hasselt NL +2009 \emdash\ 2016 +\stoplines + +\stopchapter + +\stopcomponent diff --git a/doc/context/sources/general/manuals/cld/cld-logging.tex b/doc/context/sources/general/manuals/cld/cld-logging.tex new file mode 100644 index 000000000..cbb904a69 --- /dev/null +++ b/doc/context/sources/general/manuals/cld/cld-logging.tex @@ -0,0 +1,91 @@ +% language=uk + +% maybe this will become a section instead + +\startcomponent cld-logging + +\environment cld-environment + +\startchapter[title={Logging}] + +Logging and localized messages have always been rather standardized in \CONTEXT, +so upgrading the related mechanism had been quite doable. In \MKIV\ for a while +we had two systems in parallel: the old one, mostly targeted at messages at the +\TEX\ end, and a new one used at the \LUA\ end. But when more and more hybrid +code showed up, integrating both systems made sense. + +Most logging concerns tracing and can be turned on and off on demand. This kind +of control is now possible for all messages. Given that the right interfaces are +used, you can turn off all messages: + +\starttyping +context --silent +\stoptyping + +This was already possible in \MKII, but there \TEX's own messages still were +visible. More important is that we have control: + +\starttyping +context --silent=structure*,resolve*,font* +\stoptyping + +This will disable all reporting for these three categories. It is also possible +to only disable messages to the console: + +\starttyping +context --noconsole +\stoptyping + +In \CONTEXT\ you can use directives: + +\starttyping +\enabledirectives[logs.blocked=structure*,resolve*,font*] +\enabledirectives[logs.target=file] +\stoptyping + +As all logging is under \LUA\ control and because this (and other) kind of +control has to kick in early in the initialization the code might look somewhat +tricky. Users won't notice this because they only deal with the formal interface. +Here we will only discuss the \LUA\ interfaces. + +Messages related to tracing are done as follows: + +\starttyping +local report_whatever = logs.reporter("modules","whatever") + +report_whatever("not found: %s","this or that") +\stoptyping + +The first line defined a logger in the category \type {modules}. You can give a +second argument as well, the subcategory. Both will be shown as part of the +message, of which an example is given in the second line. + +These messages are shown directly, that is, when the function is called. However, +when you generate \TEX\ code, as we discuss in this document, you need to make +sure that the message is synchronized with that code. This can be done with a +messenger instead of a reporter. + +\starttyping +local report_numbers = logs.reporter("numbers","check") +local status_numbers = logs.messenger("numbers","check") + +status_numbers("number 1: %s, number 2: %s",123,456) +report_numbers("number 1: %s, number 2: %s",456,123) +\stoptyping + +Both reporters and messages are localized when the pattern given as first +argument can be found in the \type {patterns} subtable of the interface messages. +Categories and subcategories are also translated, but these are looked up in the +\type {translations} subtable. So in the case of + +\starttyping +report_whatever("found: %s",filename) +report_whatever("not found: %s",filename) +\stoptyping + +you should not be surprised if it gets translated. Of course the category and +subcategory provide some contextual information. + +\stopchapter + +\stopcomponent diff --git a/doc/context/sources/general/manuals/cld/cld-luafunctions.tex b/doc/context/sources/general/manuals/cld/cld-luafunctions.tex new file mode 100644 index 000000000..69586887d --- /dev/null +++ b/doc/context/sources/general/manuals/cld/cld-luafunctions.tex @@ -0,0 +1,2322 @@ +% language=uk + +% table.unnest : only used in special cases +% table.derive : set metatable if unset +% table.compact : remove empty subtables + +\environment cld-environment + +\startcomponent cld-luafunctions + +\startchapter[title=Lua Functions] + +\startsection[title={Introduction}] + +When you run \CONTEXT\ you have some libraries preloaded. If you look into the +\LUA\ files you will find more than is discussed here, but keep in mind that what +is not documented, might be gone or done different one day. Some extensions live +in the same namespace as those provided by stock \LUA\ and \LUATEX, others have +their own. There are many more functions and the more obscure (or never being +used) ones will go away. + +The \LUA\ code in \CONTEXT\ is organized in quite some modules. Those with names +like \type {l-*.lua} are rather generic and are automatically available when you +use \type {mtxrun} to run a \LUA\ file. These are discusses in this chapter. A +few more modules have generic properties, like some in the categories \type +{util-*.lua}, \type {trac-*.lua}, \type {luat-*.lua}, \type {data-*.lua} and +\type {lxml-*.lua}. They contain more specialized functions and are discussed +elsewhere. + +Before we move on the the real code, let's introduce a handy helper: + +\starttyping +inspect(somevar) +\stoptyping + +Whenever you feel the need to see what value a variable has you can insert this +function to get some insight. It knows how to deal with several data types. + +\stopsection + +\startsection[title={Tables}] + +\startsummary[title={[lua] concat}] + +These functions come with \LUA\ itself and are discussed in detail in the \LUA\ +reference manual so we stick to some examples. The \type {concat} function +stitches table entries in an indexed table into one string, with an optional +separator in between. If can also handle a slice of the table + +\starttyping +local str = table.concat(t) +local str = table.concat(t,separator) +local str = table.concat(t,separator,first) +local str = table.concat(t,separator,first,last) +\stoptyping + +Only strings and numbers can be concatenated. + +\ShowLuaExampleThree {table} {concat} {{"a","b","c","d","e"}} +\ShowLuaExampleThree {table} {concat} {{"a","b","c","d","e"},"+"} +\ShowLuaExampleThree {table} {concat} {{"a","b","c","d","e"},"+",2,3} + +\stopsummary + +\startsummary[title={[lua] insert remove}] + +You can use \type {insert} and \type {remove} for adding or replacing entries in +an indexed table. + +\starttyping +table.insert(t,value,position) +value = table.remove(t,position) +\stoptyping + +The position is optional and defaults to the last entry in the table. For +instance a stack is built this way: + +\starttyping +table.insert(stack,"top") +local top = table.remove(stack) +\stoptyping + +Beware, the \type {insert} function returns nothing. You can provide an +additional position: + +\starttyping +table.insert(list,"injected in slot 2",2) +local thiswastwo = table.remove(list,2) +\stoptyping + +\stopsummary + +\startsummary[title={[lua] unpack}] + +You can access entries in an indexed table as follows: + +\starttyping +local a, b, c = t[1], t[2], t[3] +\stoptyping + +but this does the same: + +\starttyping +local a, b, c = table.unpack(t) +\stoptyping + +This is less efficient but there are situations where \type {unpack} +comes in handy. + +\stopsummary + +\startsummary[title={[lua] sort}] + +Sorting is done with \type {sort}, a function that does not return a value but +operates on the given table. + +\starttyping +table.sort(t) +table.sort(t,comparefunction) +\stoptyping + +The compare function has to return a consistent equivalent of \type {true} or +\type {false}. For sorting more complex data structures there is a specialized +sort module available. + +\ShowLuaExampleFour {table} {sort} {{"a","b","c"}} {} +\ShowLuaExampleFour {table} {sort} {{"a","b","c"}} {,function(x,y) return x > y end} +\ShowLuaExampleFour {table} {sort} {{"a","b","c"}} {,function(x,y) return x < y end} + +\stopsummary + +\startsummary[title={sorted}] + +The built|-|in \type {sort} function does not return a value but sometimes it can be +if the (sorted) table is returned. This is why we have: + +\starttyping +local a = table.sorted(b) +\stoptyping + +\stopsummary + +% table.strip + +\startsummary[title={keys sortedkeys sortedhashkeys sortedhash}] + +The \type {keys} function returns an indexed list of keys. The order is undefined +as it depends on how the table was constructed. A sorted list is provided by +\type {sortedkeys}. This function is rather liberal with respect to the keys. If +the keys are strings you can use the faster alternative \type {sortedhashkeys}. + +\starttyping +local s = table.keys (t) +local s = table.sortedkeys (t) +local s = table.sortedhashkeys (t) +\stoptyping + +Because a sorted list is often processed there is also an iterator: + +\starttyping +for key, value in table.sortedhash(t) do + print(key,value) +end +\stoptyping + +There is also a synonym \type {sortedpairs} which sometimes looks more natural +when used alongside the \type {pairs} and \type {ipairs} iterators. + +\ShowLuaExampleTwo {table} {keys} {{ [1] = 2, c = 3, [true] = 1 }} +\ShowLuaExampleTwo {table} {sortedkeys} {{ [1] = 2, c = 3, [true] = 1 }} +\ShowLuaExampleTwo {table} {sortedhashkeys} {{ a = 2, c = 3, b = 1 }} + +\stopsummary + +\startsummary[title={serialize print tohandle tofile}] + +The \type {serialize} function converts a table into a verbose representation. +The \type {print} function does the same but prints the result to the console +which is handy for tracing. The \type {tofile} function writes the table to a +file, using reasonable chunks so that less memory is used. The fourth variant +\type {tohandle} takes a handle so that you can do whatever you like with the +result. + +\starttyping +table.serialize (root, name, reduce, noquotes, hexify) +table.print (root, name, reduce, noquotes, hexify) +table.tofile (filename, root, name, reduce, noquotes, hexify) +table.tohandle (handle, root, name, reduce, noquotes, hexify) +\stoptyping + +The serialization can be controlled in several ways. Often only the first two +options makes sense: + +\ShowLuaExampleOne {table} {serialize} {{ a = 2 }} +\ShowLuaExampleOne {table} {serialize} {{ a = 2 }, "name"} +\ShowLuaExampleOne {table} {serialize} {{ a = 2 }, true} +\ShowLuaExampleOne {table} {serialize} {{ a = 2 }, false} +\ShowLuaExampleOne {table} {serialize} {{ a = 2 }, "return"} +\ShowLuaExampleOne {table} {serialize} {{ a = 2 }, 12} + +\ShowLuaExampleOne {table} {serialize} {{ a = 2, [3] = "b", [true] = "6" }, nil, true} +\ShowLuaExampleOne {table} {serialize} {{ a = 2, [3] = "b", [true] = "6" }, nil, true, true} +\ShowLuaExampleOne {table} {serialize} {{ a = 2, [3] = "b", [true] = "6" }, nil, true, true, true} + +In \CONTEXT\ there is also a \type {tocontext} function that typesets the table +verbose. This is handy for manuals and tracing. + +\stopsummary + +\startsummary[title={identical are_equal}] + +These two function compare two tables that have a similar structure. The \type +{identical} variant operates on a hash while \type {are_equal} assumes an indexed +table. + +\starttyping +local b = table.identical (one, two) +local b = table.are_equal (one, two) +\stoptyping + +\ShowLuaExampleThree {table} {identical} {{ a = { x = 2 } }, { a = { x = 3 } }} +\ShowLuaExampleThree {table} {identical} {{ a = { x = 2 } }, { a = { x = 2 } }} + +\ShowLuaExampleThree {table} {are_equal} {{ a = { x = 2 } }, { a = { x = 3 } }} +\ShowLuaExampleThree {table} {are_equal} {{ a = { x = 2 } }, { a = { x = 2 } }} + +\ShowLuaExampleThree {table} {identical} {{ "one", "two" }, { "one", "two" }} +\ShowLuaExampleThree {table} {identical} {{ "one", "two" }, { "two", "one" }} + +\ShowLuaExampleThree {table} {are_equal} {{ "one", "two" }, { "one", "two" }} +\ShowLuaExampleThree {table} {are_equal} {{ "one", "two" }, { "two", "one" }} + +\stopsummary + +\startsummary[title={tohash fromhash swapped swaphash reversed reverse mirrored}] + +We use \type {tohash} quite a lot in \CONTEXT. It converts a list into a hash so +that we can easily check if (a string) is in a given set. The \type {fromhash} +function does the opposite: it creates a list of keys from a hashed table where +each value that is not \type {false} or \type {nil} is present. + +\starttyping +local hashed = table.tohash (indexed) +local indexed = table.fromhash(hashed) +\stoptyping + +The function \type {swapped} turns keys into values vise versa while the \type +{reversed} and \type {reverse} reverses the values in an indexed table. The last +one reverses the table itself (in|-|place). + +\starttyping +local swapped = table.swapped (indexedtable) +local reversed = table.reversed (indexedtable) +local reverse = table.reverse (indexedtable) +local mirrored = table.mirrored (hashedtable) +\stoptyping + +\ShowLuaExampleTwo {table} {tohash} {{ "a", "b", "c" }} +\ShowLuaExampleTwo {table} {fromhash} {{ a = true, b = false, c = true }} +\ShowLuaExampleTwo {table} {swapped} {{ "a", "b", "c" }} +\ShowLuaExampleTwo {table} {reversed} {{ "a", "b", "c" }} +\ShowLuaExampleTwo {table} {reverse} {{ 1, 2, 3, 4 }} +\ShowLuaExampleTwo {table} {mirrored} {{ a = "x", b = "y", c = "z" }} + +\stopsummary + +\startsummary[title={append prepend}] + +These two functions operate on a pair of indexed tables. The first table gets +appended or prepended by the second. The first table is returned as well. + +\starttyping +table.append (one, two) +table.prepend(one, two) +\stoptyping + +The functions are similar to loops using \type {insert}. + +\ShowLuaExampleTwo {table} {append} {{ "a", "b", "c" }, { "d", "e" }} +\ShowLuaExampleTwo {table} {prepend} {{ "a", "b", "c" }, { "d", "e" }} + +\stopsummary + +\startsummary[title={merge merged imerge imerged}] + +You can merge multiple hashes with \type {merge} and indexed tables with \type +{imerge}. The first table is the target and is returned. + +\starttyping +table.merge (one, two, ...) +table.imerge (one, two, ...) +\stoptyping + +The variants ending with a \type {d} merge the given list of tables and return +the result leaving the first argument untouched. + +\starttyping +local merged = table.merged (one, two, ...) +local merged = table.imerged (one, two, ...) +\stoptyping + +\ShowLuaExampleTwo {table} {merge} {{ a = 1, b = 2, c = 3 }, { d = 1 }, { a = 0 }} +\ShowLuaExampleTwo {table} {imerge} {{ "a", "b", "c" }, { "d", "e" }, { "f", "g" }} + +% \ShowLuaExampleTwo {table} {merged} {{ a = 1, b = 2, c = 3 }, { d = 1 }, { a = 0 }} +% \ShowLuaExampleTwo {table} {imerged} {{ "a", "b", "c" }, { "d", "e" }, { "f", "g" }} + +\stopsummary + +\startsummary[title={copy fastcopy}] + +When copying a table we need to make a real and deep copy. The \type {copy} +function is an adapted version from the \LUA\ wiki. The \type {fastopy} is faster +because it does not check for circular references and does not share tables when +possible. In practice using the fast variant is okay. + +\starttyping +local copy = table.copy (t) +local copy = table.fastcopy(t) +\stoptyping + +\stopsummary + +\startsummary[title={flattened}] + +A nested table can be unnested using \type {flattened}. Normally you will only +use this function if the content is somewhat predictable. Often using one of the +merge functions does a similar job. + +\starttyping +local flattened = table.flatten(t) +\stoptyping + +\ShowLuaExampleTwo {table} {flattened} {{ a = 1, b = 2, { c = 3 }, d = 4}} +\ShowLuaExampleTwo {table} {flattened} {{ 1, 2, { 3, { 4 } }, 5}} +\ShowLuaExampleTwo {table} {flattened} {{ 1, 2, { 3, { 4 } }, 5}, 1} +\ShowLuaExampleTwo {table} {flattened} {{ a = 1, b = 2, { c = 3 }, d = 4}} +\ShowLuaExampleTwo {table} {flattened} {{ 1, 2, { 3, { c = 4 } }, 5}} +\ShowLuaExampleTwo {table} {flattened} {{ 1, 2, { 3, { c = 4 } }, 5}, 1} + +\stopsummary + +\startsummary[title={loweredkeys}] + +The name says it all: this function returns a new table with the keys being lower +case. This is handy in cases where the keys have a change to be inconsistent, as +can be the case when users input keys and values in less controlled ways. + +\starttyping +local normalized = table.loweredkeys { a = "a", A = "b", b = "c" } +\stoptyping + +\ShowLuaExampleTwo {table} {loweredkeys} {{ a = 1, b = 2, C = 3}} + +\stopsummary + +\startsummary[title={contains}] + +This function works with indexed tables. Watch out, when you look for a match, +the number \type {1} is not the same as string \type {"1"}. The function returns +the index or \type {false}. + +\starttyping +if table.contains(t, 5 ) then ... else ... end +if table.contains(t,"5") then ... else ... end +\stoptyping + +\ShowLuaExampleThree {table} {contains} {{ "a", 2, true, "1"}, 1} +\ShowLuaExampleThree {table} {contains} {{ "a", 2, true, "1"}, "1"} + +\stopsummary + +\startsummary[title={unique}] + +When a table (can) contain duplicate entries you can get rid of them by using the +\type {unique} helper: + +\starttyping +local t = table.unique { 1, 2, 3, 4, 3, 2, 5, 6 } +\stoptyping + +\ShowLuaExampleTwo {table} {unique} { { "a", "b", "c", "a", "d" } } + +\stopsummary + +\startsummary[title={count}] + +The name speaks for itself: this function counts the number of entries in the +given table. For an indexed table \type {#t} is faster. + +\starttyping +local n = table.count(t) +\stoptyping + +\ShowLuaExampleThree {table} {count} {{ 1, 2, [4] = 4, a = "a" }} + +\stopsummary + +\startsummary[title={sequenced}] + +Normally, when you trace a table, printing the serialized version is quite +convenient. However, when it concerns a simple table, a more compact variant is: + +\starttyping +print(table.sequenced(t, separator)) +\stoptyping + +% beware: by default sequences has | as separator + +\ShowLuaExampleThree {table} {sequenced} {{ 1, 2, 3, 4}} +\ShowLuaExampleThree {table} {sequenced} {{ 1, 2, [4] = 4, a = "a" }, ", "} + +\stopsummary + +\stopsection + +\startsection[title=Math] + +In addition to the built-in math function we provide: \type {round}, \type {odd}, +\type {even}, \type {div}, \type {mod}, \type {sind}, \type {cosd} and +\type {tand}. + +At the \TEX\ end we have a helper \type {luaexpr} that you can use to do +calculations: + +\startbuffer + \luaexpr{1 + 2.3 * 4.5 + math.pi} = \cldcontext{1 + 2.3 * 4.5 + math.pi} +\stopbuffer + +\typebuffer + +Both calls return the same result, but the first one is normally faster than the +\type {context} command which has quite some overhead. + +\blank \getbuffer \blank + +The \type {\luaexpr} command can also better deal with for instance conditions, +where it returns \type {true} or \type {false}, while \type {\cldcontext} would +interpret the boolean value as a special signal. + +\stopsection + +\startsection[title=Booleans] + +\startsummary[title={tonumber}] + +This function returns the number one or zero. You will seldom need this function. + +\starttyping +local state = boolean.tonumber(str) +\stoptyping + +\ShowLuaExampleThree {boolean} {tonumber} {true} + +\stopsummary + +\startsummary[title={toboolean}] + +When dealing with configuration files or tables a bit flexibility in setting a +state makes sense, if only because in some cases it's better to say \type {yes} +than \type {true}. + +\starttyping +local b = toboolean(str) +local b = toboolean(str,tolerant) +\stoptyping + +When the second argument is true, the strings \type {true}, \type {yes}, \type +{on}, \type {1}, \type {t} and the number \type {1} all turn into \type {true}. +Otherwise only \type {true} is honoured. This function is also defined in the +global namespace. + +\ShowLuaExampleThree {string} {toboolean} {"true"} +\ShowLuaExampleThree {string} {toboolean} {"yes"} +\ShowLuaExampleThree {string} {toboolean} {"yes",true} + +\stopsummary + +\startsummary[title={is_boolean}] + +This function is somewhat similar to the previous one. It interprets the strings +\type {true}, \type {yes}, \type {on} and \type {t} as \type {true} and +\type{false}, \type {no}, \type {off} and \type {f} as \type {false}. Otherwise +\type {nil} is returned, unless a default value is given, in which case that is +returned. + +\starttyping +if is_boolean(str) then ... end +if is_boolean(str,default) then ... end +\stoptyping + +\ShowLuaExampleThree {string} {is_boolean} {"true"} +\ShowLuaExampleThree {string} {is_boolean} {"off"} +\ShowLuaExampleThree {string} {is_boolean} {"crap",true} + +\stopsummary + +\stopsection + +\startsection[title=Strings] + +\LUA\ strings are simply sequences of bytes. Of course in some places special +treatment takes place. For instance \type {\n} expands to one or more characters +representing a newline, depending on the operating system, but normally, as long +as you manipulate strings in the perspective of \LUATEX, you don't need to worry +about such issues too much. As \LUATEX\ is a \UTF-8 engine, strings normally are +in that encoding but again, it does not matter much as \LUA\ is quite agnostic +about the content of strings: it does not care about three characters reflecting +one \UNICODE\ character or not. This means that when you use for instance the +functions discussed here, or use libraries like \type {lpeg} behave as you +expect. + +Versions later than 0.75 are likely to have some basic \UNICODE\ support on board +but we can easily adapt to that. At least till \LUATEX\ version 0.75 we provided +the \type {slunicode} library but users cannot assume that that will be present for +ever. If you want to mess around with \UTF\ string, use the \type {utf} library +instead as that is the one we provide in \MKIV. It presents the stable interface to +whatever \LUA\ itself provides and|/|or what \LUATEX\ offers and|/|or what +is there because \MKIV\ implements it. + +\startsummary[title={[lua] byte char}] + +As long as we're dealing with \ASCII\ characters we can use these two functions to +go from numbers to characters and vise versa. + +\ShowLuaExampleSeven {string} {byte} {"luatex"} +\ShowLuaExampleSeven {string} {byte} {"luatex",1,3} +\ShowLuaExampleSeven {string} {byte} {"luatex",-3,-1} + +\ShowLuaExampleSeven {string} {char} {65} +\ShowLuaExampleSeven {string} {char} {65,66,67} + +\stopsummary + +\startsummary[title={[lua] sub}] + +You cannot directly access a character in a string but you can take any slice you +want using \type {sub}. You need to provide a start position and negative values +will count backwards from the end. + +\starttyping +local slice = string.sub(str,first,last) +\stoptyping + +\ShowLuaExampleThree {string} {sub} {"abcdef",2} +\ShowLuaExampleThree {string} {sub} {"abcdef",2,3} +\ShowLuaExampleThree {string} {sub} {"abcdef",-3,-2} + +\stopsummary + +\startsummary[title={[lua] gsub}] + +There are two ways of analyzing the content of a string. The more modern and +flexible approach is to use \type {lpeg}. The other one uses some functions in +the \type {string} namespace that accept so called patterns for matching. While +\type {lpeg} is more powerfull than regular expressions, the pattern matching is +less powerfull but sometimes faster and also easier to specify. In many cases it +can do the job quite well. + +\starttyping +local new, count = string.gsub(old,pattern,replacement) +\stoptyping + +The replacement can be a function. Often you don't want the number +of matches, and the way to avoid this is either to store the result +in a variable: + +\starttyping +local new = string.gsub(old,"lua","LUA") +print(new) +\stoptyping + +or to use parentheses to signal the interpreter that only one value +is return. + +\starttyping +print((string.gsub(old,"lua","LUA")) +\stoptyping + +Patterns can be more complex so you'd better read the \LUA\ manual if you want to +know more about them. + +\ShowLuaExampleThree {string} {gsub} {"abcdef","b","B"} +\ShowLuaExampleThree {string} {gsub} {"abcdef","[bc]",string.upper} + +An optional fourth argument specifies how often the replacement has to happen + +\ShowLuaExampleThree {string} {gsub} {"textextextex","tex","abc"} +\ShowLuaExampleThree {string} {gsub} {"textextextex","tex","abc",1} +\ShowLuaExampleThree {string} {gsub} {"textextextex","tex","abc",2} + +\stopsummary + +\startsummary[title={[lua] find}] + +The \type {find} function returns the first and last position of the match: + +\starttyping +local first, last = find(str,pattern) +\stoptyping + +If you're only interested if there is a match at all, it's enough to know that +there is a first position. No match returns \type {nil}. So, + +\starttyping +if find("luatex","tex") then ... end +\stoptyping + +works out okay. You can pass an extra argument to \type {find} that indicates the +start position. So you can use this function to loop over all matches: just start +again at the end of the last match. + +A fourth optional argument is a boolean that signals not to interpret the pattern +but use it as|-|is. + +\ShowLuaExampleThree {string} {find} {"abc.def","c\letterpercent.d",1,false} +\ShowLuaExampleThree {string} {find} {"abc.def","c\letterpercent.d",1,true} +\ShowLuaExampleThree {string} {find} {"abc\letterpercent.def","c\letterpercent.d",1,false} +\ShowLuaExampleThree {string} {find} {"abc\letterpercent.def","c\letterpercent.d",1,true} + +\stopsummary + +\startsummary[title={[lua] match gmatch}] + +With \type {match} you can split of bits and pieces of a string. The parenthesis +indicate the captures. + +\starttyping +local a, b, c, ... = string.match(str,pattern) +\stoptyping + +The \type {gmatch} function is used to loop over a string, for instance the +following code prints the elements in a comma separated list, ignoring spaces +after commas. + +\starttyping +for s in string.gmatch(str,"([^,%s])+") do + print(s) +end +\stoptyping + +A more detailed description can be found in the \LUA\ reference manual, so we +only mention the special directives. Characters are grouped in classes: + +\starttabulate[|lT|l|] +\HL +\NC \letterpercent a \NC letters \NC \NR +\NC \letterpercent l \NC lowercase letters \NC \NR +\NC \letterpercent u \NC uppercase letters \NC \NR +\NC \letterpercent d \NC digits \NC \NR +\NC \letterpercent w \NC letters and digits \NC \NR +\NC \letterpercent c \NC control characters \NC \NR +\NC \letterpercent p \NC punctuation \NC \NR +\NC \letterpercent x \NC hexadecimal characters \NC \NR +\NC \letterpercent s \NC space related characters \NC \NR +\HL +\stoptabulate + +You can create sets too: + +\starttabulate[|lT|l|] +\HL +\NC [\letterpercent l\letterpercent d] \NC lowercase letters and digits \NC \NR +\NC [^\letterpercent d\letterpercent p] \NC all characters except digits and punctuation \NC \NR +\NC [p-z] \NC all characters in the range \type {p} upto \type {z} \NC \NR +\NC [pqr] \NC all characters \type {p}, \type {q} and \type {r} \NC \NR +\HL +\stoptabulate + +There are some characters with special meanings: + +\starttabulate[|lT|l|] +\HL +\NC \letterhat \NC the beginning of a string \NC \NR +\NC \letterdollar \NC end of a string \NC \NR +\NC . \NC any character \NC \NR +\NC * \NC zero or more of the preceding specifier, greedy \NC \NR +\NC - \NC zero or more of the preceding specifier, least possible \NC \NR +\NC + \NC one or more of the preceding specifier \NC \NR +\NC ? \NC zero or one of the preceding specifier \NC \NR +\NC ( ) \NC encapsulate capture \NC \NR +\NC \letterpercent b \NC capture all between the following two characters \NC \NR +\HL +\stoptabulate + +You can use whatever you like to be matched: + +\starttabulate[|lT|l|] +\HL +\NC pqr \NC the sequence \type {pqr} \NC \NR +\NC my name is (\letterpercent w) \NC the word following \type {my name is} \NC \NR +\HL +\stoptabulate + +If you want to specify such a token as it is, then you can precede it with a +percent sign, so to get a percent, you need two in a row. + +\ShowLuaExampleThree {string} {match} {"before:after","^(.-):"} +\ShowLuaExampleThree {string} {match} {"before:after","^([^:])"} +\ShowLuaExampleThree {string} {match} {"before:after","bef(.*)ter"} +\ShowLuaExampleThree {string} {match} {"abcdef","[b-e]+"} +\ShowLuaExampleThree {string} {match} {"abcdef","[b-e]*"} +\ShowLuaExampleThree {string} {match} {"abcdef","b-e+"} +\ShowLuaExampleThree {string} {match} {"abcdef","b-e*"} + +\stopsummary + +Such patterns should not be confused with regular expressions, although to some +extent they can do the same. If you really want to do complex matches, you should +look into \LPEG. + +\startsummary[title={[lua] lower upper}] + +These two function spreak for themselves. + +\ShowLuaExampleThree {string} {lower} {"LOW"} +\ShowLuaExampleThree {string} {upper} {"upper"} + +\stopsummary + +\startsummary[title={[lua] format}] + +The \type {format} function takes a template as first argument and one or more +additional arguments depending on the format. The template is similar to the one +used in \CCODE\ but it has some extensions. + +\starttyping +local s = format(format, str, ...) +\stoptyping + +The following table gives an overview of the possible format directives. The +\type {s} is the most probably candidate and can handle numbers well as strings. +Watch how the minus sign influences the alignment. \footnote {There can be +differences between platforms although so far we haven't run into problems. Also, +\LUA\ 5.2 does a bit more checking on correct arguments.} + +\starttabulate[|lB|lT|lT|lT|] +\HL +\NC integer \NC \letterpercent i \NC 12345 \NC \cldcontext{"\letterpercent i", 12345 } \NC \NR +\NC integer \NC \letterpercent d \NC 12345 \NC \cldcontext{"\letterpercent d", 12345 } \NC \NR +\NC unsigned \NC \letterpercent u \NC -12345 \NC \cldcontext{"\letterpercent u", 12345 } \NC \NR +\NC character \NC \letterpercent c \NC 123 \NC \cldcontext{"\letterpercent c", 89 } \NC \NR +\NC hexadecimal \NC \letterpercent x \NC 123 \NC \cldcontext{"\letterpercent x", 123 } \NC \NR +\NC \NC \letterpercent X \NC 123 \NC \cldcontext{"\letterpercent X", 123 } \NC \NR +\NC octal \NC \letterpercent o \NC 12345 \NC \cldcontext{"\letterpercent o", 12345 } \NC \NR +\HL +\NC string \NC \letterpercent s \NC abc \NC \cldcontext{"\letterpercent s", "abcd"} \NC \NR +\NC \NC \letterpercent -8s \NC 123 \NC \cldcontext{"\letterpercent -8s", 123 } \NC \NR +\NC \NC \letterpercent 8s \NC 123 \NC \cldcontext{"\letterpercent 8s", 123 } \NC \NR +\HL +\NC float \NC \letterpercent 0.2f \NC 12.345 \NC \cldcontext{"\letterpercent 0.2f",12.345} \NC \NR +\NC exponential \NC \letterpercent 0.2e \NC 12.345 \NC \cldcontext{"\letterpercent 0.2e",12.345} \NC \NR +\NC \NC \letterpercent 0.2E \NC 12.345 \NC \cldcontext{"\letterpercent 0.2E",12.345} \NC \NR +\NC autofloat \NC \letterpercent 0.2g \NC 12.345 \NC \cldcontext{"\letterpercent 0.2g",12.345} \NC \NR +\NC \NC \letterpercent 0.2G \NC 12.345 \NC \cldcontext{"\letterpercent 0.2G",12.345} \NC \NR +\HL +\stoptabulate + +\startasciimode +\ShowLuaExampleThree {string} {format} {"U+\letterpercent 05X",2010} +\stopasciimode + +\stopsummary + +\startsummary[title={striplines}] + +The \type {striplines} function can strip leading and trailing empty lines, +collapse or delete intermediate empty lines and strips leading and trailing +spaces. We will demonstrate this with string \type {str}: + +\startluacode +local str = table.concat( { +" ", +" aap", +" noot mies", +" ", +" ", +" wim zus jet", +"teun vuur gijs", +" lam kees bok weide", +" ", +"does hok duif schapen ", +" ", +}, "\n") + +document.TempString = str + +function document.ShowStrippedString(str) + str = string.gsub(str," ","\\allowbreak<sp>\\allowbreak ") + str = string.gsub(str,"([\010])","\\allowbreak<lf>\\allowbreak ") + context.startalign { "flushleft,verytolerant" } + context("{\\tttf %s}",str) + context.stopalign() +end + +function document.ShowStrippedBuffer(name,str) + context.tobuffer(name,str) + context.typebuffer( { name }, { numbering = "line" }) + context.resetbuffer { name } +end + +function document.ShowStrippedCommand(option) + context.type( { style = "ttbf" }, [[utilities.strings.striplines(str,"]] .. option .. [[")]]) +end + +context.blank { "big" } +document.ShowStrippedString(str) +document.ShowStrippedBuffer("dummy",str) + +\stopluacode + +The different options for stripping are demonstrated below, We use verbose +descriptions instead of vague boolean flags. + +\startluacode +local str = document.TempString ; document.TempString = nil + +for option in table.sortedhash(utilities.strings.striplinepatterns) do + local s = utilities.strings.striplines(str,option) + context.blank() + document.ShowStrippedCommand(option) + context.blank { "big,samepage" } + document.ShowStrippedString(s) + context.blank { "big,samepage" } + document.ShowStrippedBuffer(option,str) +end +\stopluacode + +You can of course mix usage with the normal \type {context} helper commands, for +instance put them in buffers. Buffers normally will prune leading and trailing +empty lines anyway. + +\starttyping +context.tobuffer("dummy",utilities.strings.striplines(str)) +context.typebuffer( { "dummy" }, { numbering = "line" }) +\stoptyping + +\stopsummary + +\startsummary[title={formatters}] + +The \type {format} function discussed before is the built|-|in. As an alternative +\CONTEXT\ provides an additional formatter that has some extensions. Interesting +is that that one is often more efficient, although there are cases where the +speed is comparable. In addition to the regular \type {format} function we have +the following extra formatting keys: \footnote {As we run out of keys some are +somewhat counter intuitive, like \type {l} for booleans (logical).} + +\start \setuptype[color=] + +\starttabulate[|lB|lT|lT|lT|] +\HL +\NC utf character \NC \letterpercent c \NC 322 \NC \cldcontext{"\letterpercent c",322} \NC \NR +\HL +\NC force tostring \NC \letterpercent S \NC nil \NC \cldcontext{"\letterpercent S",nil} \NC \NR +\NC \NC \letterpercent Q \NC nil \NC \cldcontext{"\letterpercent Q",nil} \NC \NR +\NC \NC \letterpercent N \NC 0123 \NC \cldcontext{"\letterpercent N","0123"} \NC \NR +\HL +\NC signed number \NC \letterpercent I \NC 1234 \NC \cldcontext{"\letterpercent I",1234} \NC \NR +\NC rounded number \NC \letterpercent r \NC 1234.56 \NC \cldcontext{"\letterpercent r",1234.56} \NC \NR +\HL +\NC sparseexp \NC \letterpercent 0.2j \NC 12.345e120 \NC \cldcontext{"\letterpercent 0.2j",12.345e120} \NC \NR +\NC \NC \letterpercent 0.2J \NC 12.345e120 \NC \cldcontext{"\letterpercent 0.2J",12.345e120} \NC \NR +\HL +\NC unicode value 0x \NC \letterpercent h \NC ł 1234 \NC \cldcontext{"\letterpercent v \letterpercent v", "ł",1234} \NC \NR +\NC \NC \letterpercent H \NC ł 1234 \NC \cldcontext{"\letterpercent V \letterpercent V", "ł",1234} \NC \NR +\NC unicode value U+ \NC \letterpercent u \NC ł 1234 \NC \cldcontext{"\letterpercent u \letterpercent u", "ł",1234} \NC \NR +\NC \NC \letterpercent U \NC ł 1234 \NC \cldcontext{"\letterpercent U \letterpercent U", "ł",1234} \NC \NR +\HL +\NC points \NC \letterpercent p \NC 1234567 \NC \cldcontext{"\letterpercent p",1234567} \NC \NR +\NC basepoints \NC \letterpercent b \NC 1234567 \NC \cldcontext{"\letterpercent b",1234567} \NC \NR +\HL +\NC table concat \NC \letterpercent t \NC \arg{1,2,3} \NC \cldcontext{"\letterpercent t",{1,2,3}} \NC \NR +\NC \NC \letterpercent *t \NC \arg{1,2,3} \NC \cldcontext{"\letterpercent *t",{1,2,3}} \NC \NR +\NC \NC \letterpercent \arg{ AND }t \NC \arg{a=1,b=3} \NC \cldcontext{"\letterpercent +{ AND }T",{a=1,b=2}} \NC \NR +\NC table serialize \NC \letterpercent T \NC \arg{1,2,3} \NC \cldcontext{"\letterpercent *t",{1,2,3}} \NC \NR +\NC \NC \letterpercent T \NC \arg{a=1,b=3} \NC \let|\relax\cldcontext{"\letterpercent T",{a=1,b=2}} \NC \NR +\NC \NC \letterpercent +T \NC \arg{a=1,b=3} \NC \cldcontext{"\letterpercent [+T]",{a=1,b=2}} \NC \NR +\HL +\NC boolean (logic) \NC \letterpercent l \NC "a" == "b" \NC \cldcontext{"\letterpercent l","a"=="b"} \NC \NR +\NC \NC \letterpercent L \NC "a" == "b" \NC \cldcontext{"\letterpercent L","a"=="b"} \NC \NR +\HL +\NC whitespace \NC \letterpercent w \NC 3 \NC \obeyspaces\vl\cldcontext{"\letterpercent w",3}\vl \NC \NR +\NC \NC \letterpercent 2w \NC 3 \NC \obeyspaces\vl\cldcontext{"\letterpercent 2w",3}\vl \NC \NR +\NC \NC \letterpercent 4W \NC \NC \obeyspaces\vl\cldcontext{"\letterpercent 4W"}\vl \NC \NR +\HL +\NC skip \NC \letterpercent 2z \NC 1,2,3,4 \NC \obeyspaces\vl\cldcontext{"\letterpercent s\letterpercent 2z\letterpercent s",1,2,3,4}\vl \NC \NR +\HL +\stoptabulate + +\stop + +There is also a generic formatter: \type {a} and \type {A}. This one converts the +argument into a string and deals with strings, number, booleans, tables and +whatever. We mostly use these in tracing. The lowercase variant uses single +quotes, and the uppercase variant uses double quotes. + +There are two more formatters plugged in: \type {!xml!} and \type {!tex!}. These +are best demonstrated with an example: + +\starttyping +local xf = formatter["xml escaped: %!xml!"] +local xr = formatter["tex escaped: %!tex!"] + +print(xf("x > 1 && x < 10")) +print(xt("this will cost me $123.00 at least")) +\stoptyping + +weird, this fails when cld-verbatim is there as part of the big thing: +catcodetable 4 suddenly lacks the comment being a other + +The \type {context} command uses the formatter so one can say: + +\startbuffer +\startluacode +context("first some xml: %!xml!, and now some %!tex!", + "x > 1 && x < 10", "this will cost me $123.00 at least") +\stopluacode +\stopbuffer + +\typebuffer + +This renders as follows: + +\blank \getbuffer \blank + +You can extend the formatter but we advise you not to do that unless you're sure +what you're doing. You never know what \CONTEXT\ itself might add for its own +benefit. + +However, you can define your own formatter and add to that without interference. +In fact, the main formatter is just defined that way. This is how it works: + +\startbuffer[definition] +local MyFormatter = utilities.strings.formatters.new() + +utilities.strings.formatters.add ( + MyFormatter, + "upper", + "global.string.upper(%s)" +) +\stopbuffer + +\typebuffer[definition] + +Now you can use this one as: + +\startbuffer[usage] +context.bold(MyFormatter["It's %s or %!upper!."]("this","that")) +\stopbuffer + +\typebuffer[usage] + +\blank \ctxluabuffer[definition,usage] \blank + +Because we're running inside \CONTEXT, a better definition would be this: + +\startbuffer +local MyFormatter = utilities.strings.formatters.new() + +utilities.strings.formatters.add ( + MyFormatter, + "uc", + "myupper(%s)", + -- "local myupper = global.characters.upper" + { myupper = global.characters.upper } +) + +utilities.strings.formatters.add ( + MyFormatter, + "lc", + "mylower(%s)", + -- "local mylower = global.characters.lower" + { mylower = global.characters.lower } +) + +utilities.strings.formatters.add ( + MyFormatter, + "sh", + "myshaped(%s)", + -- "local myshaped = global.characters.shaped" + { myshaped = global.characters.shaped } +) + +context(MyFormatter["Uppercased: %!uc!"]("ÀÁÂÃÄÅàáâãäå")) +context.par() +context(MyFormatter["Lowercased: %!lc!"]("ÀÁÂÃÄÅàáâãäå")) +context.par() +context(MyFormatter["Reduced: %!sh!"]("ÀÁÂÃÄÅàáâãäå")) +\stopbuffer + +\typebuffer + +The last arguments creates shortcuts. As expected we get: + +\blank \ctxluabuffer \blank + +Of course you can also apply the casing functions directly so in practice you +shouldn't use formatters without need. Among the advantages of using formatters +are: + +\startitemize[packed] +\startitem They provide a level of abstraction. \stopitem +\startitem They can replace multiple calls to \type {\context}. \stopitem +\startitem Sometimes they make source code look better. \stopitem +\startitem Using them is often more efficient and faster. \stopitem +\stopitemize + +The last argument might sound strange but considering the overhead involved in +the \type {context} (related) functions, doing more in one step has benefits. +Also, formatters are implemented quite efficiently, so their overhead can be +neglected. + +In the examples you see that a formatter extension is itself a template. + +\startbuffer +local FakeXML = utilities.strings.formatters.new() + +utilities.strings.formatters.add(FakeXML,"b",[["<" ..%s..">" ]]) +utilities.strings.formatters.add(FakeXML,"e",[["</"..%s..">" ]]) +utilities.strings.formatters.add(FakeXML,"n",[["<" ..%s.."/>"]]) + +context(FakeXML["It looks like %!b!xml%!e! doesn't it?"]("it","it")) +\stopbuffer + +\typebuffer + +This gives: \ctxluabuffer. Of course we could go over the top here: + +\startbuffer +local FakeXML = utilities.strings.formatters.new() + +local stack = { } + +function document.f_b(s) + table.insert(stack,s) + return "<" .. s .. ">" +end + +function document.f_e() + return "</" .. table.remove(stack) .. ">" +end + +utilities.strings.formatters.add(FakeXML,"b",[[global.document.f_b(%s)]]) +utilities.strings.formatters.add(FakeXML,"e",[[global.document.f_e()]]) + +context(FakeXML["It looks like %1!b!xml%0!e! doesn't it?"]("it")) +\stopbuffer + +\typebuffer + +This gives: \ctxluabuffer. Such a template look horrible, although it's not too +far from the regular format syntax: just compare \type {%1f} with \type {%1!e!}. +The zero trick permits us to inject information that we've put on the stack. As +this kind of duplicate usage might occur most, a better solution is available: + +\startbuffer +local FakeXML = utilities.strings.formatters.new() + +utilities.strings.formatters.add(FakeXML,"b",[["<" .. %s .. ">"]]) +utilities.strings.formatters.add(FakeXML,"e",[["</" .. %s .. ">"]]) + +context(FakeXML["It looks like %!b!xml%-1!e! doesn't it?"]("it")) +\stopbuffer + +\typebuffer + +We get: \ctxluabuffer. Anyhow, in most cases you will never feel the need for +such hackery and the regular formatter works fine. Adding this extension +mechanism was rather trivial and it doesn't influence the performance. + +In \CONTEXT\ we have a few more extensions: + +\starttyping +utilities.strings.formatters.add ( + strings.formatters, "unichr", + [["U+" .. format("%%05X",%s) .. " (" .. utfchar(%s) .. ")"]] +) + +utilities.strings.formatters.add ( + strings.formatters, "chruni", + [[utfchar(%s) .. " (U+" .. format("%%05X",%s) .. ")"]] +) +\stoptyping + +This one is used in messages: + +\startbuffer +context("Missing character %!chruni! in font.",234) context.par() +context("Missing character %!unichr! in font.",234) +\stopbuffer + +\typebuffer + +This shows up as: + +\blank \getbuffer \blank + +If you look closely to the definition, you will notice that we use \type {%s} +twice. This is a feature of the definer function: if only one argument is +picked up (which is default) then the replacement format can use that two +times. Because we use a format in the constructor, we need to escape the +percent sign there. + +\stopsummary + +\startsummary[title={strip}] + +This function removes any leading and trailing whitespace characters. + +\starttyping +local s = string.strip(str) +\stoptyping + +\ShowLuaExampleThree {string} {strip} {" lua + tex = luatex "} + +\stopsummary + +\startsummary[title={split splitlines checkedsplit}] + +The line splitter is a special case of the generic splitter. The \type {split} +function can get a string as well an \type {lpeg} pattern. The \type +{checkedsplit} function removes empty substrings. + +\starttyping +local t = string.split (str, pattern) +local t = string.split (str, lpeg) +local t = string.checkedsplit (str, lpeg) +local t = string.splitlines (str) +\stoptyping + +\start \let\ntex\relax % hack + +\ShowLuaExampleTwo {string} {split} {"a, b,c, d", ","} +\ShowLuaExampleTwo {string} {split} {"p.q,r", lpeg.S(",.")} +\ShowLuaExampleTwo {string} {checkedsplit} {";one;;two", ";"} +\ShowLuaExampleTwo {string} {splitlines} {"lua\ntex nic"} + +\stop + +\stopsummary + +\startsummary[title={quoted unquoted}] + +You will hardly need these functions. The \type {quoted} function can normally be +avoided using the \type {format} pattern \type {%q}. The \type {unquoted} +function removes single or double quotes but only when the string starts and ends +with the same quote. + +\starttyping +local q = string.quoted (str) +local u = string.unquoted(str) +\stoptyping + +\ShowLuaExampleThree {string} {quoted} {[[test]]} +\ShowLuaExampleThree {string} {quoted} {[[test"test]]} +\ShowLuaExampleThree {string} {unquoted} {[["test]]} +\ShowLuaExampleThree {string} {unquoted} {[["t\"est"]]} +\ShowLuaExampleThree {string} {unquoted} {[["t\"est"x]]} +\ShowLuaExampleThree {string} {unquoted} {"\'test\'"} + +\stopsummary + +\startsummary[title={count}] + +The function \type {count} returns the number of times that a given pattern +occurs. Beware: if you want to deal with \UTF\ strings, you need the variant that +sits in the \type {lpeg} namespace. + +\starttyping +local n = count(str,pattern) +\stoptyping + +\ShowLuaExampleThree {string} {count} {"test me", "e"} + +\stopsummary + +\startsummary[title={limit}] + +This function can be handy when you need to print messages that can be rather +long. By default, three periods are appended when the string is chopped. + +\starttyping +print(limit(str,max,sentinel) +\stoptyping + +\ShowLuaExampleThree {string} {limit} {"too long", 6} +\ShowLuaExampleThree {string} {limit} {"too long", 6, " (etc)"} + +\stopsummary + +\startsummary[title={is_empty}] + +A string considered empty by this function when its length is zero or when it +only contains spaces. + +\starttyping +if is_empty(str) then ... end +\stoptyping + +\ShowLuaExampleThree {string} {is_empty} {""} +\ShowLuaExampleThree {string} {is_empty} {" "} +\ShowLuaExampleThree {string} {is_empty} {" ? "} + +\stopsummary + +\startsummary[title={escapedpattern topattern}] + +These two functions are rather specialized. They come in handy when you need to +escape a pattern, i.e.\ prefix characters with a special meaning by a \type {%}. + +\starttyping +local e = escapedpattern(str, simple) +local p = topattern (str, lowercase, strict) +\stoptyping + +The simple variant does less escaping (only \type {-.?*} and is for instance used +in wildcard patterns when globbing directories. The \type {topattern} function +always does the simple escape. A strict pattern gets anchored to the beginning +and end. If you want to see what these functions do you can best look at their +implementation. + +\stopsummary + +% strings.tabtospace(str,n) +% strings.striplong + +\stopsection + +\startsection[title=\UTF] + +We used to have the \type {slunicode} library available but as most of it is not +used and because it has a somewhat fuzzy state, we will no longer rely on it. In +fact we only used a few functions in the \type {utf} namespace so as \CONTEXT\ +user you'd better stick to what is presented here. You don't have to worry how +they are implemented. Depending on the version of \LUATEX\ it can be that a +library, a native function, or \LPEG is used. + +\startsummary[title={char byte}] + +As \UTF\ is a multibyte encoding the term char in fact refers to a \LUA\ +string of one upto four 8|-|bit characters. + +\starttyping +local b = utf.byte("å") +local c = utf.char(0xE5) +\stoptyping + +The number of places in \CONTEXT\ where do such conversion is not that large: +it happens mostly in tracing messages. + +\starttyping +logs.report("panic","the character U+%05X is used",utf.byte("æ")) +\stoptyping + +\ShowLuaExampleThree {utf} {byte} {"æ"} +\ShowLuaExampleThree {utf} {char} {0xE6} + +\stopsummary + +\startsummary[title={sub}] + +If you need to take a slice of an \UTF\ encoded string the \type {sub} function +can come in handy. This function takes a string and a range defined by two +numbers. Negative numbers count from the end of the string. + +\ShowLuaExampleThree {utf} {sub} {"123456àáâãäå",1,7} +\ShowLuaExampleThree {utf} {sub} {"123456àáâãäå",0,7} +\ShowLuaExampleThree {utf} {sub} {"123456àáâãäå",0,9} +\ShowLuaExampleThree {utf} {sub} {"123456àáâãäå",4} +\ShowLuaExampleThree {utf} {sub} {"123456àáâãäå",0} +\ShowLuaExampleThree {utf} {sub} {"123456àáâãäå",0,0} +\ShowLuaExampleThree {utf} {sub} {"123456àáâãäå",4,4} +\ShowLuaExampleThree {utf} {sub} {"123456àáâãäå",4,0} +\ShowLuaExampleThree {utf} {sub} {"123456àáâãäå",-3,0} +\ShowLuaExampleThree {utf} {sub} {"123456àáâãäå",0,-3} +\ShowLuaExampleThree {utf} {sub} {"123456àáâãäå",-5,-3} +\ShowLuaExampleThree {utf} {sub} {"123456àáâãäå",-3} + +\stopsummary + +\startsummary[title={len}] + +There are probably not that many people that can instantly see how many bytes the +string in the following example takes: + +\starttyping +local l = utf.len("ÀÁÂÃÄÅàáâãäå") +\stoptyping + +Programming languages use \ASCII\ mostly so there each characters takes one byte. +In \CJK\ scripts however, you end up with much longer sequences. If you ever did +some typesetting of such scripts you have noticed that the number of characters +on a page is less than in the case of a Latin script. As information is coded +in less characters, effectively the source of a Latin or \CJK\ document will not +differ that much. + +\ShowLuaExampleThree {utf} {len} {"ÒÓÔÕÖòóôõö"} + +\stopsummary + +\startsummary[title={values characters}] + +There are two iterators that deal with \UTF. In \LUATEX\ these are extensions to +the \type {string} library but for consistency we've move them to the \type {utf} +namespace. + +The following function loops over the \UTF\ characters in a string and returns +the \UNICODE\ number in \type {u}: + +\starttyping +for u in utf.values(str) do + ... -- u is a number +end +\stoptyping + +The next one returns a string \type {c} that has one or more characters as \UTF\ +characters can have upto 4 bytes. + +\starttyping +for c in utf.characters(str) do + ... -- c is a string +end +\stoptyping + +\stopsummary + +\startsummary[title={ustring xstring tocodes}] + +These functions are mostly useful for logging where we want to see the \UNICODE\ +number. + +\ShowLuaExampleThree {utf} {ustring} {0xE6} +\ShowLuaExampleThree {utf} {ustring} {"ù"} +\ShowLuaExampleThree {utf} {xstring} {0xE6} +\ShowLuaExampleThree {utf} {xstring} {"à"} +\ShowLuaExampleThree {utf} {tocodes} {"ùúü"} +\ShowLuaExampleThree {utf} {tocodes} {"àáä",""} +\ShowLuaExampleThree {utf} {tocodes} {"òóö","+"} + +\stopsummary + +\startsummary[title={split splitlines totable}] + +The \type {split} function splits a sequence of \UTF\ characters into a table +which one character per slot. The \type {splitlines} does the same but each slot +has a line instead. The \type {totable} function is similar to \type {split}, but +the later strips an optionally present \UTF\ bom. + +\ShowLuaExampleThree {utf} {split} {"òóö"} + +\stopsummary + +\startsummary[title={count}] + +This function counts the number of times that a given substring occurs in a +string. The patterns can be a string or an \LPEG\ pattern. + +\ShowLuaExampleThree {utf} {count} {"òóöòóöòóö","ö"} +\ShowLuaExampleThree {utf} {count} {"äáàa",lpeg.P("á") + lpeg.P("à")} + +\stopsummary + +\startsummary[title={remapper replacer substituter}] + +With \type {remapper} you can create a remapping function that remaps a given +string using a (hash) table. + +\starttyping +local remap = utf.remapper { a = 'd', b = "c", c = "b", d = "a" } + +print(remap("abcd 1234 abcd")) +\stoptyping + +A remapper checks each character against the given mapping table. Its cousin +\type {replacer} is more efficient and skips non matches. The \type {substituter} +function only does a quick check first and avoids building a string with no +replacements. That one is much faster when you expect not that many replacements. + +The \type {replacer} and \type {substituter} functions take table as argument +and an indexed as well as hashed one are acceptable. In fact you can even do +things like this: + +\starttyping +local rep = utf.replacer { [lpeg.patterns.digit] = "!" } +\stoptyping + +\stopsummary + +\startsummary[title={is_valid}] + +This function returns false if the argument is no valid \UTF\ string. As \LUATEX\ +is pretty strict with respect to the input, this function is only useful when +dealing with external files. + +\starttyping +function checkfile(filename) + local data = io.loaddata(filename) + if data and data ~= "" and not utf.is_valid(data) then + logs.report("error","file %q contains invalid utf",filename) + end +end +\stoptyping + +\stopsummary + +% not that relevant: +% +% -- utf.filetype +% -- string.toutf + +\stopsection + +\startsection[title=Numbers and bits] + +In the \type {number} namespace we collect some helpers that deal with numbers as +well as bits. Starting with \LUA\ 5.2 a library \type {bit32} is but the language +itself doesn't provide for them via operators: the library uses functions to +manipulate numbers upto 2\high{32}. For advanced bit manipulations you should use +the \type {bit32} library, otherwise it's best to stick to the functions +described here. + +\startsummary[title={hasbit setbit clearbit}] + +As bitsets are numbers you will also use numbers to qualify them. So, if you want to +set bits 1, 4 and 8, you can to that using the following specification: + +\starttyping +local b = 1 + 4 + 8 -- 0x1 + 0x4 + 0x8 +local b = 13 -- or 0xC +\stoptyping + +However, changing one bit by adding a number to an existing doesn't work out that well +if that number already has that bit set. Instead we use: + +\starttyping +local b = number.setbit(b,0x4) +\stoptyping + +In a similar fashion you can turn of a bit: + +\starttyping +local b = number.clearbit(b,0x4) +\stoptyping + +Testing for a bit(set) is done as follows: + +\starttyping +local okay = number.hasbit(b,0x4) +\stoptyping + +\stopsummary + +\startsummary[title={bit}] + +Where the previously mentioned helpers work with numbers representing one or more +bits, it is sometimes handy to work with positions. The \type {bit} function +returns the associated number value. + +\ShowLuaExampleThree {number} {bit} {5} + +\stopsummary + +\startsummary[title={tobitstring}] + +There is no format option to go from number to bits in terms of zeros and ones so +we provide a helper: \type {tobitsting}. + +\ShowLuaExampleThree {number} {tobitstring} {2013} +\ShowLuaExampleThree {number} {tobitstring} {2013,3} +\ShowLuaExampleThree {number} {tobitstring} {2013,1} + +\stopsummary + +\startsummary[title={bits}] + +If you ever want to convert a bitset into a table containing the set bits you can +use this function. + +\ShowLuaExampleTwo {number} {bits} {11} + +\stopsummary + +\startsummary[title={toset}] + +A string or number can be split into digits with \type {toset}. Beware, this +function does not return a function but multiple numbers + +\starttyping +local a, b, c, d = number.toset("1001") +\stoptyping + +The returned values are either numbers or \type {nil} when an valid digit is +seen. + +\ShowLuaExampleSeven {number} {toset} {100101} +\ShowLuaExampleSeven {number} {toset} {"100101"} +\ShowLuaExampleSeven {number} {toset} {"21546"} + +\stopsummary + +\startsummary[title={valid}] + +This function can be used to check or convert a number, for instance in user +interfaces. + +\ShowLuaExampleThree {number} {valid} {12} +\ShowLuaExampleThree {number} {valid} {"34"} +\ShowLuaExampleThree {number} {valid} {"ab",56} + +\stopsummary + +\stopsection + +\startsection[title=\LPEG\ patterns] + +For \LUATEX\ and \CONTEXT\ \MKIV\ the \type {lpeg} library came at the right +moment as we can use it in lots of places. An in|-|depth discussion makes no +sense as it's easier to look into \type {l-lpeg.lua}, so we stick to an overview. +\footnote {If you search the web for \type {lua lpeg} you will end up at the +official documentation and tutorial.} Most functions return an \type {lpeg} +object that can be used in a match. In time critical situations it's more +efficient to use the match on a predefined pattern that to create the pattern new +each time. Patterns are cached so there is no penalty in predefining a pattern. +So, in the following example, the \type {splitter} that splits at the asterisk +will only be created once. + +\starttyping +local splitter_1 = lpeg.splitat("*") +local splitter_2 = lpeg.splitat("*") + +local n, m = lpeg.match(splitter_1,"2*4") +local n, m = lpeg.match(splitter_2,"2*4") +\stoptyping + +\startsummary[title={[lua] match print P R S V C Cc Cs ...}] + +The \type {match} function does the real work. Its first argument is a \type +{lpeg} object that is created using the functions with the short uppercase names. + +\starttyping +local P, R, C, Ct = lpeg.P, lpeg.R, lpeg.C, lpeg.Ct + +local pattern = Ct((P("[") * C(R("az")^0) * P(']') + P(1))^0) + +local words = lpeg.match(pattern,"a [first] and [second] word") +\stoptyping + +In this example the words between square brackets are collected in a table. There +are lots of examples of \type {lpeg} in the \CONTEXT\ code base. + +\stopsummary + +\startsummary[title={anywhere}] + +\starttyping +local p = anywhere(pattern) +\stoptyping + +\ShowLuaExampleTwo {lpeg} {match} {lpeg.Ct((lpeg.anywhere("->")/"!")^0), "oeps->what->more"} + +\stopsummary + +\startsummary[title={splitter splitat firstofsplit secondofsplit}] + +The \type {splitter} function returns a pattern where each match gets an action +applied. The action can be a function, table or string. + +\starttyping +local p = splitter(pattern, action) +\stoptyping + +The \type {splitat} function returns a pattern that will return the split off +parts. Unless the second argument is \type {true} the splitter keeps splitting + +\starttyping +local p = splitat(separator,single) +\stoptyping + +When you need to split off a prefix (for instance in a label) you can use: + +\starttyping +local p = firstofsplit(separator) +local p = secondofsplit(separator) +\stoptyping + +The first function returns the original when there is no match but the second +function returns \type {nil} instead. + +\ShowLuaExampleTwo {lpeg} {match} {lpeg.Ct(lpeg.splitat("->",false)), "oeps->what->more"} +\ShowLuaExampleTwo {lpeg} {match} {lpeg.Ct(lpeg.splitat("->",false)), "oeps"} +\ShowLuaExampleTwo {lpeg} {match} {lpeg.Ct(lpeg.splitat("->",true)), "oeps->what->more"} +\ShowLuaExampleTwo {lpeg} {match} {lpeg.Ct(lpeg.splitat("->",true)), "oeps"} + +\ShowLuaExampleThree {lpeg} {match} {lpeg.firstofsplit(":"), "before:after"} +\ShowLuaExampleThree {lpeg} {match} {lpeg.firstofsplit(":"), "whatever"} +\ShowLuaExampleThree {lpeg} {match} {lpeg.secondofsplit(":"), "before:after"} +\ShowLuaExampleThree {lpeg} {match} {lpeg.secondofsplit(":"), "whatever"} + +\stopsummary + +\startsummary[title={split checkedsplit}] + +The next two functions have counterparts in the \type {string} namespace. They +return a table with the split parts. The second function omits empty parts. + +\starttyping +local t = split (separator,str) +local t = checkedsplit(separator,str) +\stoptyping + +\ShowLuaExampleTwo {lpeg} {split} {",","a,b,c"} +\ShowLuaExampleTwo {lpeg} {split} {",",",a,,b,c,"} +\ShowLuaExampleTwo {lpeg} {checkedsplit} {",",",a,,b,c,"} + +\stopsummary + +\startsummary[title={stripper keeper replacer}] + +These three functions return patterns that manipulate a string. The \type +{replacer} gets a mapping table passed. + +\starttyping +local p = stripper(str or pattern) +local p = keeper (str or pattern) +local p = replacer(mapping) +\stoptyping + +\ShowLuaExampleThree {lpeg} {match} {lpeg.stripper(lpeg.R("az")), "[-a-b-c-d-]"} +\ShowLuaExampleThree {lpeg} {match} {lpeg.stripper("ab"), "[-a-b-c-d-]"} +\ShowLuaExampleThree {lpeg} {match} {lpeg.keeper(lpeg.R("az")), "[-a-b-c-d-]"} +\ShowLuaExampleThree {lpeg} {match} {lpeg.keeper("ab"), "[-a-b-c-d-]"} +\ShowLuaExampleThree {lpeg} {match} {lpeg.replacer{{"a","p"},{"b","q"}}, "[-a-b-c-d-]"} + +\stopsummary + +\startsummary[title={balancer}] + +One of the nice things about \type {lpeg} is that it can handle all kind of +balanced input. So, a function is provided that returns a balancer pattern: + +\starttyping +local p = balancer(left,right) +\stoptyping + +\ShowLuaExampleTwo {lpeg} {match} {lpeg.Ct((lpeg.C(lpeg.balancer("{","}"))+1)^0),"{a} {b{c}}"} +\ShowLuaExampleTwo {lpeg} {match} {lpeg.Ct((lpeg.C(lpeg.balancer("((","]"))+1)^0),"((a] ((b((c]]"} + +\stopsummary + +\startsummary[title={counter}] + +The \type {counter} function returns a function that returns the length of a +given string. The \type {count} function differs from its counterpart living in +the \type {string} namespace in that it deals with \UTF\ and accepts strings as +well as patterns. + +\starttyping +local fnc = counter(lpeg.P("á") + lpeg.P("à")) +local len = fnc("äáàa") +\stoptyping + +\stopsummary + +\startsummary[title={UP US UR}] + +In order to make working with \UTF-8 input somewhat more convenient a few helpers +are provided. + +\starttyping +local p = lpeg.UP(utfstring) +local p = lpeg.US(utfstring) +local p = lpeg.UR(utfpair) +local p = lpeg.UR(first,last) +\stoptyping + +\ShowLuaExampleThree {utf} {count} {"äáàa",lpeg.UP("áà")} +\ShowLuaExampleThree {utf} {count} {"äáàa",lpeg.US("àá")} +\ShowLuaExampleThree {utf} {count} {"äáàa",lpeg.UR("aá")} +\ShowLuaExampleThree {utf} {count} {"äáàa",lpeg.UR("àá")} +\ShowLuaExampleThree {utf} {count} {"äáàa",lpeg.UR(0x0000,0xFFFF)} + +\startsummary[title={patterns}] + +The following patterns are available in the \type {patterns} table in the \type +{lpeg} namespace: + +\startluacode +context.startalignment { "flushleft" } +local done = false +for k, v in table.sortedpairs(lpeg.patterns) do + if done then + context.space() + else + done = true + end + context.type(k) +end +context.stopalignment() +\stopluacode + +There will probably be more of them in the future. + +\stopsummary + +\stopsection + +\startsection[title=IO] + +The \type {io} library is extended with a couple of functions as well and +variables but first we mention a few predefined functions. + +\startsummary[title={[lua] open popen...}] + +The IO library deals with in- and output from the console and +files. + +\starttyping +local f = io.open(filename) +\stoptyping + +When the call succeeds \type {f} is a file object. You close this file +with: + +\starttyping +f:close() +\stoptyping + +Reading from a file is done with \type {f:read(...)} and writing to a file with +\type {f:write(...)}. In order to write to a file, when opening a second argument +has to be given, often \type {wb} for writing (binary) data. Although there are +more efficient ways, you can use the \type {f:lines()} iterator to process a file +line by line. + +You can open a process with \type {io.popen} but dealing with this one depends a +bit on the operating system. + +\stopsummary + +\startsummary[title={fileseparator pathseparator}] + +The value of the following two strings depends on the operating system that is +used. + +\starttyping +io.fileseparator +io.pathseparator +\stoptyping + +\ShowLuaExampleFive {io} {fileseparator} +\ShowLuaExampleFive {io} {pathseparator} + +\stopsummary + +\startsummary[title={loaddata savedata}] + +These two functions save you some programming. The first function loads a whole +file in a string. By default the file is loaded in binary mode, but when the +second argument is \type {true}, some interpretation takes place (for instance +line endings). In practice the second argument can best be left alone. + +\starttyping +io.loaddata(filename,textmode) +\stoptyping + +Saving the data is done with: + +\starttyping +io.savedata(filename,str) +io.savedata(filename,tab,joiner) +\stoptyping + +When a table is given, you can optionally specify a string that +ends up between the elements that make the table. + +\stopsummary + +\startsummary[title={exists size noflines}] + +These three function don't need much comment. + +\starttyping +io.exists(filename) +io.size(filename) +io.noflines(fileobject) +io.noflines(filename) +\stoptyping + +\stopsummary + +\startsummary[title={characters bytes readnumber readstring}] + +When I wrote the icc profile loader, I needed a few helpers for reading strings +of a certain length and numbers of a given width. Both accept five values of +\type {n}: \type {-4}, \type {-2}, \type {1}, \type {2} and \type {4} where the +negative values swap the characters or bytes. + +\starttyping +io.characters(f,n) -- +io.bytes(f,n) +\stoptyping + +The function \type {readnumber} accepts five sizes: \type {1}, \type {2}, \type +{4}, \type {8}, \type {12}. The string function handles any size and strings zero +bytes from the string. + +\starttyping +io.readnumber(f,size) +io.readstring(f,size) +\stoptyping + +Optionally you can give the position where the reading has to start: + +\starttyping +io.readnumber(f,position,size) +io.readstring(f,position,size) +\stoptyping + +\stopsummary + +\startsummary[title={ask}] + +In practice you will probably make your own variant of the following function, +but at least a template is there: + +\starttyping +io.ask(question,default,options) +\stoptyping + +For example: + +\starttyping +local answer = io.ask("choice", "two", { "one", "two" }) +\stoptyping + +\stopsummary + +\stopsection + +\startsection[title=File] + +The file library is one of the larger core libraries that comes with +\CONTEXT. + +\startsummary[title={dirname basename extname nameonly}] + +We start with a few filename manipulators. + +\starttyping +local path = file.dirname(name,default) +local base = file.basename(name) +local suffix = file.extname(name,default) -- or file.suffix +local name = file.nameonly(name) +\stoptyping + +\ShowLuaExampleThree {file} {dirname} {"/data/temp/whatever.cld"} +\ShowLuaExampleThree {file} {dirname} {"c:/data/temp/whatever.cld"} +\ShowLuaExampleThree {file} {basename} {"/data/temp/whatever.cld"} +\ShowLuaExampleThree {file} {extname} {"c:/data/temp/whatever.cld"} +\ShowLuaExampleThree {file} {nameonly} {"/data/temp/whatever.cld"} + +\stopsummary + +\startsummary[title={addsuffix replacesuffix}] + +These functions are used quite often: + +\starttyping +local filename = file.addsuffix(filename, suffix, criterium) +local filename = file.replacesuffix(filename, suffix) +\stoptyping + +The first one adds a suffix unless one is present. When \type {criterium} is +\type {true} no checking is done and the suffix is always appended. The second +function replaces the current suffix or add one when there is none. + +\ShowLuaExampleThree {file} {addsuffix} {"whatever","cld"} +\ShowLuaExampleThree {file} {addsuffix} {"whatever.tex","cld"} +\ShowLuaExampleThree {file} {addsuffix} {"whatever.tex","cld",true} + +\ShowLuaExampleThree {file} {replacesuffix} {"whatever","cld"} +\ShowLuaExampleThree {file} {replacesuffix} {"whatever.tex","cld"} + +\stopsummary + +\startsummary[title={is_writable is_readable}] + +These two test the nature of a file: + +\starttyping +file.is_writable(name) +file.is_readable(name) +\stoptyping + +\stopsummary + +\startsummary[title={splitname join collapsepath}] + +Instead of splitting off individual components you can get them all in one go: + +\starttyping +local drive, path, base, suffix = file.splitname(name) +\stoptyping + +The \type {drive} variable is empty on operating systems other than \MSWINDOWS. +Such components are joined with the function: + +\starttyping +file.join(...) +\stoptyping + +The given snippets are joined using the \type {/} as this is +rather platform independent. Some checking takes place in order +to make sure that nu funny paths result from this. There is +also \type {collapsepath} that does some cleanup on a path +with relative components, like \type {..}. + +\ShowLuaExampleSix {file} {splitname} {"a:/b/c/d.e"} +\ShowLuaExampleThree {file} {join} {"a","b","c.d"} +\ShowLuaExampleThree {file} {collapsepath} {"a/b/../c.d"} +\ShowLuaExampleThree {file} {collapsepath} {"a/b/../c.d",true} + +\stopsummary + +\startsummary[title={splitpath joinpath}] + +By default splitting a execution path specification is done using the operating +system dependant separator, but you can force one as well: + +\starttyping +file.splitpath(str,separator) +\stoptyping + +The reverse operation is done with: + +\starttyping +file.joinpath(tab,separator) +\stoptyping + +Beware: in the following examples the separator is system dependent so +the outcome depends on the platform you run on. + +\ShowLuaExampleTwo {file} {splitpath} {"a:b:c"} +\ShowLuaExampleTwo {file} {splitpath} {"a;b;c"} +\ShowLuaExampleThree {file} {joinpath} {{"a","b","c"}} + +\stopsummary + +\startsummary[title={robustname}] + +In workflows filenames with special characters can be a pain so the following +function replaces characters other than letters, digits, periods, slashes and +hyphens by hyphens. + +\starttyping +file.robustname(str,strict) +\stoptyping + +\ShowLuaExampleThree {file} {robustname} {"We don't like this!"} +\ShowLuaExampleThree {file} {robustname} {"We don't like this!",true} + +\stopsummary + +\startsummary[title={readdata writedata}] + +These two functions are duplicates of functions with the +same name in the \type {io} library. + +\stopsummary + +\startsummary[title={copy}] + +There is not much to comment on this one: + +\starttyping +file.copy(oldname,newname) +\stoptyping + +\stopsummary + +\startsummary[title={is_qualified_path is_rootbased_path}] + +A qualified path has at least one directory component while a rootbased path is +anchored to the root of a filesystem or drive. + +\starttyping +file.is_qualified_path(filename) +file.is_rootbased_path(filename) +\stoptyping + +\ShowLuaExampleThree {file} {is_qualified_path} {"a"} +\ShowLuaExampleThree {file} {is_qualified_path} {"a/b"} +\ShowLuaExampleThree {file} {is_rootbased_path} {"a/b"} +\ShowLuaExampleThree {file} {is_rootbased_path} {"/a/b"} + +\stopsummary + +\stopsection + +\startsection[title=Dir] + +The \type {dir} library uses functions of the \type {lfs} library that is linked +into \LUATEX. + +\startsummary[title={current}] + +This returns the current directory: + +\starttyping +dir.current() +\stoptyping + +\stopsummary + +\startsummary[title={glob globpattern globfiles}] + +% not yet documented: dir.collectpattern(path,patt,recurse,result) -- collects tree + +The \type {glob} function collects files with names that match a given pattern. +The pattern can have wildcards: \type {*} (oen of more characters), \type {?} +(one character) or \type {**} (one or more directories). You can pass the +function a string or a table with strings. Optionally a second argument can be +passed, a table that the results are appended to. + +\starttyping +local files = dir.glob(pattern,target) +local files = dir.glob({pattern,...},target) +\stoptyping + +The target is optional and often you end up with simple calls like: + +\starttyping +local files = dir.glob("*.tex") +\stoptyping + +There is a more extensive version where you start at a path, and applies an +action to each file that matches the pattern. You can either or not force +recursion. + +\starttyping +dir.globpattern(path,patt,recurse,action) +\stoptyping + +The \type {globfiles} function collects matches in a table that is returned at +the end. You can pass an existing table as last argument. The first argument is +the starting path, the second arguments controls analyzing directories and the +third argument has to be a function that gets a name passed and is supposed to +return \type {true} or \type {false}. This function determines what gets +collected. + +\starttyping +dir.globfiles(path,recurse,func,files) +\stoptyping + +\stopsummary + +\startsummary[title={makedirs}] + +With \type {makedirs} you can create the given directory. If more than one +name is given they are concatinated. + +\starttyping +dir.makedirs(name,...) +\stoptyping + +\stopsummary + +\startsummary[title={expandname}] + +This function tries to resolve the given path, including relative paths. + +\starttyping +dir.expandname(str) +\stoptyping + +\ShowLuaExampleThree {dir} {expandname} {"."} + +\stopsummary + +\stopsection + +\startsection[title=URL] + +\startsummary[title={split hashed construct}] + +This is a specialized library. You can split an \type {url} into its components. +An \URL\ is constructed like this: + +\starttyping +foo://example.com:2010/alpha/beta?gamma=delta#epsilon +\stoptyping + +\starttabulate[|T|T|] +\NC scheme \NC foo:// \NC \NR +\NC authority \NC example.com:2010 \NC \NR +\NC path \NC /alpha/beta \NC \NR +\NC query \NC gamma=delta \NC \NR +\NC fragment \NC epsilon \NC \NR +\stoptabulate + +A string is split into a hash table with these keys using the following function: + +\starttyping +url.hashed(str) +\stoptyping + +or in strings with: + +\starttyping +url.split(str) +\stoptyping + +The hash variant is more tolerant than the split. In the hash +there is also a key \type {original} that holds the original \URL\ +and and the boolean \type {noscheme} indicates if there is a +scheme at all. + +The reverse operation is done with: + +\starttyping +url.construct(hash) +\stoptyping + +\startasciimode +\ShowLuaExampleTwo {url} {hashed} {"foo://example.com:2010/alpha/beta?gamma=delta#epsilon"} +\ShowLuaExampleTwo {url} {hashed} {"alpha/beta"} +\ShowLuaExampleTwo {url} {split} {"foo://example.com:2010/alpha/beta?gamma=delta#epsilon"} +\ShowLuaExampleTwo {url} {split} {"alpha/beta"} +\stopasciimode + +\startsummary[title={hasscheme addscheme filename query}] + +There are a couple of helpers and their names speaks for themselves: + +\starttyping +url.hasscheme(str) +url.addscheme(str,scheme) +url.filename(filename) +url.query(str) +\stoptyping + +\ShowLuaExampleThree {url} {hasscheme} {"http://www.pragma-ade.com/cow.png"} +\ShowLuaExampleThree {url} {hasscheme} {"www.pragma-ade.com/cow.png"} +\ShowLuaExampleThree {url} {addscheme} {"www.pragma-ade.com/cow.png","http://"} +\ShowLuaExampleThree {url} {addscheme} {"www.pragma-ade.com/cow.png"} +\ShowLuaExampleThree {url} {filename} {"http://www.pragma-ade.com/cow.png"} +\ShowLuaExampleTwo {url} {query} {"a=b&c=d"} + +\stopsection + +\startsection[title=OS] + +\startsummary[title={[lua luatex] env setenv getenv}] + +In \CONTEXT\ normally you will use the resolver functions to deal with the +environment and files. However, a more low level interface is still available. +You can query and set environment variables with two functions. In addition there +is the \type {env} table as interface to the environment. This threesome replaces +the built in functions. + +\starttyping +os.setenv(key,value) +os.getenv(key) +os.env[key] +\stoptyping + +\stopsummary + +\startsummary[title={[lua] execute}] + +There are several functions for running programs. One comes directly from \LUA, +the otheres come with \LUATEX. All of them are are overloaded in \CONTEXT\ in +order to get more control. + +\starttyping +os.execute(...) +\stoptyping + +\stopsummary + +\startsummary[title={[luatex] spawn exec}] + +Two other runners are: + +\starttyping +os.spawn(...) +os.exec (...) +\stoptyping + +The \type {exec} variant will transfer control from the current process to the +new one and not return to the current job. There is a more detailed explanation +in the \LUATEX\ manual. + +\stopsummary + +\startsummary[title={resultof launch}] + +The following function runs the command and returns the result as string. +Multiple lines are combined. + +\starttyping +os.resultof(command) +\stoptyping + +The next one launches a file assuming that the operating system knows +what application to use. + +\starttyping +os.launch(str) +\stoptyping + +\stopsummary + +\startsummary[title={type name platform libsuffix binsuffix}] + +There are a couple of strings that reflect the current machinery: \type {type} +returns either \type {windows} or \type {unix}. The variable \type {name} is more +detailed: \type {windows}, \type {msdos}, \type {linux}, \type {macosx}, etc. If +you also want the architecture you can consult \type {platform}. + +\starttyping +local t = os.type +local n = os.name +local p = os.platform +\stoptyping + +These three variables as well as the next two are used internally and normally +they are not needed in your applications as most functions that matter are aware +of what platform specific things they have to deal with. + +\starttyping +local s = os.libsuffix +local b = os.binsuffix +\stoptyping + +These are string, not functions. + +\ShowLuaExampleFive {os} {type} +\ShowLuaExampleFive {os} {name} +\ShowLuaExampleFive {os} {platform} +\ShowLuaExampleFive {os} {libsuffix} +\ShowLuaExampleFive {os} {binsuffix} + +\stopsummary + +\startsummary[title={[lua] time}] + +The built in time function returns a number. The accuracy is +implementation dependent and not that large. + +\ShowLuaExampleThree {os} {time} {} + +\stopsummary + +\startsummary[title={[luatex] times gettimeofday}] + +Although \LUA\ has a built in type {os.time} function, we normally will use the +one provided by \LUATEX\ as it is more precise: + +\starttyping +os.gettimeofday() +\stoptyping + +There is also a more extensive variant: + +\starttyping +os.times() +\stoptyping + +This one is platform dependent and returns a table with \type {utime} (use time), +\type {stime} (system time), \type {cutime} (children user time), and \type +{cstime} (children system time). + +\stopsummary + +\ShowLuaExampleThree {os} {gettimeofday} {} +\ShowLuaExampleTwo {os} {times} {} + +\startsummary[title={runtime}] + +More interesting is: + +\starttyping +os.runtime() +\stoptyping + +which returns the time spent in the application so far. + +\ShowLuaExampleThree {os} {runtime} {} + +Sometimes you need to add the timezone to a verbose time and the following +function does that for you. + +\starttyping +os.timezone(delta) +\stoptyping + +\ShowLuaExampleThree {os} {timezone} {} +\ShowLuaExampleThree {os} {timezone} {1} +\ShowLuaExampleThree {os} {timezone} {-1} + +\stopsummary + +\startsummary[title={uuid}] + +A version 4 UUID can be generated with: + +\starttyping +os.uuid() +\stoptyping + +The generator is good enough for our purpose. + +\ShowLuaExampleThree {os} {uuid} {} + +\stopsummary + +\stopsection + +\stopchapter + +\stopcomponent diff --git a/doc/context/sources/general/manuals/cld/cld-macros.tex b/doc/context/sources/general/manuals/cld/cld-macros.tex new file mode 100644 index 000000000..de677e2c1 --- /dev/null +++ b/doc/context/sources/general/manuals/cld/cld-macros.tex @@ -0,0 +1,168 @@ +% language=uk + +\startcomponent cld-macros + +\environment cld-environment + +\startchapter[title=Macros] + +\startsection[title={Introduction}] + +You can skip this chapter if you're not interested in defining macros or are +quite content with defining them in \TEX. It's just an example of possible future +interface definitions and it's not the fastest mechanism around. + +\stopsection + +\startsection[title={Parameters}] + +Right from the start \CONTEXT\ came with several user interfaces. As a +consequence you need to take this into account when you write code that is +supposed to work with interfaces other than the English one. The \TEX\ command: + +\starttyping +\setupsomething[key=value] +\stoptyping + +and the \LUA\ call: + +\starttyping +context.setupsomething { key = value } +\stoptyping + +are equivalent. However, all keys at the \TEX\ end eventually become English, but +the values are unchanged. This means that when you code in \LUA\ you should use +English keys and when dealing with assigned values later on, you need to +translate them of compare with translations (which is easier). This is why in the +\CONTEXT\ code you will see: + +\starttyping +if somevalue == interfaces.variables.yes then + ... +end +\stoptyping + +instead of: + +\starttyping +if somevalue == "yes" then + ... +end +\stoptyping + +\stopsection + +\startsection[title={User interfacing}] + +Unless this is somehow inhibited, users can write their own macros and this is +done in the \TEX\ language. Passing data to macros is possible and looks like +this: + +\starttyping +\def\test#1#2{.. #1 .. #2 .. } \test{a}{b} +\def\test[#1]#2{.. #1 .. #2 .. } \test[a]{b} +\stoptyping + +Here \type {#1} and \type {#2} represent an argument and there can be at most 9 +of them. The \type{[]} are delimiters and you can delimit in many ways so the +following is also right: + +\starttyping +\def\test(#1><#2){.. #1 .. #2 .. } \test(a><b) +\stoptyping + +Macro packages might provide helper macros that for instance take care of +optional arguments, so that we can use calls like: + +\starttyping +\test[1,2,3][a=1,b=2,c=3]{whatever} +\stoptyping + +and alike. If you are familiar with the \CONTEXT\ syntax you know that we use +this syntax all over the place. + +If you want to write a macro that calls out to \LUA\ and handles things at that +end, you might want to avoid defining the macro itself and this is possible. + +\startbuffer +\startluacode +function test(opt_1, opt_2, arg_1) + context.startnarrower() + context("options 1: %s",interfaces.tolist(opt_1)) + context.par() + context("options 2: %s",interfaces.tolist(opt_2)) + context.par() + context("argument 1: %s",arg_1) + context.stopnarrower() +end + +interfaces.definecommand { + name = "test", + arguments = { + { "option", "list" }, + { "option", "hash" }, + { "content", "string" }, + }, + macro = test, +} +\stopluacode + +test: \test[1][a=3]{whatever} +\stopbuffer + +An example of a definition and usage at the \LUA\ end is: + +\typebuffer + +The call gives: + +\startpacked +\getbuffer +\stoppacked + +\startbuffer +\startluacode +local function startmore(opt_1) + context.startnarrower() + context("start more, options: %s",interfaces.tolist(opt_1)) + context.startnarrower() +end + +local function stopmore(opt_1) + context.stopnarrower() + context("stop more, options: %s",interfaces.tolist(opt_1)) + context.stopnarrower() +end + +interfaces.definecommand ( "more", { + environment = true, + arguments = { + { "option", "list" }, + }, + starter = startmore, + stopper = stopmore, +} ) +\stopluacode + +more: \startmore[1] one \startmore[2] two \stopmore one \stopmore +\stopbuffer + +If you want to to define an environment (i.e.\ a \type {start}||\type {stop} +pair, it looks as follows: + +\typebuffer + +This gives: + +\startpacked +\getbuffer +\stoppacked + +The arguments are know in both \type {startmore} and \type {stopmore} and nesting +is handled automatically. + +\stopsection + +\stopchapter + +\stopcomponent diff --git a/doc/context/sources/general/manuals/cld/cld-mkiv.tex b/doc/context/sources/general/manuals/cld/cld-mkiv.tex new file mode 100644 index 000000000..5c35fa4e7 --- /dev/null +++ b/doc/context/sources/general/manuals/cld/cld-mkiv.tex @@ -0,0 +1,91 @@ +% language=uk + +% author : Hans Hagen +% copyright : PRAGMA ADE & ConTeXt Development Team +% license : Creative Commons Attribution ShareAlike 4.0 International +% reference : pragma-ade.nl | contextgarden.net | texlive (related) distributions +% origin : the ConTeXt distribution +% +% comment : Because this manual is distributed with TeX distributions it comes with a rather +% liberal license. We try to adapt these documents to upgrades in the (sub)systems +% that they describe. Using parts of the content otherwise can therefore conflict +% with existing functionality and we cannot be held responsible for that. Many of +% the manuals contain characteristic graphics and personal notes or examples that +% make no sense when used out-of-context. +% +% comment : Some chapters might have been published in TugBoat, the NTG Maps, the ConTeXt +% Group journal or otherwise. Thanks to the editors for corrections. Also thanks +% to users for testing, feedback and corrections. + +% \disabledirectives[paragraphs.normalize.global] +% \disabledirectives[paragraphs.normalize.local] + +% \usemodule[s-lan-03] +% \ctxlua{languages.words.tracers.showwords()} % no run check yet +% \page +% \setupspellchecking[state=start,method=2] + +% \enabletrackers[structures.export.spaces] +% \enabletrackers[structures.export.showtree] + +% \enabletrackers[export.trace] +% \enabletrackers[export.trace.spacing] +% \enabletrackers[export.lessstate] +% \enabletrackers[export.comment] + +% \enablemode[export] + +\startmode[export] + + \setupbackend + [export=yes] + + \setupexport + [hyphen=yes, + width=60em] + +\stopmode + +\setupinteraction + [title=Context Lua Documents, + %subtitle=preliminary version, + author=Hans Hagen] + +\startproduct cld-mkiv + +\environment cld-environment + +\component cld-titlepage + +\startfrontmatter + \component cld-contents + \component cld-introduction +\stopfrontmatter + +\startbodymatter + \component cld-abitoflua + \component cld-gettingstarted + \component cld-moreonfunctions + \component cld-afewdetails + \component cld-somemoreexamples + \component cld-graphics + \component cld-macros + \component cld-verbatim + \component cld-logging + \component cld-luafunctions + \component cld-ctxfunctions + \component cld-callbacks + \component cld-backendcode + \component cld-goodies + \component cld-nicetoknow + %\component cld-xml + \component cld-summary + \component cld-specialcommands + \component cld-files +\stopbodymatter + +% \startbackmatter +% \component cld-index +% \stopbackmatter + +\stopproduct diff --git a/doc/context/sources/general/manuals/cld/cld-moreonfunctions.tex b/doc/context/sources/general/manuals/cld/cld-moreonfunctions.tex new file mode 100644 index 000000000..fab22515e --- /dev/null +++ b/doc/context/sources/general/manuals/cld/cld-moreonfunctions.tex @@ -0,0 +1,354 @@ +% language=uk + +\startcomponent cld-moreonfunctions + +\environment cld-environment + +\startchapter[title=More on functions] + +\startsection[title=Why we need them] + +\index{functions} + +In a previous chapter we introduced functions as arguments. At first sight this +feature looks strange but you need to keep in mind that a call to a \type +{context} function has no direct consequences. It generates \TEX\ code that is +executed after the current \LUA\ chunk ends and control is passed back to \TEX. +Take the following code: + +\startbuffer +context.framed( { + frame = "on", + offset = "5mm", + align = "middle" + }, + context.input("knuth") +) +\stopbuffer + +\typebuffer + +We call the function \type {framed} but before the function body is executed, the +arguments get evaluated. This means that \type {input} gets processed before +\type {framed} gets done. As a result there is no second argument to \type +{framed} and no content gets passed: an error is reported. This is why we need +the indirect call: + +\startbuffer +context.framed( { + frame = "on", + align = "middle" + }, + function() context.input("knuth") end +) +\stopbuffer + +\typebuffer + +This way we get what we want: + +\startlinecorrection +\ctxluabuffer +\stoplinecorrection + +The function is delayed till the \type {framed} command is executed. If your +applications use such calls a lot, you can of course encapsulate this ugliness: + +\starttyping +mycommands = mycommands or { } + +function mycommands.framed_input(filename) + context.framed( { + frame = "on", + align = "middle" + }, + function() context.input(filename) end +end + +mycommands.framed_input("knuth") +\stoptyping + +Of course you can nest function calls: + +\starttyping +context.placefigure( + "caption", + function() + context.framed( { + frame = "on", + align = "middle" + }, + function() context.input("knuth") end + ) + end +) +\stoptyping + +Or you can use a more indirect method: + +\starttyping +function text() + context.framed( { + frame = "on", + align = "middle" + }, + function() context.input("knuth") end + ) +end + +context.placefigure( + "none", + function() text() end +) +\stoptyping + +You can develop your own style and libraries just like you do with regular \LUA\ +code. Browsing the already written code can give you some ideas. + +\stopsection + +\startsection[title=How we can avoid them] + +\index{delaying} +\index{nesting} + +As many nested functions can obscure the code rather quickly, there is an +alternative. In the following examples we use \type {test}: + +\startbuffer +\def\test#1{[#1]} +\stopbuffer + +\typebuffer \getbuffer + +\startbuffer +context.test("test 1 ",context("test 2a")," test 3") +\stopbuffer + +\typebuffer + +This gives: \ctxluabuffer. As you can see, the second argument is executed before +the encapsulating call to \type {test}. So, we should have packed it into a +function but here is an alternative: + +\startbuffer +context.test("test 1 ",context.delayed("test 2a")," test 3") +\stopbuffer + +\typebuffer + +Now we get: \ctxluabuffer. We can also delay functions themselves, +look at this: + +\startbuffer +context.test("test 1 ",context.delayed.test("test 2b")," test 3") +\stopbuffer + +\typebuffer + +The result is: \ctxluabuffer. This feature also conveniently permits the use of +temporary variables, as in: + +\starttyping +local f = context.delayed.test("test 2c") +context("before ",f," after") +\stoptyping + +Of course you can limit the amount of keystrokes even more by +creating a shortcut: + +\starttyping +local delayed = context.delayed + +context.test("test 1 ",delayed.test("test 2")," test 3") +context.test("test 4 ",delayed.test("test 5")," test 6") +\stoptyping + +So, if you want you can produce rather readable code and readability of code is +one of the reasons why \LUA\ was chosen in the first place. This is a good +example of why coding in \TEX\ makes sense as it looks more intuitive: + +\starttyping +\test{test 1 \test{test 2} test 3} +\test{test 4 \test{test 5} test 6} +\stoptyping + +There is also another mechanism available. In the next example the second +argument is actually a string. + +\starttyping +local nested = context.nested + +context.test("test 8",nested.test("test 9"),"test 10") +\stoptyping + +There is a pitfall here: a nested context command needs to be flushed explicitly, +so in the case of: + +\starttyping +context.nested.test("test 9") +\stoptyping + +a string is created but nothing ends up at the \TEX\ end. Flushing is up to you. +Beware: \type {nested} only works with the regular \CONTEXT\ catcode regime. + +\stopsection + +\startsection[title=Trial typesetting] + +\index {prerolls} +\index {trial typesetting} + +Some typesetting mechanisms demand a preroll. For instance, when determining the +most optimal way to analyse and therefore typeset a table, it is necessary to +typeset the content of cells first. Inside \CONTEXT\ there is a state tagged +\quote {trial typesetting} which signals other mechanisms that for instance +counters should not be incremented more than once. + +Normally you don't need to worry about these issues, but when writing the code +that implements the \LUA\ interface to \CONTEXT, it definitely had to be taken +into account as we either or not can free cached (nested) functions. + +You can influence this caching to some extend. If you say + +\starttyping +function() + context("whatever") +end +\stoptyping + +the function will be removed from the cache when \CONTEXT\ is not in the trial +typesetting state. You can prevent removal of a function by returning \type +{true}, as in: + +\starttyping +function() + context("whatever") + return true +end +\stoptyping + +Whenever you run into a situation that you don't get the outcome that you expect, +you can consider returning \type {true}. However, keep in mind that it will take +more memory, something that only matters on big runs. You can force flushing the +whole cache by: + +\starttyping +context.restart() +\stoptyping + +An example of an occasion where you need to keep the function available is in +repeated content, for instance in headers and footers. + +\starttyping +context.setupheadertexts { + function() + context.pagenumber() + return true + end +} +\stoptyping + +Of course it is not needed when you use the following method: + +\starttyping +context.pagenumber("pagenumber") +\stoptyping + +Because here \CONTEXT\ itself deals with the content driven by the keyword \type +{pagenumber}. + +\stopsection + +\startsection[title=Steppers] + +The \type {context} commands are accumulated within a \type {\ctxlua} call and +only after the call is finished, control is back at the \TEX\ end. Sometimes you +want (in your \LUA\ code) to go on and pretend that you jump out to \TEX\ for a +moment, but come back to where you left. The stepper mechanism permits this. + +A not so practical but nevertheless illustrative example is the following: + +\startbuffer +\startluacode + context.stepwise (function() + context.startitemize() + context.startitem() + context.step("BEFORE 1") + context.stopitem() + context.step("\\setbox0\\hbox{!!!!}") + context.startitem() + context.step("%p",tex.getbox(0).width) + context.stopitem() + context.startitem() + context.step("BEFORE 2") + context.stopitem() + context.step("\\setbox2\\hbox{????}") + context.startitem() + context.step("%p",tex.getbox(2).width) + context.startitem() + context.step("BEFORE 3") + context.stopitem() + context.startitem() + context.step("\\copy0\\copy2") + context.stopitem() + context.startitem() + context.step("BEFORE 4") + context.startitemize() + context.stepwise (function() + context.step("\\bgroup") + context.step("\\setbox0\\hbox{>>>>}") + context.startitem() + context.step("%p",tex.getbox(0).width) + context.stopitem() + context.step("\\setbox2\\hbox{<<<<}") + context.startitem() + context.step("%p",tex.getbox(2).width) + context.stopitem() + context.startitem() + context.step("\\copy0\\copy2") + context.stopitem() + context.startitem() + context.step("\\copy0\\copy2") + context.stopitem() + context.step("\\egroup") + end) + context.stopitemize() + context.stopitem() + context.startitem() + context.step("AFTER 1\\par") + context.stopitem() + context.startitem() + context.step("\\copy0\\copy2\\par") + context.stopitem() + context.startitem() + context.step("\\copy0\\copy2\\par") + context.stopitem() + context.startitem() + context.step("AFTER 2\\par") + context.stopitem() + context.startitem() + context.step("\\copy0\\copy2\\par") + context.stopitem() + context.startitem() + context.step("\\copy0\\copy2\\par") + context.stopitem() + context.stopitemize() +end) +\stopluacode +\stopbuffer + +\typebuffer + +This gives an (ugly) itemize with a nested one: + +\getbuffer + +As you can see in the code, the \type {step} call accepts multiple arguments, but +when more than one argument is given the first one is treated as a formatter. + +\stopsection + +\stopchapter + +\stopcomponent diff --git a/doc/context/sources/general/manuals/cld/cld-nicetoknow.tex b/doc/context/sources/general/manuals/cld/cld-nicetoknow.tex new file mode 100644 index 000000000..fcc0aa26b --- /dev/null +++ b/doc/context/sources/general/manuals/cld/cld-nicetoknow.tex @@ -0,0 +1,163 @@ +% language=uk + +\startcomponent cld-nicetoknow + +\environment cld-environment + +\startchapter[title=Nice to know] + +\startsection[title=Introduction] + +As we like to abstract interfaces it is no surprise that \CONTEXT\ and +therefore it's \LUA\ libraries come with all kind of helpers. In this +chapter I will explain a few of them. Feel free to remind of adding more +here. + +\stopsection + +\startsection[title=Templates] + +{\em Eventually we will move this to the utilities section.} + +When dealing with data from tables or when order matters it can be handy +to abstract the actual data from the way it is dealt with. For this we +provide a template mechanism. The following example demonstrate its use. + +\startbuffer +require("util-ran") -- needed for this example + +local preamble = [[|l|l|c|]] +local template = [[\NC %initials% \NC %surname% \NC %length% \NC \NR]] + +context.starttabulate { preamble } + for i=1,10 do + local row = utilities.templates.replace(template, { + surname = utilities.randomizers.surname(5,10), + initials = utilities.randomizers.initials(1,3), + length = string.format("%0.2f",math.random(140,195)), + }) + context(row) + end +context.stoptabulate() +\stopbuffer + +\typebuffer + +This renders a table with random entries: + +\ctxluabuffer + +The nice thing is that when we change the order of the columns, we don't need to +change the table builder. + +\starttyping +local preamble = [[|c|l|l|]] +local template = [[\NC %length% \NC %initials% \NC %surname% \NC \NR]] +\stoptyping + +The \type {replace} function takes a few more arguments. There are also a some +more replacement options. + +\starttyping +replace("test '%[x]%' test",{ x = [[a 'x' a]] })) +replace("test '%[x]%' test",{ x = true })) +replace("test '%[x]%' test",{ x = [[a 'x' a]], y = "oeps" },'sql')) +replace("test '%[x]%' test",{ x = [[a '%y%' a]], y = "oeps" },'sql',true)) +replace([[test %[x]% test]],{ x = [[a "x" a]]})) +replace([[test %(x)% test]],{ x = [[a "x" a]]})) +\stoptyping + +The first argument is the template and the second one a table with mappings from +keys to values. The third argument can be used to inform the replace mechanism +what string escaping has to happen. The last argument triggers recursive +replacement. The above calls result in the following strings: + +\starttyping +test 'a 'x' \127 a' test +test 'true' test +test 'a ''x'' a' test +test 'a ''oeps'' a' test +test a \"x\" \127 a test +test "a \"x\" \127 a" test +\stoptyping + +These examples demonstrate that by adding a pair of square brackets we get +escaped strings. When using parenthesis the quotes get added automatically. This +is somewhat faster in case when \LUA\ is the target, but in practice it is not +that noticeable. + +% replace(str,mapping,how,recurse) + +\stopsection + +\startsection [title=Extending] + +Instead of extending tex endlessly we can also define our own extensions. Here +is an example. When you want to manipulate a box at the \LUA\ end you have the +problem that the following will not always work out well: + +\starttyping +local b = tex.getbox(0) +-- mess around with b +tex.setbox(0,b) +\stoptyping + +So we end up with: + +\starttyping +local b = node.copy_list(tex.getbox(0)) +-- mess around with b +tex.setbox(0,b) +\stoptyping + +The reason is that at the \TEX\ end grouping plays a role which means that values +are saved and restored. However, there is a save way out by defining a function +that cheats a bit: + +\starttyping +function tex.takebox(id) + local box = tex.getbox(id) + if box then + local copy = node.copy(box) + local list = box.list + copy.list = list + box.list = nil + tex.setbox(id,nil) + return copy + end +end +\stoptyping + +Now we can say: + +\starttyping +local b = tex.takebox(0) +-- mess around with b +tex.setbox(b) +\stoptyping + +In this case we first get the box content and then let \TEX\ do some housekeeping. +But, because we only keep the list node (which we copied) in the register the +overhead of copying a whole list is gone. + +\stopsection + +% require("util-sto") require("char-def") require("char-ini") + +% local myformatter = utilities.strings.formatters.new() + +% string.addformatter("upper", [[upper (%s)]],[[local upper = characters.upper ]]) -- maybe handy +% string.addformatter("lower", [[lower (%s)]],[[local lower = characters.lower ]]) -- maybe handy +% string.addformatter("shaped", [[shaped(%s)]],[[local shaped = characters.shaped]]) -- maybe handy + +% utilities.strings.formatters.add("upper", [[lpegmatch(p_toupper,%s)]],[[local p_toupper = lpeg.patterns.toupper]]) -- maybe handy +% utilities.strings.formatters.add("lower", [[lpegmatch(p_tolower,%s)]],[[local p_tolower = lpeg.patterns.tolower]]) -- maybe handy +% utilities.strings.formatters.add("shaped", [[lpegmatch(p_toshape,%s)]],[[local p_toshape = lpeg.patterns.toshape]]) -- maybe handy + +% print("\n>>>",string.formatters["Is this %s handy or not?"](characters.upper("ÀÁÂÃÄÅàáâãäå"))) +% print("\n>>>",string.formatters["Is this %!upper! handy or not?"]("ÀÁÂÃÄÅàáâãäå")) +% print("\n>>>",string.formatters["Is this %!shaped! handy or not?"]("ÀÁÂÃÄÅàáâãäå")) + +\stopchapter + +\stopcomponent diff --git a/doc/context/sources/general/manuals/cld/cld-somemoreexamples.tex b/doc/context/sources/general/manuals/cld/cld-somemoreexamples.tex new file mode 100644 index 000000000..a282be4e9 --- /dev/null +++ b/doc/context/sources/general/manuals/cld/cld-somemoreexamples.tex @@ -0,0 +1,753 @@ +% language=uk + +\startcomponent cld-somemoreexamples + +\environment cld-environment + +\usemodule[morse] + +\startchapter[title=Some more examples] + +\startsection[title=Appetizer] + +Before we give some more examples, we will have a look at the way the title page +is made. This way you get an idea what more is coming. + +\typefile {cld-mkiv-simple-titlepage.cld} + +This does not look that bad, does it? Of course in pure \TEX\ code it looks +mostly the same but loops and calculations feel a bit more natural in \LUA\ then +in \TEX. The result is shown in \in {figure} [fig:cover]. The actual cover page +was derived from this. + +\startplacefigure[location=here,reference=fig:cover,title={The simplified cover page.}] + \doiffileexistselse {cld-mkiv-simple-titlepage.pdf} { + \externalfigure + [cld-mkiv-simple-titlepage.pdf] + [height=.5\textheight] + } { + \scale + [height=.5\textheight] + {\cldprocessfile{cld-mkiv-simple-titlepage.cld}} + } +\stopplacefigure + +\stopsection + +\startsection[title=A few examples] + +As it makes most sense to use the \LUA\ interface for generated text, here is +another example with a loop: + +\startbuffer +context.startitemize { "a", "packed", "two" } + for i=1,10 do + context.startitem() + context("this is item %i",i) + context.stopitem() + end +context.stopitemize() +\stopbuffer + +\typebuffer + +\ctxluabuffer + +Just as you can mix \TEX\ with \XML\ and \METAPOST, you can define bits and +pieces of a document in \LUA. Tables are good candidates: + +\startbuffer +local one = { + align = "middle", + style = "type", +} +local two = { + align = "middle", + style = "type", + background = "color", + backgroundcolor = "darkblue", + foregroundcolor = "white", +} +local random = math.random +context.bTABLE { framecolor = "darkblue" } + for i=1,10 do + context.bTR() + for i=1,20 do + local r = random(99) + context.bTD(r < 50 and one or two) + context("%2i",r) + context.eTD() + end + context.eTR() + end +context.eTABLE() +\stopbuffer + +\typebuffer + +\placetable[top][tab:random]{A table generated by \LUA.}{\ctxluabuffer} + +Here we see a function call to \type {context} in the most indented line. The +first argument is a format that makes sure that we get two digits and the random +number is substituted into this format. The result is shown in +\in{table}[tab:random]. The line correction is ignored when we use this table as +a float, otherwise it assures proper vertical spacing around the table. Watch how +we define the tables \type {one} and \type {two} beforehand. This saves 198 +redundant table constructions. + +Not all code will look as simple as this. Consider the following: + +\starttyping +context.placefigure( + "caption", + function() context.externalfigure( { "cow.pdf" } ) end +) +\stoptyping + +Here we pass an argument wrapped in a function. If we would not do that, the +external figure would end up wrong, as arguments to functions are evaluated +before the function that gets them (we already showed some alternative approaches +in previous chapters). A function argument is treated as special and in this case +the external figure ends up right. Here is another example: + +\startbuffer +context.placefigure("Two cows!",function() + context.bTABLE() + context.bTR() + context.bTD() + context.externalfigure( + { "cow.pdf" }, + { width = "3cm", height = "3cm" } + ) + context.eTD() + context.bTD { align = "{lohi,middle}" } + context("and") + context.eTD() + context.bTD() + context.externalfigure( + { "cow.pdf" }, + { width = "4cm", height = "3cm" } + ) + context.eTD() + context.eTR() + context.eTABLE() +end) +\stopbuffer + +\typebuffer + +In this case the figure is not an argument so it gets flushed sequentially +with the rest. + +\ctxluabuffer + +\stopsection + +\startsection[title=Styles] + +Say that you want to typeset a word in a bold font. You can do +that this way: + +\starttyping +context("This is ") +context.bold("important") +context("!") +\stoptyping + +Now imagine that you want this important word to be in red too. As we have +a nested command, we end up with a nested call: + +\starttyping +context("This is ") +context.bold(function() context.color( { "red" }, "important") end) +context("!") +\stoptyping + +or + +\starttyping +context("This is ") +context.bold(context.delayed.color( { "red" }, "important")) +context("!") +\stoptyping + +In that case it's good to know that there is a command that combines both +features: + +\starttyping +context("This is ") +context.style( { style = "bold", color = "red" }, "important") +context("!") +\stoptyping + +But that is still not convenient when we have to do that often. So, you can wrap +the style switch in a function. + +\starttyping +local function mycommands.important(str) + context.style( { style = "bold", color = "red" }, str ) +end + +context("This is ") +mycommands.important( "important") +context(", and ") +mycommands.important( "this") +context(" too !") +\stoptyping + +Or you can setup a named style: + +\starttyping +context.setupstyle( { "important" }, { style = "bold", color = "red" } ) + +context("This is ") +context.style( { "important" }, "important") +context(", and ") +context.style( { "important" }, "this") +context(" too !") +\stoptyping + +Or even define one: + +\starttyping +context.definestyle( { "important" }, { style = "bold", color = "red" } ) + +context("This is ") +context.important("important") +context(", and ") +context.important("this") +context(" too !") +\stoptyping + +This last solution is especially handy for more complex cases: + +\startbuffer +context.definestyle( { "important" }, { style = "bold", color = "red" } ) + +context("This is ") +context.startimportant() +context.inframed("important") +context.stopimportant() +context(", and ") +context.important("this") +context(" too !") +\stopbuffer + +\typebuffer + +\ctxluabuffer + +\stopsection + +\startsection[title=A complete example] + +One day my 6 year old niece Lorien was at the office and wanted to know what I +was doing. As I knew she was practicing arithmetic at school I wrote a quick and +dirty script to generate sheets with exercises. The most impressive part was that +the answers were included. It was a rather braindead bit of \LUA, written in a +few minutes, but the weeks after I ended up running it a few more times, for her +and her friends, every time a bit more difficult and also using different +arithmetic. It was that script that made me decide to extend the basic cld manual +into this more extensive document. + +We generate three columns of exercises. Each exercise is a row in a table. The +last argument to the function determines if answers are shown. + +\starttyping +local random = math.random + +local function ForLorien(n,maxa,maxb,answers) + context.startcolumns { n = 3 } + context.starttabulate { "|r|c|r|c|r|" } + for i=1,n do + local sign = random(0,1) > 0.5 + local a, b = random(1,maxa or 99), random(1,max or maxb or 99) + if b > a and not sign then a, b = b, a end + context.NC() + context(a) + context.NC() + context.mathematics(sign and "+" or "-") + context.NC() + context(b) + context.NC() + context("=") + context.NC() + context(answers and (sign and a+b or a-b)) + context.NC() + context.NR() + end + context.stoptabulate() + context.stopcolumns() + context.page() +end +\stoptyping + +This is a typical example of where it's more convenient to write the code in +\LUA\ that in \TEX's macro language. As a consequence setting up the page also +happens in \LUA: + +\starttyping +context.setupbodyfont { + "palatino", + "14pt" +} + +context.setuplayout { + backspace = "2cm", + topspace = "2cm", + header = "1cm", + footer = "0cm", + height = "middle", + width = "middle", +} +\stoptyping + +This leave us to generate the document. There is a pitfall here: we need to use +the same random number for the exercises and the answers, so we freeze and +defrost it. Functions in the \type {commands} namespace implement functionality +that is used at the \TEX\ end but better can be done in \LUA\ than in \TEX\ macro +code. Of course these functions can also be used at the \LUA\ end. + +\starttyping +context.starttext() + + local n = 120 + + commands.freezerandomseed() + + ForLorien(n,10,10) + ForLorien(n,20,20) + ForLorien(n,30,30) + ForLorien(n,40,40) + ForLorien(n,50,50) + + commands.defrostrandomseed() + + ForLorien(n,10,10,true) + ForLorien(n,20,20,true) + ForLorien(n,30,30,true) + ForLorien(n,40,40,true) + ForLorien(n,50,50,true) + +context.stoptext() +\stoptyping + +\placefigure + [here] + [fig:lorien] + {Lorien's challenge.} + {\startcombination + {\externalfigure[cld-005.pdf][page=1,width=.45\textwidth,frame=on]} {exercises} + {\externalfigure[cld-005.pdf][page=6,width=.45\textwidth,frame=on]} {answers} + \stopcombination} + +A few pages of the result are shown in \in {figure} [fig:lorien]. In the +\CONTEXT\ distribution a more advanced version can be found in \type +{s-edu-01.cld} as I was also asked to generate multiplication and table +exercises. In the process I had to make sure that there were no duplicates on a +page as she complained that was not good. There a set of sheets is generated +with: + +\starttyping +moduledata.educational.arithematic.generate { + name = "Bram Otten", + fontsize = "12pt", + columns = 2, + run = { + { method = "bin_add_and_subtract", maxa = 8, maxb = 8 }, + { method = "bin_add_and_subtract", maxa = 16, maxb = 16 }, + { method = "bin_add_and_subtract", maxa = 32, maxb = 32 }, + { method = "bin_add_and_subtract", maxa = 64, maxb = 64 }, + { method = "bin_add_and_subtract", maxa = 128, maxb = 128 }, + }, +} +\stoptyping + +\stopsection + +\startsection[title=Interfacing] + +The fact that we can define functionality using \LUA\ code does not mean that we +should abandon the \TEX\ interface. As an example of this we use a relatively +simple module for typesetting morse code.\footnote {The real module is a bit +larger and can format verbose morse.} First we create a proper namespace: + +\starttyping + +moduledata.morse = moduledata.morse or { } +local morse = moduledata.morse +\stoptyping + +We will use a few helpers and create shortcuts for them. The first helper loops +over each \UTF\ character in a string. The other two helpers map a character onto +an uppercase (because morse only deals with uppercase) or onto an similar shaped +character (because morse only has a limited character set). + +\starttyping +local utfcharacters = string.utfcharacters +local ucchars, shchars = characters.ucchars, characters.shchars +\stoptyping + +The morse codes are stored in a table. + +\starttyping +local codes = { + + ["A"] = "·—", ["B"] = "—···", + ["C"] = "—·—·", ["D"] = "—··", + ["E"] = "·", ["F"] = "··—·", + ["G"] = "——·", ["H"] = "····", + ["I"] = "··", ["J"] = "·———", + ["K"] = "—·—", ["L"] = "·—··", + ["M"] = "——", ["N"] = "—·", + ["O"] = "———", ["P"] = "·——·", + ["Q"] = "——·—", ["R"] = "·—·", + ["S"] = "···", ["T"] = "—", + ["U"] = "··—", ["V"] = "···—", + ["W"] = "·——", ["X"] = "—··—", + ["Y"] = "—·——", ["Z"] = "——··", + + ["0"] = "—————", ["1"] = "·————", + ["2"] = "··———", ["3"] = "···——", + ["4"] = "····—", ["5"] = "·····", + ["6"] = "—····", ["7"] = "——···", + ["8"] = "———··", ["9"] = "————·", + + ["."] = "·—·—·—", [","] = "——··——", + [":"] = "———···", [";"] = "—·—·—", + ["?"] = "··——··", ["!"] = "—·—·——", + ["-"] = "—····—", ["/"] = "—··—· ", + ["("] = "—·——·", [")"] = "—·——·—", + ["="] = "—···—", ["@"] = "·——·—·", + ["'"] = "·————·", ['"'] = "·—··—·", + + ["À"] = "·——·—", + ["Å"] = "·——·—", + ["Ä"] = "·—·—", + ["Æ"] = "·—·—", + ["Ç"] = "—·—··", + ["É"] = "··—··", + ["È"] = "·—··—", + ["Ñ"] = "——·——", + ["Ö"] = "———·", + ["Ø"] = "———·", + ["Ü"] = "··——", + ["ß"] = "··· ···", + +} + +morse.codes = codes +\stoptyping + +As you can see, there are a few non \ASCII\ characters supported as well. There +will never be full \UNICODE\ support simply because morse is sort of obsolete. +Also, in order to support \UNICODE\ one could as well use the bits of \UTF\ +characters, although \unknown\ memorizing the whole \UNICODE\ table is not much +fun. + +We associate a metatable index function with this mapping. That way we can not +only conveniently deal with the casing, but also provide a fallback based on the +shape. Once found, we store the representation so that only one lookup is needed +per character. + +\starttyping +local function resolvemorse(t,k) + if k then + local u = ucchars[k] + local v = rawget(t,u) or rawget(t,shchars[u]) or false + t[k] = v + return v + else + return false + end +end + +setmetatable(codes, { __index = resolvemorse }) +\stoptyping + +Next comes some rendering code. As we can best do rendering at the \TEX\ end we +just use macros. + +\starttyping +local MorseBetweenWords = context.MorseBetweenWords +local MorseBetweenCharacters = context.MorseBetweenCharacters +local MorseLong = context.MorseLong +local MorseShort = context.MorseShort +local MorseSpace = context.MorseSpace +local MorseUnknown = context.MorseUnknown +\stoptyping + +The main function is not that complex. We need to keep track of spaces and +newlines. We have a nested loop because a fallback to shape can result in +multiple characters. + +\starttyping +function morse.tomorse(str) + local inmorse = false + for s in utfcharacters(str) do + local m = codes[s] + if m then + if inmorse then + MorseBetweenWords() + else + inmorse = true + end + local done = false + for m in utfcharacters(m) do + if done then + MorseBetweenCharacters() + else + done = true + end + if m == "·" then + MorseShort() + elseif m == "—" then + MorseLong() + elseif m == " " then + MorseBetweenCharacters() + end + end + inmorse = true + elseif s == "\n" or s == " " then + MorseSpace() + inmorse = false + else + if inmorse then + MorseBetweenWords() + else + inmorse = true + end + MorseUnknown(s) + end + end +end +\stoptyping + +We use this function in two additional functions. One typesets a file, the other +a table of available codes. + +\starttyping +function morse.filetomorse(name,verbose) + morse.tomorse(resolvers.loadtexfile(name),verbose) +end + +function morse.showtable() + context.starttabulate { "|l|l|" } + for k, v in table.sortedpairs(codes) do + context.NC() context(k) + context.NC() morse.tomorse(v,true) + context.NC() context.NR() + end + context.stoptabulate() +end +\stoptyping + +We're done with the \LUA\ code that we can either put in an external file or put +in the module file. The \TEX\ file has two parts. The typesetting macros that we +use at the \LUA\ end are defined first. These can be overloaded. + +\starttyping +\def\MorseShort + {\dontleavehmode + \vrule + width \MorseWidth + height \MorseHeight + depth \zeropoint + \relax} + +\def\MorseLong + {\dontleavehmode + \vrule + width 3\dimexpr\MorseWidth + height \MorseHeight + depth \zeropoint + \relax} + +\def\MorseBetweenCharacters + {\kern\MorseWidth} + +\def\MorseBetweenWords + {\hskip3\dimexpr\MorseWidth\relax} + +\def\MorseSpace + {\hskip7\dimexpr\MorseWidth\relax} + +\def\MorseUnknown#1 + {[\detokenize{#1}]} +\stoptyping + +The dimensions are stored in macros as well. Of course we could provide a proper +setup command, but it hardly makes sense. + +\starttyping +\def\MorseWidth {0.4em} +\def\MorseHeight{0.2em} +\stoptyping + +Finally we have arrived at the macros that interface to the \LUA\ functions. + +\starttyping +\def\MorseString#1{\ctxlua{moduledata.morse.tomorse(\!!bs#1\!!es)}} +\def\MorseFile #1{\ctxlua{moduledata.morse.filetomorse("#1")}} +\def\MorseTable {\ctxlua{moduledata.morse.showtable()}} +\stoptyping + +\startbuffer +\Morse{A more advanced solution would be to convert a node list. That +way we can deal with weird input.} +\stopbuffer + +A string is converted to morse with the first command. + +\typebuffer + +This shows up as: + +\startalignment[flushleft,tolerant]\getbuffer\stopalignment + +Reduction and uppercasing is demonstrated in the next example: + +\startbuffer +\MorseString{ÀÁÂÃÄÅàáâãäå} +\stopbuffer + +\typebuffer + +This gives: + +\startalignment[flushleft,tolerant]\getbuffer\stopalignment + +\stopsection + +\startsection[title=Using helpers] + +The next example shows a bit of \LPEG. On top of the standard functionality +a few additional functions are provided. Let's start with a pure \TEX\ +example: + +\startbuffer +\defineframed + [colored] + [foregroundcolor=red, + foregroundstyle=\underbar, + offset=.1ex, + location=low] +\stopbuffer + +\typebuffer \getbuffer + +\startbuffer +\processisolatedwords {\input ward \relax} \colored +\stopbuffer + +\typebuffer \blank \getbuffer \blank + +Because this processor macro operates at the \TEX\ end it has some limitations. +The content is collected in a very narrow box and from that a regular paragraph +is constructed. It is for this reason that no color is applied: the snippets that +end up in the box are already typeset. + +An alternative is to delegate the task to \LUA: + +\startbuffer +\startluacode +local function process(data) + + local words = lpeg.split(lpeg.patterns.spacer,data or "") + + for i=1,#words do + if i == 1 then + context.dontleavehmode() + else + context.space() + end + context.colored(words[i]) + end + +end + +process(io.loaddata(resolvers.findfile("ward.tex"))) +\stopluacode +\stopbuffer + +\typebuffer \blank \getbuffer \blank + +The function splits the loaded data into a table with individual words. We use a +splitter that splits on spacing tokens. The special case for \type {i = 1} makes +sure that we end up in horizontal mode (read: properly start a paragraph). This +time we do get color because the typesetting is done directly. Here is an +alternative implementation: + +\starttyping +local done = false + +local function reset() + done = false + return true +end + +local function apply(s) + if done then + context.space() + else + done = true + context.dontleavehmode() + end + context.colored(s) +end + +local splitter = lpeg.P(reset) + * lpeg.splitter(lpeg.patterns.spacer,apply) + +local function process(data) + lpeg.match(splitter,data) +end +\stoptyping + +This version is more efficient as it does not create an intermediate table. The +next one is comaprable: + +\starttyping +local function apply(s) + context.colored("%s ",s) +end + +local splitter lpeg.splitter(lpeg.patterns.spacer,apply) + +local function process(data) + context.dontleavevmode() + lpeg.match(splitter,data) + context.removeunwantedspaces() +end +\stoptyping + +\stopsection + +\startsection[title=Formatters] + +Sometimes can save a bit of work by using formatters. By default, the \type {context} +command, when called directly, applies a given formatter. But when called as table +this feature is lost because then we want to process non|-|strings as well. The next +example shows a way out: + +\startbuffer +context("the current emwidth is %p",\number\emwidth) +context.par() +context.formatted("the current emwidth is %p",\number\emwidth) +context.par() +context.bold(string.formatters["the current emwidth is %p"](\number\emwidth)) +context.par() +context.formatted.bold("the current emwidth is %p",\number\emwidth) +\stopbuffer + +The last one is the most interesting one here: in the subnamespace \type +{formatted} (watch the \type {d}) a format specification with extra arguments is +expected. + +\ctxluabuffer + +\stopsection + +\stopchapter + +\stopcomponent diff --git a/doc/context/sources/general/manuals/cld/cld-specialcommands.tex b/doc/context/sources/general/manuals/cld/cld-specialcommands.tex new file mode 100644 index 000000000..37e891019 --- /dev/null +++ b/doc/context/sources/general/manuals/cld/cld-specialcommands.tex @@ -0,0 +1,46 @@ +% language=uk + +\startcomponent cld-specialcommands + +\environment cld-environment + +\startchapter[title=Special commands] + +\index{tracing} + +There are a few functions in the \type {context} namespace that are no +macros at the \TEX\ end. + +\starttyping +context.runfile("somefile.cld") +\stoptyping + +Another useful command is: + +\starttyping +context.settracing(true) +\stoptyping + +There are a few tracing options that you can set at the \TEX\ end: + +\starttyping +\enabletrackers[context.files] +\enabletrackers[context.trace] +\stoptyping + +A few macros have special functions at the \LUA\ end. One of them is \type +{\char}. The function makes sure that the characters ends up right. The same is +true for \type {\chardef}. So, you don't need to mess around with \type {\relax} +or trailing spaces as you would do at the \TEX\ end in order to tell the scanner +to stop looking ahead. + +\starttyping +context.char(123) +\stoptyping + +Other examples of macros that have optimized functions are \type {\par}, +\type{\bgroup} and \type {\egroup}. + +\stopchapter + +\stopcomponent diff --git a/doc/context/sources/general/manuals/cld/cld-summary.tex b/doc/context/sources/general/manuals/cld/cld-summary.tex new file mode 100644 index 000000000..2b62597fa --- /dev/null +++ b/doc/context/sources/general/manuals/cld/cld-summary.tex @@ -0,0 +1,841 @@ +% language=uk + +\startcomponent cld-summary + +\environment cld-environment + +\usemodule[s][characters-properties] + +\startchapter[title=A sort of summary] + +In this chapter we summarize the functionality provided by the \type {context} +namespace. We repeat some of what has been explained in other chapter so that in +fact you can start with this summary. + +If you have read this manual (or seen code) you know that you can access all the +core commands using this namespace: + +\starttyping +context.somecommand("some argument") +context["somecommand"]("some argument") +\stoptyping + +These calls will eventually expand \type {\somecommand} with the given argument. +This interface has been around form the start and has proven to be quite flexible +and robust. In spite of what you might think, the \type {somecommand} is not +really defined in the \type {context} namespace, but in its own one called \type +{core}, accessible via \type {context.core}. + +Next we describe the commands that are naturally defined in the \type {context} +namespace. Some have counterparts at the macro level (like \type {bgroup}) but +many haven't (for instance \type {rule}). We tried not to polute the \type +{context} namespace too much but although we could have put the helpers in a +separate namespace it would make usage a bit more unnatural. + +\startsection[title=Access to commands] + +\startsummary[title={context(".. some text ..")}] + +The string is flushed as|-|is: + +\starttyping +.. some text .. +\stoptyping + +\stopsummary + +\startsummary[title={context("format",...)}] + +The first string is a format specification according that is passed to the \LUA\ +function \type {format} in the \type {string} namespace. Following arguments are +passed too. + +\stopsummary + +\startsummary[title={context(123,...)}] + +The numbers (and following numbers or strings) are flushed without any +formatting. + +\starttyping +123... (concatenated) +\stoptyping + +\stopsummary + +\startsummary[title={context(true)}] + +An explicit \type {endlinechar} is inserted, in \TEX\ speak: + +\starttyping +^^M +\stoptyping + +\stopsummary + +\startsummary[title={context(false,...)}] + +Strings and numbers are flushed surrounded by curly braces, an indexed table is +flushed as option list, and a hashed table is flushed as parameter set. + +\starttyping +multiple {...} or [...] etc +\stoptyping + +\stopsummary + +\startsummary[title={context(node)}] + +The node (or list of nodes) is injected at the spot. Keep in mind that you need +to do the proper memory management yourself. + +\stopsummary + +\startsummary[title={context["command"] context.core["command"]}] + +The function that implements \type {\command}. The \type{core} table is where +these functions realy live. + +\stopsummary + +\startsummary[title={context["command"](value,...)}] + +The value (string or number) is flushed as a curly braced (regular) argument. + +\starttyping +\command {value}... +\stoptyping + +\stopsummary + +\startsummary[title={context["command"]({ value },...)}] + +The table is flushed as value set. This can be an identifier, +a list of options, or a directive. + +\starttyping +\command [value]... +\stoptyping + +\stopsummary + +\startsummary[title={context["command"]({ key = val },...)}] + +The table is flushed as key|/|value set. + +\starttyping +\command [key={value}]... +\stoptyping + +\stopsummary + +\startsummary[title={context["command"](true)}] + +An explicit \type {endlinechar} is inserted. + +\starttyping +\command ^^M +\stoptyping + +\stopsummary + +\startsummary[title={context["command"](node)}] + +The node(list) is injected at the spot. Keep in mind that you need to do the +proper memory management yourself. + +\starttyping +\command {node(list)} +\stoptyping + +\stopsummary + +\startsummary[title={context["command"](false,value)}] + +The value is flushed without encapsulating tokens. + +\starttyping +\command value +\stoptyping + +\stopsummary + +\startsummary[title={context["command"]({ value }, { key = val }, val, false, val)}] + +The arguments are flushed accordingly their nature and the order can be any. + +\starttyping +\command [value][key={value}]{value}value +\stoptyping + +\stopsummary + +\startsummary[title={context.direct(...)}] + +The arguments are interpreted the same as if \type {direct} was a command, but no +\type {\direct} is injected in front. Braces are added: + +\startbuffer +regular \expandafter \bold \ctxlua{context.direct("bold")} regular +black \expandafter \color \ctxlua{context.direct({"red"})}{red} black +black \expandafter \color \ctxlua{context.direct({"green"},"green")} black +\stopbuffer + +\typebuffer + +The \type {\expandafter} makes sure that the \type {\bold} and \type {\color} +macros see the following \type{{bold}}, \type {[red]}, and \type {[green]{green}} +arguments. + +\startlines\getbuffer\stoplines + +\stopsummary + +\startsummary[title={context.delayed(...)}] + +The arguments are interpreted the same as in a \type {context} call, but instead +of a direct flush, the arguments will be flushed in a next cycle. + +\stopsummary + +\startsummary[title={context.delayed["command"](...)}] + +The arguments are interpreted the same as in a \type {command} call, but instead +of a direct flush, the command and arguments will be flushed in a next cycle. + +\stopsummary + +\startsummary[title={context.nested["command"]}] + +This command returns the command, including given arguments as a string. No +flushing takes place. + +\stopsummary + +\startsummary[title={context.nested}] + +This command returns the arguments as a string and treats them the same as a +regular \type {context} call. + +\stopsummary + +\startsummary[title={context.formatted["command"]([<regime>,]<format>,<arguments>)}] + +This command returns the command that will pass it's arguments to the string +formatter. When the first argument is a number, then it is interpreted as a +catcode regime. + +\stopsummary + +\startsummary[title={context.formatted([<regime>,]<format>,<arguments>)}] + +This command passes it's arguments to the string formatter. When the first +argument is a number, then it is interpreted as a catcode regime. + +\stopsummary + +\stopsection + +\startsection[title=\METAFUN] + +\startsummary[title={context.metafun.start()}] + +This starts a \METAFUN\ (or \METAPOST) graphic. + +\stopsummary + +\startsummary[title={context.metafun.stop()}] + +This finishes and flushes a \METAFUN\ (or \METAPOST) graphic. + +\stopsummary + +\startsummary[title={context.metafun("format",...)}] + +The argument is appended to the current graphic data but the string formatter is +used on following arguments. + +\stopsummary + +\startsummary[title={context.metafun.delayed}] + +This namespace does the same as \type {context.delayed}: it wraps the code in such +a way that it can be used in a function call. + +\stopsummary + +\startsection[title=Building blocks] + +\startsummary[title={context.bgroup() context.egroup()}] + +These are just \type {\bgroup} and \type {\egroup} equivalents and as these are +in fact shortcuts to the curly braced we output these instead. + +\stopsummary + +\startsummary[title={context.space()}] + +This one directly maps onto \type {\space}. + +\stopsummary + +\startsummary[title={context.par()}] + +This one directly maps onto \type {\par}. + +\stopsummary + +\stopsection + +\startsection[title=Basic Helpers] + +\startsummary[title={context.rule(wd,ht,dp,direction) context.rule(specification)}] + +A rule node is injected with the given properties. A specification is just a +table with the four fields. The rule gets the current attributes. + +\stopsummary + +\startsummary[title={context.glyph(fontid,n) context.glyph(n)}] + +A glyph node is injected with the given font id. When no id is given, the current font +is used. The glyph gets the current attributes. + +\stopsummary + +\startsummary[title={context.char(n) context.char(str) context.char(tab)}] + +This will inject one or more copies of \type {\char} calls. You can pass a +number, a string representing a number, or a table with numbers. + +\stopsummary + +\startsummary[title={context.utfchar(n) context.utfchar(str)}] + +This injects is \UTF\ character (one or more bytes). You can pass a number +or a string representing a numbers. You need to be aware of special +characters in \TEX, like \type {#}. + +\stopsummary + +\stopsection + +\startsection[title={Registers}] + +This is a table that hosts a couple of functions. The following \type {new} +ones are available: + +\starttyping +local n = newdimen (name) +local n = newskip (name) +local n = newcount (name) +local n = newmuskip(name) +local n = newtoks (name) +local n = newbox (name) +\stoptyping + +These define a register with name \type {name} at the \LUA\ end and \type {\name} +at the \TEX\ end. The registers' number is returned. The next function is like +\type {\chardef}: it defines \type {\name} with value \type {n}. + +\starttyping +local n = newchar(name,n) +\stoptyping + +It's not likely that you will use any of these commands, if only because when +you're operating from the \LUA\ end using \LUA\ variables is more convenient. + +\stopsection + +\startsection[title=Catcodes] + +Normally we operate under the so called \type {context} catcode regime. This +means that content gets piped to \TEX\ using the same meanings for characters as +you normally use in \CONTEXT. So, a \type {$} starts math. In \in {table} +[tab:catcodes] we show the catcode regimes. + +\startplacetable[location=page,title={Catcode regimes},reference=tab:catcodes] + \showcharactercatcodes +\stopplacetable + +\startsummary[title={context.catcodes}] + +The \type {context.catcodes} tables contains the internal numbers of the +catcode tables used. The next table shows the names that can be used. + +\starttabulate[|lT|cT|lT|] +\BC name \BC mnemonic \BC \TEX\ command \NC \NR +\NC context \NC ctx \NC ctxcatcodes \NC \NR +\NC protect \NC prt \NC prtcatcodes \NC \NR +\NC plain \NC tex \NC texcatcodes \NC \NR +\NC text \NC txt \NC txtcatcodes \NC \NR +\NC verbatim \NC vrb \NC vrbcatcodes \NC \NR +\stoptabulate + +\stopsummary + +\startsummary[title={context.newindexer(catcodeindex)}] + +This function defines a new indexer. You can think of the context command itself +as an indexer. There are two (extra) predefined indexers: + +\starttyping +context.verbatim = context.newindexer(context.catcodes.verbatim) +context.puretext = context.newindexer(context.catcodes.text) +\stoptyping + +\stopsummary + +\startsummary[title={context.pushcatcodes(n) context.popcatcodes()}] + +These commands switch to another catcode regime and back. They have to be used +in pairs. Only the regimes atthe \LUA\ end are set. + +\stopsummary + +\startsummary[title={context.unprotect() context.protect()}] + +These commands switch to the protected regime and back. They have to be used in +pairs. Beware: contrary to what its name suggests, the \type {unprotect} enables +the protected regime. These functions also issue an \type {\unprotect} and \type +{\protect} equivalent at the \TEX\ end. + +\stopsummary + +\startsummary[title={context.verbatim context.puretext}] + +The differences between these are subtle: + +\startbuffer +\startluacode + context.verbatim.bold("Why do we use $ for math?") context.par() + context.verbatim.bold("Why do we use { as start?") context.par() + context.verbatim.bold("Why do we use } as end?") context.par() + context.puretext.bold("Why do we use {\\bi $} at all?") +\stopluacode +\stopbuffer + +\typebuffer + +Verbatim makes all characters letters while pure text leaves the backslash and +curly braces special. + +\startpacked \getbuffer \stoppacked + +\stopsummary + +\startsummary[title={context.protected}] + +The protected namespace is only used for commands that are in the \CONTEXT\ +private namespace. + +\stopsummary + +\startsummary[title={context.escaped(str) context.escape(str)}] + +The first command pipes the escaped string to \TEX, while the second one just +returns an unescaped string. The characters \typ {# $ % \ \ { }} are escaped. + +\stopsummary + +\startsummary[title={context.startcollecting() context.stopcollecting()}] + +These two commands will turn flushing to \TEX\ into collecting. This can be handy +when you want to interface commands that grab arguments using delimiters and as +such they are used deep down in some table related interfacing. You probably +don't need them. + +\stopsummary + +\stopsection + +\startsection[title={Templates}] + +In addition to the regular template mechanism (part of the utilities) there is a +dedicated template feature in the \type {context} namespace. An example demonstrates +its working: + +\startbuffer +\startluacode + local MyTable = [[ + \bTABLE + \bTR + \bTD \bf %one_first% \eTD + \bTD %[one_second]% \eTD + \eTR + \bTR + \bTD \bf %two_first% \eTD + \bTD %[two_second]% \eTD + \eTR + \eTABLE + ]] + + context.templates[MyTable] { + one_first = "one", + two_first = "two", + one_second = "just one $", + two_second = "just two $", + } +\stopluacode +\stopbuffer + +\typebuffer + +This renders: + +\startlinecorrection + \getbuffer +\stoplinecorrection + +You can also use more complex tables. Watch the space before and after the keys: + +\startbuffer +\startluacode + local MyOtherTable = [[ + \bTABLE + \bTR + \bTD \bf % ['one']['first'] % \eTD + \bTD %[ ['one']['second'] ]% \eTD + \eTR + \bTR + \bTD \bf % ['two']['first'] % \eTD + \bTD %[ ['two']['second'] ]% \eTD + \eTR + \eTABLE + ]] + + local data = { + one = { first = "one", second = "only 1$" }, + two = { first = "two", second = "only 2$" }, + } + + context.templates[MyOtherTable](data) + + context.templates(MyOtherTable,data) +\stopluacode +\stopbuffer + +\typebuffer + +We get: + +\startlinecorrection + \getbuffer +\stoplinecorrection + +\stopsection + +\startsection[title={Management}] + +\startsummary[title={context.functions}] + +This is private table that hosts managament of functions. You'd better leave this +one alone! + +\stopsummary + +\startsummary[title={context.nodes}] + +Normally you will just use \type {context(<somenode>)} to flush a node and this +private table is more for internal use. + +\stopsummary + +\stopsection + +\startsection[title=String handlers] + +These two functions implement handlers that split a given string into lines and +do something with it. We stick to showing their call. They are used for special +purpose flushing, like flushing content to \TEX\ in commands discussed here. The +\XML\ subsystem also used a couple of dedicated handlers. + +\starttyping +local foo = newtexthandler { + content = function(s) ... end, + endofline = function(s) ... end, + emptyline = function(s) ... end, + simpleline = function(s) ... end, +} + +local foo = newverbosehandler { + line = function(s) ... end, + space = function(s) ... end, + content = function(s) ... end, + before = function() ... end, + after = function() ... end, +} +\stoptyping + +\startsummary[title={context.printlines(str)}] + +The low level \type {tex.print} function pipes its content to \TEX\ and thereby +terminates at at \type {\r} (cariage return, \ASCII\ 13), although it depends on +the way catcodes and line endings are set up. In fact, a line ending in \TEX\ is +not really one, as it gets replaced by a space. Only several lines in succession +indicate a new paragraph. + +\startbuffer +\startluacode + tex.print("line 1\n line 2\r line 3") +\stopluacode +\stopbuffer + +\typebuffer + +This renders only two lines: + +\getbuffer + +\startbuffer +\startluacode + context("line 1\n line 2\r line 3") +\stopluacode +\stopbuffer + +However, the \type {context} command gives all three lines: + +\typebuffer + +Like: + +\getbuffer + +The \type {context.printlines} command is a direct way to print a string in a way +similar to reading from a file. So, + +\starttyping +tex.print(io.loaddata(resolvers.findfile("tufte"))) +\stoptyping + +Gives one line, while: + +\starttyping +context.printlines(io.loaddata(resolvers.findfile("tufte"))) +\stoptyping + +gives them all, as does: + +\starttyping +context(io.loaddata(resolvers.findfile("tufte"))) +\stoptyping + +as does a na\"ive: + +\starttyping +tex.print((string.gsub(io.loaddata(resolvers.findfile("tufte")),"\r","\n"))) +\stoptyping + +But, because successive lines need to become paragraph separators as bit more +work is needed and that is what \type {printlines} and \type {context} do for +you. However, a more convenient alternative is presented next. + +\stopsummary + +\startsummary[title={context.loadfile(name)}] + +This function locates and loads the file with the given name. The leading and +trailing spaces are stripped. + +\stopsummary + +\startsummary[title={context.runfile(name)}] + +This function locates and processes the file with the given name. The assumption +is that it is a valid \LUA\ file! When no suffix is given, the suffix \type {cld} +(\CONTEXT\ \LUA\ document) is used. + +\stopsummary + +\startsummary[title={context.viafile(data[,tag])}] + +The \type {data} is saved to a (pseudo) file with the optional name \type {tag} +and read in again from that file. This is a robust way to make sure that the data +gets processed like any other data read from file. It permits all kind of +juggling with catcodes, verbatim and alike. + +\stopsummary + +\stopsection + +\startsection[title={Helpers}] + +\startsummary[title={context.tocontext(variable)}] + +For documentation or tracing it can be handy to serialize a variable. The \type +{tocontext} function does this: + +\starttyping +context.tocontext(true) +context.tocontext(123) +context.tocontext("foo") +context.tocontext(tonumber) +context.tocontext(nil) +context.tocontext({ "foo", "bar" },true) +context.tocontext({ this = { foo , "bar" } },true) +\stoptyping + +Beware, \type {tocontext} is also a table that you can assign to, but that might +spoil serialization. This property makes it possible to extend the serializer. + +\stopsummary + +\startsummary[title={context.tobuffer(name,str[,catcodes])}] + +With this function you can put content in a buffer, optionally under a catcode +regime. + +\stopsummary + +\startsummary[title={context.tolines(str[,true])}] + +This function splits the string in lines and flushes them one by one. When the +second argument is \type {true} leading and trailing spaces are stripped. Each +flushed line always gets one space appended. + +\stopsummary + +\startsummary[title={context.fprint([regime,]fmt,...),tex.fprint([regime,]fmt,...)}] + +The \type {tex.fprint} is just there to complement the other flushers in the +\type {tex} namespace and therefore we also have it in the \type {context} +namespace. + +\stopsummary + +\stopsection + +\startsection[title=Tracing] + +\startsummary[title={context.settracing(true or false))}] + +You can trace the \TEX\ code that is generated at the \TEX\ end with: + +\starttyping +\enabletrackers[context.trace] +\stoptyping + +The \LUA\ function sets the tracing from the \LUA\ end. As the \type {context} +command is used a lot in the core, you can expect some more tracing that the code +that you're currently checking. + +\stopsummary + +\startsummary[title={context.pushlogger(fnc) context.poplogger() context.getlogger()}] + +You can provide your own logger if needed. The pushed function receives one string +argument. The getter returns three functions: + +\starttyping +local flush, writer, flushdirect = context.getlogger() +\stoptyping + +The \type{flush} function is similar to \type {tex.sprint} and appends its +arguments, while \type {flushdirect} treats each argument as a line and behaves +like \type {tex.print}. The \type {flush} function adds braces and paranthesis +around its arguments, apartt from the first one, which is considered to be a +command. Examples are: + +\starttyping +flush("one",2,"three") -- catcode, strings|numbers +writer("\\color",{"red"},"this is red") +\stoptyping + +and: + +\starttyping +flush(context.catcodes.verbatim,"one",2,"three") +writer(context.catcodes.verbatim,"\\color",{"red"},"this is red") +\stoptyping + +\stopsummary + +\stopsection + +\startsection[title=States] + +There are several ways to implement alternative code paths in \CONTEXT\ but modes +and conditionals are used mostly. There area few helpers for that. + +\startsummary[title={context.conditionals context.setconditional(name,value)}] + +Conditionals are used to keep a state. You can set their value using the setter, +but their effect is not immediate but part of the current sequence of commands +which is delegated to \TEX. However, you can easily keep track of your state +at the \LUA\ end with an extra boolean. So, after + +\starttyping +if context.conditionals.whatever then + context.setconditional("dothis",false) +else + context.setconditional("dothat",true) +end +\stoptyping + +the value of \type {dothis} and \type {dothat} conditions are not yet set in +\LUA. + +\stopsummary + +\startsummary[title={context.modes context.setmode(name,value)}] + +As with conditionals, you can (re)set the modes in \LUA\ but their values +get changes as part of the command sequence which is delayed till after the +\LUA\ call. + +\stopsummary + +\startsummary[title={context.systemmodes context.setsystemmode(name,value)}] + +The same applies as for regular modes. + +\stopsummary + +\startsummary[title={context.trialtypesetting()}] + +This function returns \type {true} if we're in trial typesetting mode (used when +for instance prerolling a table). + +\stopsummary + +\stopsection + +\startsection[title=Steps] + +The stepper permits stepwise processing of \CONTEXT\ code: after a step contyrol +gets delegated to \CONTEXT\ and afterwards back to \LUA. There main limitation of +this mechanism is that it cannot exceed the number of input levels. + +\startsummary[title={context.stepwise() context.step([str])}] + +Usage is as follows: + +\starttyping +context.stepwise (function() + ... + context.step(...) + ... + context.step(...) + ... + context.stepwise (function() + ... + context.step(...) + ... + context.step(...) + ... + end) + ... + context.step(...) + ... + context.step(...) + ... +end) +\stoptyping + +\stopsummary + +\stopsection + +\stopchapter + +\stopcomponent diff --git a/doc/context/sources/general/manuals/cld/cld-titlepage.tex b/doc/context/sources/general/manuals/cld/cld-titlepage.tex new file mode 100644 index 000000000..926a98952 --- /dev/null +++ b/doc/context/sources/general/manuals/cld/cld-titlepage.tex @@ -0,0 +1,14 @@ +\startcomponent cld-titlepage + +\environment cld-environment + +% \cldprocessfile{cld-mkiv-titlepage.cld} + +\startTEXpage + \externalfigure[cld-mkiv-titlepage.pdf]% +\stopTEXpage % faster during writing + +\startstandardmakeup[doublesided=no,page=no] +\stopstandardmakeup + +\stopcomponent diff --git a/doc/context/sources/general/manuals/cld/cld-verbatim.tex b/doc/context/sources/general/manuals/cld/cld-verbatim.tex new file mode 100644 index 000000000..2007f7d73 --- /dev/null +++ b/doc/context/sources/general/manuals/cld/cld-verbatim.tex @@ -0,0 +1,470 @@ +% language=uk + +\startcomponent cld-verbatim + +\environment cld-environment + +\startchapter[title=Verbatim] + +\startsection[title=Introduction] + +\index{verbatim} + +If you are familiar with traditional \TEX, you know that some characters have +special meanings. For instance a \type {$} starts and ends inline math mode: + +\starttyping +$e=mc^2$ +\stoptyping + +If we want to typeset math from the \LUA\ end, we can say: + +\starttyping +context.mathematics("e=mc^2") +\stoptyping + +This is in fact: + +\starttyping +\mathematics{e=mc^2} +\stoptyping + +However, if we want to typeset a dollar and use the \type {ctxcatcodes} regime, +we need to explicitly access that character using \type {\char} or use a command +that expands into the character with catcode other. + +One step further is that we typeset all characters as they are and this is called +verbatim. In that mode all characters are tokens without any special meaning. + +\stopsection + +\startsection[title=Special treatment] + +The formula in the introduction can be typeset verbatim as follows: + +\startbuffer +context.verbatim("$e=mc^2$") +\stopbuffer + +\typebuffer + +This gives: + +\ctxluabuffer + +You can also do things like this: + +\startbuffer +context.verbatim.bold("$e=mc^2$") +\stopbuffer + +\typebuffer + +Which gives: + +\ctxluabuffer + +So, within the \type {verbatim} namespace, each command gets its arguments +verbatim. + +\startbuffer +context.verbatim.inframed({ offset = "0pt" }, "$e=mc^2$") +\stopbuffer + +\typebuffer + +Here we get: \ctxluabuffer. So, settings and alike are processed as if the user +had used a regular \type {context.inframed} but the content comes out verbose. + +If you wonder why verbatim is needed as we also have the \type {type} function +(macro) the answer is that it is faster, easier to key in, and sometimes the only +way to get the desired result. + +\stopsection + +\startsection[title=Multiple lines] + +Currently we have to deal with linebreaks in a special way. This is due to the +way \TEX\ deals with linebreaks. In fact, when we print something to \TEX, the +text after a \type {\n} is simply ignored. + +For this reason we have a few helpers. If you want to put something in a buffer, +you cannot use the regular buffer functions unless you make sure that they are +not overwritten while you're still at the \LUA\ end. + +\starttyping +context.tobuffer("temp",str) +context.getbuffer("temp") +\stoptyping + +Another helper is the following. It splits the string into lines and feeds them +piecewise using the \type {context} function and in the process adds a space at +the end of the line (as this is what \TEX\ normally does. + +\starttyping +context.tolines(str) +\stoptyping + +Catcodes can get in the way when you pipe something to \TEX\ that itself changes +the catcodes. This happens for instance when you write buffers that themselves +have buffers or have code that changes the line endings as with \type +{startlines}. In that case you need to feed back the content as if it were a +file. This is done with: + +\starttyping +context.viafile(str) +\stoptyping + +The string can contain newlines. The string is written to a virtual file that is +input. Currently names looks like \type {virtual://virtualfile.1} but future +versions might have a different name part, so best use the variable instead. +After all, you don't know the current number in advance anyway. + +\stopsection + +\startsection[title=Pretty printing] + +In \CONTEXT\ \MKII\ there have always been pretty printing options. We needed it +for manuals and it was also handy to print sources in the same colors as the +editor uses. Most of those pretty printers work in a line|-|by|-|line basis, but +some are more complex, especially when comments or strings can span multiple +lines. + +When the first versions of \LUATEX\ showed up, rewriting the \MKII\ code to use +\LUA\ was a nice exercise and the code was not that bad, but when \LPEG\ showed +up, I put it on the agenda to reimplement them again. + +We only ship a few pretty printers. Users normally have their own preferences and +it's not easy to make general purpose pretty printers. This is why the new +framework is a bit more flexible and permits users to kick in their own code. + +Pretty printing involves more than coloring some characters or words: + +\startitemize[packed] +\startitem spaces should honoured and can be visualized \stopitem +\startitem newlines and empty lins need to be honoured as well \stopitem +\startitem optionally lines have to be numbered but \stopitem +\startitem wrapped around lines should not be numbered \stopitem +\stopitemize + +It's not much fun to deal with these matters each time that you write a pretty +printer. This is why we can start with an existing one like the default pretty +printer. We show several variants of doing the same. We start with a simple clone +of the default parser. \footnote {In the meantime the lexer of the \SCITE\ editor +that I used also provides a mechanism for using \LPEG\ based lexers. Although in +the pretty printing code we need a more liberal one I might backport the lexers I +wrote for editing \TEX, \METAPOST, \LUA, \CLD, \XML\ and \PDF\ as a variant for +the ones we use in \MKIV\ now. That way we get similar colorschemes which might +be handy sometimes.} + +\startbuffer +local P, V = lpeg.P, lpeg.V + +local grammar = visualizers.newgrammar("default", { + pattern = V("default:pattern"), + visualizer = V("pattern")^1 +} ) + +local parser = P(grammar) + +visualizers.register("test-0", { parser = parser }) +\stopbuffer + +\typebuffer \ctxluabuffer + +We distinguish between grammars (tables with rules), parsers (a grammar turned +into an \LPEG\ expression), and handlers (collections of functions that can be +applied. All three are registered under a name and the verbatim commands can +refer to that name. + +\startbuffer +\starttyping[option=test-0,color=] +Test 123, +test 456 and +test 789! +\stoptyping +\stopbuffer + +\typebuffer + +Nothing special happens here. We just get straightforward verbatim. + +\getbuffer + +Next we are going to color digits. We collect as many as possible in a row, so +that we minimize the calls to the colorizer. + +\startbuffer +local patterns, P, V = lpeg.patterns, lpeg.P, lpeg.V + +local function colorize(s) + context.color{"darkred"} + visualizers.writeargument(s) +end + +local grammar = visualizers.newgrammar("default", { + digit = patterns.digit^1 / colorize, + pattern = V("digit") + V("default:pattern"), + visualizer = V("pattern")^1 +} ) + +local parser = P(grammar) + +visualizers.register("test-1", { parser = parser }) +\stopbuffer + +\typebuffer \ctxluabuffer + +Watch how we define a new rule for the digits and overload the pattern rule. We +can refer to the default rule by using a prefix. This is needed when we define a +rule with the same name. + +\startbuffer +\starttyping[option=test-1,color=] +Test 123, +test 456 and +test 789! +\stoptyping +\stopbuffer + +\typebuffer + +This time the digits get colored. + +\getbuffer + +In a similar way we can colorize letters. As with the previous example, we use +\CONTEXT\ commands at the \LUA\ end. + +\startluacode +local patterns, P, V = lpeg.patterns, lpeg.P, lpeg.V + +local function colorize_lowercase(s) + context.color{"darkgreen"} + visualizers.writeargument(s) +end +local function colorize_uppercase(s) + context.color{"darkblue"} + visualizers.writeargument(s) +end + +local grammar = visualizers.newgrammar("default", { + + lowercase = patterns.lowercase^1 / colorize_lowercase, + uppercase = patterns.uppercase^1 / colorize_uppercase, + + pattern = + V("lowercase") + + V("uppercase") + + V("default:pattern"), + + visualizer = V("pattern")^1 + +} ) + +local parser = P(grammar) + +visualizers.register("test-2", { parser = parser }) +\stopluacode + +\startbuffer +\starttyping[option=test-2,color=] +Test 123, +test 456 and +test 789! +\stoptyping +\stopbuffer + +\typebuffer + +Again we get some coloring. + +\getbuffer + +It will be clear that the amount of rules and functions is larger when we use a +more complex parser. It is for this reason that we can group functions in +handlers. We can also make a pretty printer configurable by defining handlers at +the \TEX\ end. + +\startbuffer +\definestartstop + [MyDigit] + [style=bold,color=darkred] + +\definestartstop + [MyLowercase] + [style=bold,color=darkgreen] + +\definestartstop + [MyUppercase] + [style=bold,color=darkblue] +\stopbuffer + +\typebuffer \getbuffer + +The \LUA\ code now looks different. Watch out: we need an indirect call to for +instance \type {MyDigit} because a second argument can be passed: the settings +for this environment and you don't want that get passed to \type {MyDigit} and +friends. + +\startluacode +local patterns, P, V = lpeg.patterns, lpeg.P, lpeg.V +local pattern = visualizers.pattern +local verbatim = context.verbatim + +local MyDigit = verbatim.MyDigit +local MyLowercase = verbatim.MyLowercase +local MyUppercase = verbatim.MyUppercase + +-- local handler = newhandler("default, { +-- digit = function(s) MyDigit (s) end, +-- lowercase = function(s) MyLowercase(s) end, +-- uppercase = function(s) MyUppercase(s) end, +-- } ) + +local handler = { + digit = function(s) MyDigit (s) end, + lowercase = function(s) MyLowercase(s) end, + uppercase = function(s) MyUppercase(s) end, +} + +local grammar = visualizers.newgrammar("default", { + + digit = pattern(handler,"digit", patterns.digit ^1), + lowercase = pattern(handler,"lowercase", patterns.lowercase^1), + uppercase = pattern(handler,"uppercase", patterns.uppercase^1), + + pattern = + V("lowercase") + + V("uppercase") + + V("digit") + + V("default:pattern"), + + visualizer = V("pattern")^1 + +} ) + +local parser = P(grammar) + +visualizers.register("test-3", { parser = parser, handler = handler }) +\stopluacode + +\startbuffer +\starttyping[option=test-3,color=] +Test 123, +test 456 and +test 789! +\stoptyping +\stopbuffer + +\typebuffer + +We get digits, upper- and lowercase characters colored: + +\getbuffer + +You can also use parsers that don't use \LPEG: + +\startbuffer +local function parser(s) + visualizers.write("["..s.."]") +end + +visualizers.register("test-4", { parser = parser }) +\stopbuffer + +\typebuffer \ctxluabuffer + +\startbuffer +\starttyping[option=test-4,space=on,color=darkred] +Test 123, +test 456 and +test 789! +\stoptyping +\stopbuffer + +\typebuffer + +The function \type {visualizer.write} takes care of spaces and newlines. + +\getbuffer + +We have a few more helpers: + +\starttabulate[|||] +\NC \type{visualizers.write} \NC interprets the argument and applies methods \NC \NR +\NC \type{visualizers.writenewline} \NC goes to the next line (similar to \type {\par} \NC \NR +\NC \type{visualizers.writeemptyline} \NC inserts an empty line (similer to \type {\blank} \NC \NR +\NC \type{visualizers.writespace} \NC inserts a (visible) space \NC \NR +\NC \type{visualizers.writedefault} \NC writes the argument verbatim without interpretation \NC \NR +\stoptabulate + +These mechanism have quite some overhead in terms of function calls. In the worst +case each token needs a (nested) call. However, doing all this at the \TEX\ end +also comes at a price. So, in practice this approach is more flexible but without +too large a penalty. + +In all these examples we typeset the text verbose: what is keyed in normally +comes out (either or not with colors), so spaces stay spaces and linebreaks are +kept. + +\startbuffer +local function parser(s) + local s = string.gsub(s,"show","demonstrate") + local s = string.gsub(s,"'re"," are") + context(s) +end + +visualizers.register("test-5", { parser = parser }) +\stopbuffer + +\typebuffer \ctxluabuffer + +\startbuffer +\starttyping[option=test-5,color=darkred,style=] +This is just some text to show what we can do with this mechanism. In +spite of what you might think we're not bound to verbose text. +\stoptyping +\stopbuffer + +We can apply this visualizer as follows: + +\typebuffer + +This time the text gets properly aligned: + +\getbuffer + +It often makes sense to use a buffer: + +\startbuffer +\startbuffer[demo] +This is just some text to show what we can do with this mechanism. In +spite of what you might think we're not bound to verbose text. +\stopbuffer +\stopbuffer + +\typebuffer \getbuffer + +Instead of processing the buffer in verbatim mode you can then +process it directly: + +\startbuffer +\setuptyping[file][option=test-5,color=darkred,style=] +\ctxluabuffer[demo] +\stopbuffer + +\typebuffer + +Which gives: + +\start \getbuffer \stop + +In this case, the space is a normal space and not the fixed verbatim space, which +looks better. + +\stopsection + +\stopchapter + +\stopcomponent diff --git a/doc/context/sources/general/manuals/details/back-0.tex b/doc/context/sources/general/manuals/details/back-0.tex new file mode 100644 index 000000000..137884919 --- /dev/null +++ b/doc/context/sources/general/manuals/details/back-0.tex @@ -0,0 +1,39 @@ +% content=tex +% +% copyright=pragma-ade readme=readme.pdf licence=cc-by-nc-sa + +\startenvironment back-0 + +\usemodule[simulate] + +\definecolor[shadecolor][r=.5,g=.5,b=.75] % blue +\definecolor[shadecolor][r=.5,g=.5,b=.25] % yellow + +\definecolor[red] [r=.5] +\definecolor[blue] [b=.5] +\definecolor[green][g=.5] + +\setuplayout + [width=middle,height=middle, + backspace=1cm,topspace=1cm, + header=0pt,footer=0pt,grid=yes] + +\setuprandomize + [medium] + +\setupbackgrounds + [page] + [background=color, + backgroundcolor=white] + +\setuptolerance + [verytolerant,stretch] + +\setupcolors + [state=start] + +\showgrid + +\setrandomseed{1000} + +\stopenvironment diff --git a/doc/context/sources/general/manuals/details/back-1.tex b/doc/context/sources/general/manuals/details/back-1.tex new file mode 100644 index 000000000..5f5109184 --- /dev/null +++ b/doc/context/sources/general/manuals/details/back-1.tex @@ -0,0 +1,58 @@ +\environment back-0 + +\setupindenting[big] + +\definecolumnset[two][n=3] +\definecolumnsetspan[test] + +\definetextbackground[test] + [background=color, + backgroundcolor=gray] + +\definetextbackground[more] + [background=color, + backgroundcolor=lightgray, + alternative=1,rulethickness=2pt] + +\dontcomplain + +\starttext + +\startcolumnset[two] + + \startcolumnsetspan[test] + \input tufte + \stopcolumnsetspan + + \starttextbackground[test] + + \input tufte \par + + \startnarrower + + \starttextbackground[more] + + \input tufte \par + \input tufte \par + \input tufte \par + \input tufte \par + \input tufte \par + \input tufte + + \stoptextbackground + + \stopnarrower + + \stoptextbackground + + \input tufte + + \starttextbackground[more] \input tufte \stoptextbackground + + \starttextbackground[test] \input tufte \stoptextbackground + + \starttextbackground[more] \input tufte \stoptextbackground + +\stopcolumnset + +\stoptext diff --git a/doc/context/sources/general/manuals/details/back-2.tex b/doc/context/sources/general/manuals/details/back-2.tex new file mode 100644 index 000000000..053125827 --- /dev/null +++ b/doc/context/sources/general/manuals/details/back-2.tex @@ -0,0 +1,99 @@ +\environment back-0 + +\startuseMPgraphic{mpos:par:color} + for i=1 upto nofmultipars : + fill multipars[i] withcolor + if multikind[i]="single" : "darkgray" ; + elseif multikind[i]="first" : "red" ; + elseif multikind[i]="middle" : "green" ; + elseif multikind[i]="last" : "blue" ; + else : "black" ; + fi ; + endfor ; +\stopuseMPgraphic + +\setupindenting + [medium,first] + +\definecolumnset + [four] + [n=4, + distance=7.5mm] + +\definetextbackground + [test] + [location=text, + mp=mpos:par:color, + before=\blank, + after=\blank] + +\starttext + +\starttexdefinition test #1#2#3 + \blank + \bgroup + \dontcomplain + \hangindent#1\relax + \hangafter #2\relax + \parindent #3\relax + \starttextbackground[test]% + \simulatewords[n=200,m=500,min=1,max=5,color=gray]% + \stoptextbackground + \par + \egroup + \blank +\stoptexdefinition + +\startcolumnset[four] + +\startbuffer[a] +\test {2cm} { -2} { 5mm} +\test {2cm} { -2} { 0cm} +\test {2cm} { -2} {-5mm} + +\test {2cm} { -5} { 5mm} +\test {2cm} { -5} { 0cm} +\test {2cm} { -5} {-5mm} + +\stopbuffer + +\startbuffer[b] +\test {-1cm} { -2} { 5mm} +\test {-1cm} { -2} { 0cm} +\test {-1cm} { -2} {-5mm} + +\test {-1cm} { -5} { 5mm} +\test {-1cm} { -5} { 0cm} +\test {-1cm} { -5} {-5mm} +\stopbuffer + +\startbuffer[c] +\test { 1cm} { 2} { 5mm} +\test { 1cm} { 2} { 0cm} +\test { 1cm} { 2} {-5mm} + +\test { 1cm} { 5} { 5mm} +\test { 1cm} { 5} { 0cm} +\test { 1cm} { 5} {-5mm} +\stopbuffer + +\startbuffer[d] +\test {-1cm} { 2} { 5mm} +\test {-1cm} { 2} { 0cm} +\test {-1cm} { 2} {-5mm} + +\test {-1cm} { 5} { 5mm} +\test {-1cm} { 5} { 0cm} +\test {-1cm} { 5} {-5mm} +\stopbuffer + +\dorecurse{2}{ + \dorecurse{1}{\getbuffer[a]} + \dorecurse{1}{\getbuffer[b]} + \dorecurse{1}{\getbuffer[c]} + \dorecurse{1}{\getbuffer[d]} +} + +\stopcolumnset + +\stoptext diff --git a/doc/context/sources/general/manuals/details/back-4.tex b/doc/context/sources/general/manuals/details/back-4.tex new file mode 100644 index 000000000..217525ed8 --- /dev/null +++ b/doc/context/sources/general/manuals/details/back-4.tex @@ -0,0 +1,39 @@ +\environment back-0 + +\startuseMPgraphic{mpos:par:color} + for i=1 upto nofmultipars : + fill multipars[i] withcolor + if multikind[i]="single" : "darkgray" ; + elseif multikind[i]="first" : "red" ; + elseif multikind[i]="middle" : "green" ; + elseif multikind[i]="last" : "blue" ; + else : "black" ; + fi ; + endfor ; +\stopuseMPgraphic + +\definecolumnset + [three] + [n=3, + distance=5mm] + +\definetextbackground + [shade] + [location=paragraph, + mp=mpos:par:color, + before=\blank, + after=\blank] + +\starttext + +\startcolumnset[three] + + \dorecurse {20} { + \starttextbackground[shade] + \simulatewords[n=50,m=500,min=1,max=5,color=gray]% + \stoptextbackground + } + +\stopcolumnset + +\stoptext diff --git a/doc/context/sources/general/manuals/details/back-5.tex b/doc/context/sources/general/manuals/details/back-5.tex new file mode 100644 index 000000000..a2d2c4632 --- /dev/null +++ b/doc/context/sources/general/manuals/details/back-5.tex @@ -0,0 +1,64 @@ +\environment back-0 + +\startuseMPgraphic{mpos:par:columnset:shade} + numeric h ; + for i=1 upto nofmultipars : + h := bbheight(p) ; + if multikind[i] = "single" : + fill multipars[i] topenlarged -.5h + withshademethod "linear" + withshadedirection shadedup + withcolor boxfillcolor shadedinto .8white ; + fill multipars[i] bottomenlarged -.5h + withshademethod "linear" + withshadedirection shadedup + withcolor .8white shadedinto boxfillcolor ; + elseif multikind[i] = "first" : + fill multipars[i] + withshademethod "linear" + withshadedirection shadedup + withcolor boxfillcolor shadedinto .8white ; + elseif multikind[i] = "middle" : + fill multipars[i] topenlarged -.5h + withshademethod "linear" + withshadedirection shadedup + withcolor boxfillcolor shadedinto .8white ; + fill multipars[i] bottomenlarged -.5h + withshademethod "linear" + withshadedirection shadedup + withcolor .8white shadedinto boxfillcolor ; + elseif multikind[i] = "last" : + fill multipars[i] + withshademethod "linear" + withshadedirection shadedup + withcolor .8white shadedinto boxfillcolor ; + fi ; + endfor ; +\stopuseMPgraphic + +\definecolumnset + [four] + [n=4, + distance=5mm] + +\definetextbackground + [shade] + [location=paragraph, + backgroundcolor=shadecolor, + mp=mpos:par:columnset:shade, + before=\blank, + after=\blank] + +\starttext + + \startcolumnset[four] + + \dorecurse{15} { + \starttextbackground[shade] + \simulatewords[n=10,m=500,min=1,max=5,color=text]% + \stoptextbackground + } + + \stopcolumnset + +\stoptext diff --git a/doc/context/sources/general/manuals/details/cow.pdf b/doc/context/sources/general/manuals/details/cow.pdf Binary files differnew file mode 100644 index 000000000..9cc8fb0b4 --- /dev/null +++ b/doc/context/sources/general/manuals/details/cow.pdf diff --git a/doc/context/sources/general/manuals/details/details-backpage.tex b/doc/context/sources/general/manuals/details/details-backpage.tex new file mode 100644 index 000000000..85e4d38ce --- /dev/null +++ b/doc/context/sources/general/manuals/details/details-backpage.tex @@ -0,0 +1,34 @@ +% language=uk + +\environment details-environment + +\startcomponent details-backpage + +\page[right] + +\startpagemakeup[doublesided=no,pagestate=stop,page=no] + \startMPcode + StartPage ; + fill Page withcolor \MPcolor{blue} ; % .5blue ; + StopPage ; + \stopMPcode +\stoppagemakeup + +\startpagemakeup[doublesided=no,pagestate=stop,page=no] + \startMPcode + StartPage ; + path p[] ; picture q[] ; + p[1] := Page ; + p[2] := Page xscaled .6 shifted (.2PaperWidth,0) ; + q[1] := textext.raw("\color[white]{CONTEXT}") xsized(.6PaperWidth) ; + q[2] := textext.raw("\color[white]{\currentdate}") xsized(.6PaperWidth) ; + fill p[1] withcolor \MPcolor{red} ; % .5red + fill p[2] withcolor \MPcolor{blue} ; % .5blue + q[2] := q[2] shifted (0,-1.5bbheight(q[2])) ; + draw q[1] shifted (.2PaperWidth,.15PaperHeight) ; + draw q[2] shifted (.2PaperWidth,.15PaperHeight) ; + StopPage ; + \stopMPcode +\stoppagemakeup + +\stopcomponent diff --git a/doc/context/sources/general/manuals/details/details-captiontrickery.tex b/doc/context/sources/general/manuals/details/details-captiontrickery.tex new file mode 100644 index 000000000..ccd163e20 --- /dev/null +++ b/doc/context/sources/general/manuals/details/details-captiontrickery.tex @@ -0,0 +1,290 @@ +% language=uk + +\environment details-environment + +\startcomponent details-captiontrickery + +\startchapter[title={Caption handling}] + +\start + +It's hard to predict what kind of caption placements users want. The amount of +variation if large and thereby any system of specifying them will look complex. +So, examples are the best way to show them. + +\startbuffer +\setupcaption + [figure] + [location=bottom] +\placefigure + [left] + {}{\externalfigure[dummy][lines=2,width=4cm]} +\fakewords{60}{80} \par +\stopbuffer + +\typebuffer \getbuffer + +\startbuffer +% \setupfloats[grid=yes] +% \setupfloats[grid=tolerant] +\setupcaption + [figure] + [location=top] +\placefigure + [left] + {}{\externalfigure[dummy][lines=2,width=4cm]} +\fakewords{60}{80} \par +\stopbuffer + +\typebuffer \getbuffer + +In this document we typeset on a grid. For more complex cases and when a document +is processed without any user intervention, this is often a bad idea because the +snapper can decide to make sure that there is enough space above and below an +element. You can however influence the snapper explicitly: + +\startbuffer +\setupcaption + [figure] + [location=top] +\placefigure + [left,line] + {}{\externalfigure[dummy][lines=2,width=4cm]} +\fakewords{60}{80} \par +\stopbuffer + +\typebuffer \getbuffer + +Normally a side float plus caption has a normalized (strut) depth while also +top skip gets applied. When one of the grid related options \type {height}, \type +{line}, \type {depth}, \type {grid} or \type {halfline} is given the top skip +correction is removed. The \type {grid} option removes the depth too. The \type +{grid} option removes the depth while the \type {height} and \type {depth} +options adds an extra amount of strut depth. The \type {depth} option also adds a +line and \type {halfline} removes a line but adds strut height. Indeed this sounds +complicated so best play with it a bit. + +Keep in mind that the snapper plays safe and therefore tends to add more space when +needed. You can set a grid parameter that controls it: + +\starttyping +\setupfloats[grid=tolerant] +\stoptyping + +Currently this only applies to side floats but in the future we might support it +for regular floats too. + +\startbuffer +\setupcaption + [figure] + [width=4cm,align=flushright,location={left,high}] +\placefigure + [left] + {}{\externalfigure[dummy][lines=2,width=4cm]} +\fakewords{60}{80} \par +\stopbuffer + +\typebuffer \getbuffer + +\startbuffer +\setupcaption + [figure] + [width=4cm,align=flushright,location={high,lefthanging}] +\placefigure + [left] + {}{\externalfigure[dummy][lines=2,width=4cm]} +\fakewords{60}{80} \par +\stopbuffer + +\typebuffer \getbuffer + +\startbuffer +\setupcaption + [figure] + [width=4cm,align=flushleft,location={high,righthanging}] +\placefigure + [right] + {}{\externalfigure[dummy][lines=2,width=4cm]} +\fakewords{60}{80} \par +\stopbuffer + +\typebuffer \getbuffer + +\startbuffer +\setupcaption + [figure] + [width=4cm,align=flushleft,location={high,rightmargin}] +\placefigure + [right] + {}{\externalfigure[dummy][lines=2,width=4cm]} +\fakewords{60}{80} \par +\stopbuffer + +\typebuffer \getbuffer + +The location of a caption is determined by the keywords \type {top}, \type +{bottom} and for the side captions \type {high}, \type {middle}, \type {low}, +either or not in combination with \type {left}, \type {right}, \type +{leftmargin}, \type {rightmargin}, {lefthanging} or \type {righthanging}. + +The next series of examples shows the regular (non||side) floats. + +\startbuffer +\setupcaption + [figure] + [location={high,left}] +\placefigure + {}{\externalfigure[dummy][lines=2,width=4cm]} +\stopbuffer + +\typebuffer \getbuffer + +\startbuffer +\setupcaption + [figure] + [width=4cm,align=flushright,location={high,left}] +\placefigure + {}{\externalfigure[dummy][lines=2,width=4cm]} +\stopbuffer + +\typebuffer \getbuffer + +\startbuffer +\setupcaption + [figure] + [width=4cm,align=flushright,location={middle,left}] +\placefigure + {}{\externalfigure[dummy][lines=2,width=4cm]} +\stopbuffer + +\typebuffer \getbuffer + +\startbuffer +\setupcaption + [figure] + [width=4cm,align=flushright,location={low,left}] +\placefigure + {}{\externalfigure[dummy][lines=2,width=4cm]} +\stopbuffer + +\startbuffer +\setupfloat + [figure] + [location=right] +\setupcaption + [figure] + [width=4cm,align=flushright,location=high] +\placefigure + {}{\externalfigure[dummy][lines=2,width=4cm]} +\stopbuffer + +\typebuffer \getbuffer + +\startbuffer +\setupfloat + [figure] + [location=right] +\setupcaption + [figure] + [width=4cm,align=flushright,location={high,left}] +\placefigure + {}{\externalfigure[dummy][lines=2,width=4cm]} + +\setupfloat + [figure] + [location=left] +\setupcaption + [figure] + [width=4cm,align=flushleft, location={high,left}] +\placefigure + {}{\externalfigure[dummy][lines=2,width=4cm]} +\stopbuffer + +\typebuffer \getbuffer + +\startbuffer +\setupfloat + [figure] + [location=middle] +\setupcaption + [figure] + [width=4cm,align=flushright, location={high,lefthanging}] +\placefigure + {}{\externalfigure[dummy][lines=2,width=4cm]} +\stopbuffer + +\typebuffer \getbuffer + +\startbuffer +\setupfloat + [figure] + [location=middle] +\setupcaption + [figure] + [width=4cm,align=flushleft, location={high,righthanging}] +\placefigure + {}{\externalfigure[dummy][lines=2,width=4cm]} +\stopbuffer + +\typebuffer \getbuffer + +\startbuffer +\setupfloat + [figure] + [location=right] +\setupcaption + [figure] + [width=4cm,align=flushleft, location={high,rightmargin}] +\placefigure + {}{\externalfigure[dummy][lines=2,width=4cm]} +\stopbuffer + +\typebuffer \getbuffer + +\startbuffer +\setupfloat + [figure] + [location=left] +\setupcaption + [figure] + [width=4cm,align=flushright,location={high,leftmargin}] +\placefigure + {}{\externalfigure[dummy][lines=2,width=4cm]} +\stopbuffer + +\typebuffer \getbuffer + +\startbuffer +\setupfloat + [figure] + [location=middle] +\setupcaption + [figure] + [width=4cm,align=flushright,location={high,outermargin}] +\placefigure + {}{\externalfigure[dummy][lines=2,width=4cm]} +\stopbuffer + +\typebuffer \getbuffer + +\startbuffer +\setupfloat + [figure] + [location=middle] +\setupcaption + [figure] + [width=4cm,align=flushleft, location={high,innermargin}] +\placefigure + {}{\externalfigure[dummy][lines=2,width=4cm]} +\stopbuffer + +\typebuffer \getbuffer + +The \type {innermargin} and \type {outermargin} are special cases. They adapt to +the kind of page. + +\page \stop + +\stopchapter + +\stopcomponent diff --git a/doc/context/sources/general/manuals/details/details-colofon.tex b/doc/context/sources/general/manuals/details/details-colofon.tex new file mode 100644 index 000000000..1ceda44e7 --- /dev/null +++ b/doc/context/sources/general/manuals/details/details-colofon.tex @@ -0,0 +1,36 @@ +% language=uk + +\environment details-environment + +\startcomponent details-colofon + +\startchapter[title={About this document}] + +This document is typeset in \CONTEXT\ using \LUATEX\ with \METAPOST. We use only +one font: the Computer Modern Typewriter. The verbatim portions of the text are +typeset in its mono spaced variant. One of the reasons that I chose this font is +that we need a mono spaced font to typeset the example code, and the Computer +Modern Typewriter is one the best there is. This font combines well with many +other typefaces, but the sometimes excessive use of different fonts (and sizes) +in the styles that I have to implement made me long for simplicity. And so I +decided to stick to one font. A careful reader will notice that this document has +character protruding enabled (resulting in hanging punctuation). + +We use a couple of colors. Again, I went for simplicity and use rather primary +colors, although I do use them in transparent variants as well. + +There is not much more to say, apart from that I want to thank our customers as +well as \CONTEXT\ users for asking me to implement \DTP\ competing styles and +features. Their demands drive \CONTEXT\ in directions we could not have foreseen +when we started its development. + +We use a (transparent) gray background behind the text so that we have an +indication where the text area is positioned relative to the page. It also +enables us to comfortably turn on the grid. + +Some features shown here are relatively new and therefore they occasionally are +improved. As a result some aspects of their functionality may change. + +\stopchapter + +\stopcomponent diff --git a/doc/context/sources/general/manuals/details/details-contents.tex b/doc/context/sources/general/manuals/details/details-contents.tex new file mode 100644 index 000000000..737f080a0 --- /dev/null +++ b/doc/context/sources/general/manuals/details/details-contents.tex @@ -0,0 +1,13 @@ +% language=uk + +\environment details-environment + +\startcomponent details-contents + +\starttitle[title={Table of contents}] + +\placelist[chapter][criterium=text] + +\stoptitle + +\stopcomponent diff --git a/doc/context/sources/general/manuals/details/details-environment.tex b/doc/context/sources/general/manuals/details/details-environment.tex new file mode 100644 index 000000000..003ea6905 --- /dev/null +++ b/doc/context/sources/general/manuals/details/details-environment.tex @@ -0,0 +1,317 @@ +% language=uk + +% this a rather old style and made for mkii, currently the only adaption to mkiv is +% with respect to fonts + +\showgrid + +\startenvironment details-environment + +\usemodule[abr-02,simulate] % visual + +\setupsystem + [random=123] + +\setupinteraction + [state=start, + style=, + color=] + +\setuplist + [chapter] + [interaction=all] + +\setupalign + [verytolerant, + stretch, + hanging] + +\setuptolerance + [verytolerant, + stretch] + +\definefontfeature + [fullprotrusion] + [protrusion=pure] + +\definefontfeature[default][default,fullprotrusion] + +\setupbodyfont[modernvariable,12pt] + +\setuppagenumbering + [alternative=doublesided] + +\setupindenting + [medium] + +\setuptyping + [margin=standard] + +\setuptyping + [color=blue] + +\setuptype + [color=blue] + +\startmode [screen] + \definepapersize[A4-S][width=210mm,height=210mm] + \setuppapersize[A4-S][A4-S] +\stopmode + +\setuplayout + [header=3cm, + footer=0pt, + topspace=0cm, + bottomspace=2cm, + bottom=2cm, + bottomdistance=0pt, + height=middle, + margindistance=.5cm, + leftmargin=2.0cm, + rightmargin=2.5cm, + backspace=2.5cm, + cutspace=3cm, + width=middle, + lines=48, % otherwise background issue +% textdistance=\dimexpr-\topskip+\strutheight+.5cm\relax, + grid=yes] + +\setuplayout + [margindistance=.5cm, + edgedistance=.25cm, + rightmargin=1cm, + rightedge=.75cm, + leftmargin=1cm, + leftedge=.5cm] + +\setuppagenumbering + [location=] + +\definecolor[red] [r=.5] +\definecolor[blue] [b=.5] +\definecolor[green] [g=.5] +\definecolor[yellow] [r=.5,g=.5] +\definecolor[gray] [s=.5] + +\definecolor[tred] [r=.5,t=.5,a=1] +\definecolor[tblue] [b=.5,t=.5,a=1] +\definecolor[tgreen] [g=.5,t=.5,a=1] +\definecolor[tyellow] [r=.5,g=.5,t=.5,a=1] +\definecolor[twhite] [s=0,t=.5,a=1] + +\definecolor[infogray] [g=.5,t=.5,a=1] +\definecolor[infogray] [s=.7,t=.5,a=1] +\definecolor[pagegray] [y=.5,t=.5,a=1] +\definecolor[textgray] [s=.9,t=.5,a=1] +\definecolor[areafill] [g=.5,t=.125,a=1] +\definecolor[areafill] [b=.5,t=.125,a=1] + +\definecolor[fakerulecolor] [green] +\definecolor[fakeparindentcolor][blue] + +\definefont[BigNumber][RegularBold sa 4] % 5 +\definefont[BigText] [RegularBold sa 2] +\definefont[MedNumber][RegularBold sa 2] + +\startbuffer[regular:sizes] +\definefont[regular:1][Regular*default sa 1] +\definefont[regular:2][Regular*default sa 2] +\definefont[regular:3][Regular*default sa 3] +\definefont[regular:4][Regular*default sa 4] +\stopbuffer + +\getbuffer[regular:sizes] + +\useMPlibrary[dum] + +\definecolor[p-red] [r=1] +\definecolor[p-blue] [b=1] +\definecolor[p-yellow] [r=1,g=1] + +\definepalet + [placeholder] + [1=p-red,2=p-blue,3=p-yellow] + +\definelayer + [graphics] + [position=yes] + +\setupbackgrounds + [page] + [background={color,graphics}, + backgroundoffset=1cm, + backgroundcolor=pagegray] + +\definelayer + [extras] + [width=\paperwidth,height=\paperheight] + +\setupbackgrounds + [leftpage] + [background=extras] + +\setupbackgrounds + [rightpage] + [background=extras] + +\definelayer % we need to compensate the backgroundoffset + [text] + [hoffset=1cm, + voffset=1cm] + +\setupbackgrounds + [text] + [background={color,text}, + backgroundoffset=1cm, + backgroundcolor=textgray] + +% chapter head + +\setuphead + [chapter] + [placehead=empty, + header=chapter, + incrementnumber=details, + style=\BigText, + numberstyle=\BigNumber] + +% we need to check each file +% +% \setuphead +% [chapter] +% [beforesection=\page, +% aftersection=\page] + +\definetext + [chapter] + [header] + [\setups{chapter}] + [] + +\definelayer + [chapter] + [width=\dimexpr\makeupwidth+\cutspace\relax, + height=\headerheight] + +\startsetups chapter + \setups[chapter:title] + \setups[chapter:number] + \setups[chapter:finish] +\stopsetups + +% here we can use mp instead but the following is not that bad either + +\startsetups chapter:title + + \setlayerframed + [chapter] + [x=\dimexpr\makeupwidth+\cutspace\relax, + location=lb] + [height=\headerheight, + foregroundcolor=white, + background=color, + backgroundcolor=blue, + frame=off, + offset=none, + align={right,lohi}] + {\hbox spread .5\cutspace + {\hss + \doiftextelse{\placeheadtext[chapter]}% + {\placeheadtext[chapter]}% + {\placeheadtext[title]}% + \hss}\space + \vskip.5cm} + +\stopsetups + +\startsetups chapter:number + + \setlayerframed + [chapter] + [x=\dimexpr\makeupwidth+\cutspace\relax, + y=\vsize, + location=lb] + [width=\dimexpr\cutspace-\rightmargindistance\relax, + height=\dimexpr\cutspace-\rightmargindistance\relax, + foregroundcolor=white, + background=color, + backgroundcolor=red, + frame=off, + offset=none, + align={middle,lohi}] + {\hbox to \hsize + {\hskip.5cm\hss + \doifmode{*bodypart}{\placeheadnumber[chapter]}% + \hss}} + +\stopsetups + +\startsetups chapter:finish + + \framed + [width=\makeupwidth, + height=\headerheight, + background=chapter, + frame=off] + {} + +\stopsetups + +% page number + +\defineframedtext + [pagenumbertext] + [align={lohi,middle}, + width=\dimexpr\cutspace-\margindistance\relax, % \hsize, + height=\vsize, + background=color, + backgroundcolor=green, + style=\MedNumber, + color=white, + offset=none, + frame=off] + +\setupbottomtexts + [margin] + [] + [\pagenumbertext{\hbox to \hsize{\hskip.5cm\hss\placepagenumber\hss}}] + [\pagenumbertext{\hbox to \hsize{\hss\placepagenumber\hss\hskip.5cm}}] + [] + +% area + +\setupbackgrounds [text] [leftedge] [backgroundoffset=0pt,backgroundcolor=areafill] +\setupbackgrounds [text] [rightedge] [backgroundoffset=0pt,backgroundcolor=areafill] +\setupbackgrounds [text] [leftmargin] [backgroundoffset=0pt,backgroundcolor=areafill] +\setupbackgrounds [text] [rightmargin] [backgroundoffset=0pt,backgroundcolor=areafill] + +% grids + +\setuptextbackground + [grid] + [state=start] + +% intros + +% \definetextbackground +% [intro] +% [backgroundcolor=infogray, % green, +% backgroundoffset=.25cm, +% offset=.5cm, +% frame=off, +% color=white] + +\setuplist + [chapter] + [before=, + after=, + alternative=c, + aligntitle=yes] + +\startsectionblockenvironment [backpart] + + \writebetweenlist[chapter]{\blank} + +\stopsectionblockenvironment + +\stopenvironment diff --git a/doc/context/sources/general/manuals/details/details-finetuningfloats.tex b/doc/context/sources/general/manuals/details/details-finetuningfloats.tex new file mode 100644 index 000000000..71e0772d1 --- /dev/null +++ b/doc/context/sources/general/manuals/details/details-finetuningfloats.tex @@ -0,0 +1,657 @@ +% language=uk + +% todo: \setlayeranchored[text-1]{HELLO WORLD} + +\environment details-environment + +\startcomponent details-finetuningfloats + +\startchapter[title={Finetuning graphics}] + +In this chapter we will discuss a few more tricks to control float placement. +This control is needed if you want to typeset documents in a semi desk top +publishing way. + +When you combine technical graphics, you may wish to align the content optically. +This can be done with the \type {offset} command. We will demonstrate this with a +couple of \METAPOST\ graphics: + +\startbuffer +\startreusableMPgraphic{alpha} + fill fullsquare xyscaled( 2cm, 2cm) withcolor \MPcolor{red} ; + fill unitsquare xyscaled(+.5cm,+.5cm) withcolor \MPcolor{gray} ; +\stopreusableMPgraphic + +\startreusableMPgraphic{beta} + fill fullsquare xyscaled( 2cm, 2cm) withcolor \MPcolor{red} ; + fill unitsquare xyscaled(+.5cm,-.5cm) withcolor \MPcolor{gray} ; +\stopreusableMPgraphic + +\startreusableMPgraphic{gamma} + fill fullsquare xyscaled( 2cm, 2cm) withcolor \MPcolor{red} ; + fill unitsquare xyscaled(-.5cm,-.5cm) withcolor \MPcolor{gray} ; +\stopreusableMPgraphic + +\startuseMPgraphic{delta} + fill fullsquare xyscaled( 2cm, 2cm) withcolor \MPcolor{red} ; + fill unitsquare xyscaled(-.5cm,+.5cm) withcolor \MPcolor{gray} ; +\stopuseMPgraphic +\stopbuffer + +\typebuffer \getbuffer + +\startbuffer +\startcombination[2*2] + {\reuseMPgraphic{alpha}} {alpha} + {\reuseMPgraphic {beta}} {beta} + {\reuseMPgraphic{gamma}} {gamma} + {\reuseMPgraphic{delta}} {delta} +\stopcombination +\stopbuffer + +\typebuffer + +In \in {figure} [fig:offset-1] we place these graphics in a \type {2*2} grid. As +you can see, the centers don't align well. + +\placefigure[here][fig:offset-1]{}{\getbuffer} + +In \in {figure} [fig:offset-2] the centers of the graphic align well. This is +accomplished by adding some space around the graphics. + +\startbuffer +\startcombination[2*2] + {\ruledhbox{\offset[rightoffset=1cm] {\reuseMPgraphic{alpha}}}} {alpha} + {\ruledhbox{\offset[bottomoffset=.5cm]{\reuseMPgraphic {beta}}}} {beta} + {\ruledhbox{\offset[bottomoffset=.5cm]{\reuseMPgraphic{gamma}}}} {gamma} + {\ruledhbox{\offset[leftoffset=1cm] {\reuseMPgraphic{delta}}}} {delta} +\stopcombination +\stopbuffer + +\placefigure[here][fig:offset-2]{}{\getbuffer} + +\starttyping +\startcombination[2*2] + {\offset[rightoffset=1cm] {\reuseMPgraphic{alpha}}} {alpha} + {\offset[bottomoffset=.5cm]{\reuseMPgraphic {beta}}} {beta} + {\offset[bottomoffset=.5cm]{\reuseMPgraphic{gamma}}} {gamma} + {\offset[leftoffset=1cm] {\reuseMPgraphic{delta}}} {delta} +\stopcombination +\stoptyping + +If we align the centers vertically, as demonstrated in \in {figure} +[fig:offset-2] we can stick to a few bottom offsets. + +\starttyping +\startcombination[4*1] + {\reuseMPgraphic{alpha}} {alpha} + {\offset[bottomoffset=.5cm]{\reuseMPgraphic {beta}}} {beta} + {\offset[bottomoffset=.5cm]{\reuseMPgraphic{gamma}}} {gamma} + {\reuseMPgraphic{delta}} {delta} +\stopcombination +\stoptyping + +\startbuffer +\startcombination[4*1] + {\ruledhbox {\reuseMPgraphic{alpha}}} {alpha} + {\ruledhbox{\offset[bottomoffset=.5cm]{\reuseMPgraphic {beta}}}} {beta} + {\ruledhbox{\offset[bottomoffset=.5cm]{\reuseMPgraphic{gamma}}}} {gamma} + {\ruledhbox {\reuseMPgraphic{delta}}} {delta} +\stopcombination +\stopbuffer + +\placefigure[here][fig:offset-3]{}{\getbuffer} + +These examples demonstrate that the dimensions change with the offset. You can +retain the dimensions but still align them by using the \type {x} and \type {y} +parameter. This kind of manipulations will often result in a ugly spacing because +the placement macros handle on the original dimensions. \in {Figure} +[fig:offset-4] demonstrates this. + +\starttyping +\startcombination[4*1] + {\reuseMPgraphic{alpha}} {alpha} + {\offset[y=-.5cm]{\reuseMPgraphic {beta}}} {beta} + {\offset[y=-.5cm]{\reuseMPgraphic{gamma}}} {gamma} + {\reuseMPgraphic{delta}} {delta} +\stopcombination +\stoptyping + +\startbuffer +\startcombination[4*1] + {\ruledhbox {\reuseMPgraphic{alpha}}} {alpha} + {\ruledhbox{\offset[y=-.5cm]{\reuseMPgraphic {beta}}}} {beta} + {\ruledhbox{\offset[y=-.5cm]{\reuseMPgraphic{gamma}}}} {gamma} + {\ruledhbox {\reuseMPgraphic{delta}}} {delta} +\stopcombination +\stopbuffer + +\placefigure[here][fig:offset-4]{}{\getbuffer} + +In the previous chapter we demonstrated how a side float can be moved up or down +by providing a placement directive or by preceding the placement with \type +{\movesidefloat}. Such a move can be used to align a graphic with particular line +of text. This command can also be used for alignment purposes similar to the +\type {\offset} command. We will demonstrate this with the following graphics. + +\startbuffer +\startreusableMPgraphic{gnu} + fill fullsquare xyscaled( 4cm, 1cm) withcolor \MPcolor{red} ; + fill unitsquare xyscaled(-1cm,.5cm) + shifted (0,-.25cm) withcolor \MPcolor{gray} ; +\stopreusableMPgraphic + +\startreusableMPgraphic{gnat} + fill fullsquare xyscaled( 4cm, 1cm) withcolor \MPcolor{red} ; + fill unitsquare xyscaled(+1cm,.5cm) + shifted (0,-.25cm) withcolor \MPcolor{gray} ; +\stopreusableMPgraphic +\stopbuffer + +\typebuffer \getbuffer + +In the next two examples we shift the \type {gnu} and \type {gnat} graphics +horizontally in order to get them aligned. The move does not change the +dimensions of the float, but they do influence the paragraph shape. + +\startbuffer[a] +\movesidefloat [x=.5cm] +\placefigure [left,none] {} {\reuseMPgraphic{gnu}} +\stopbuffer + +\startbuffer[b] +\movesidefloat [x=-.5cm] +\placefigure [left,none] {} {\reuseMPgraphic{gnat}} +\stopbuffer + +\typebuffer[a,b] + +\getbuffer[a] \fakewords{50}{100} +\getbuffer[b] \fakewords{50}{100} + +\blank + +It is possible to shift vertically by setting \type {y}, but this is often a bad +idea and definitely may spoil alignment of graphics to the grid. If you have to +revert to this trick, you are probably working in document screw||up mode. This +is why in grid mode, we automatically round to an equal number of lines. + +If you know what text you're dealing with and also can be sure about the height +of a graphic, you can trick \CONTEXT\ to ignore the dimensions of a graphic. Here +we use the graphic: + +\startbuffer +\startreusableMPgraphic{gnome} + fill fullsquare xyscaled(2cm, 1cm) withcolor \MPcolor{red} ; + fill fullsquare xyscaled(1cm,.5cm) withcolor \MPcolor{gray} ; +\stopreusableMPgraphic +\stopbuffer + +\typebuffer \getbuffer + +\startbuffer +\placefigure[leftmargin,none,reset]{}{\reuseMPgraphic{gnome}} +\stopbuffer + +\typebuffer \getbuffer + +The graphic is moved into the margin (\type {leftmargin}), has no caption (\type +{none}), and all kind of tricky housekeeping is reset (\type {reset}). + +\startbuffer +\placefigure[left,none,high,low]{}{\reuseMPgraphic{gnome}} +\stopbuffer + +\getbuffer + +Now the next graphic is not influenced by the previous one, so we can place them +close to each other. Use these tricks with care, especially if your document +source is reused and the typeset products are not carefully checked. + +\typebuffer + +When \CONTEXT\ tries to determine if a float fits, it makes a couple of +assumptions, for instance that the available room equals the text height minus +the height of the text so far. You can slightly influence the way these values +are interpreted by setting the calculation method. You can set the methods as +follows: + +\starttyping +\setupfloats[textmethod=0,sidemethod=1] +\stoptyping + +Method~0 just looks at the raw dimensions, while method~1 lessens the maximum +text height by one percent, thereby playing safe. Method~2 takes a window of +1~point. This may lead to better decisions since we may run into rounding errors +of several scaled points (which is small but troublesome). Method~2 is well +suited when typesetting on a grid, because there everything has to fit in a +rounded number of lines, which leaves no room for rounding errors. + +\starttabulate[||c|c|] +\NC \bf grid mode \NC \bf yes \NC \bf no \NC \NR +\NC \type{sidemethod} \NC \type{2} \NC \type{1} \NC \NR +\NC \type{textmethod} \NC \type{2} \NC \type{0} \NC \NR +\stoptabulate + +\startusableMPgraphic{demo-1}{color} + path p ; + p := fullsquare xyscaled (3cm,2LineHeight) ; + fill p withcolor \MPvar{color} ; +\stopusableMPgraphic + +\startusableMPgraphic{demo-2}{color,morecolor} + path p ; p := fullsquare xyscaled (6cm,4LineHeight) ; + path q ; q := fullsquare xyscaled (3cm,2LineHeight) ; + fill p withcolor \MPvar{color} ; + setbounds currentpicture to q ; + fill q withcolor \MPcolor{morecolor} ; +\stopusableMPgraphic + +As you may know by now, we can use the directives \type {high}, \type {low}, +\type {height}, \type {depth} and \type {line} to influence the spacing around a +side float. A real tight spacing can be achieved with \type {fit}. + +\starttyping +\placefigure[left,fit,none]{}{some graphic} +\stoptyping + +\placefigure[left,fit,none]{}{\useMPgraphic{demo-1}{color=red}} + +This kind of placements only make sense in special situations, because normally +you don't want the graphic to touch the text. + +If you think that this is all a user may want, you're wrong. It is not imaginary +that graphics have small pieces sticking out and|/|or lots of white space as part +of their design. In that case, the bounding box can be set to a smaller size. + +\placefigure + [left,fit,none] + {} + {\setlayer + [graphics] + {\useMPgraphic{demo-2}{color=red,morecolor=tgreen}}} + +Now, when handling a side float, \CONTEXT\ first places the float, and then +starts with typesetting the paragraph, cleverly avoiding the graphic. However, +when the graphic is virtually larger than its known size, it may cover part of +the preceding paragraph. + +How come that the graphic starting this paragraph does not do that? It is because +we explicitly moved it to the background. This involves some preparation. At the +document level, we define a layer called \type {graphic}. + +\starttyping +\definelayer[graphics][position=yes] +\stoptyping + +The position directive tells \CONTEXT\ that it should honour the position of the +graphic. Next we must make sure that this layer is placed. + +\starttyping +\setupbackgounds[page][background=graphics] +\stoptyping + +Now we're ready to move graphics to this layer: + +\starttyping +\placefigure + [left,fit,none] + {}{\setlayer[graphics]{graphic}} +\stoptyping + +It's now a small step to more advanced movements. Say that you want to move the +graphic a little bit to the left. In that case you can tell the layer placement +to do so. + +\starttyping +\placefigure + [left,fit,none]{}{\setlayer[graphics][hoffset=-12pt]{graphic}} +\stoptyping + +From this you can deduce that there is also a movement in the vertical direction +using \type {voffset}. In addition you can anchor the graphic using the \type +{location} parameter and provide offsets. + +\placefigure + [left,fit,none] + {} + {\setlayer + [graphics][hoffset=-12pt] + {\useMPgraphic{demo-2}{color=red,morecolor=tgreen}}} + +As soon as you run into situations where float placement is to be consistently +enforced, you will feel the need for dedicate placement macros. For example: + +\startbuffer +\definefloat + [somefloat] + [figure] + +\setupfloat + [somefloat] + [sidespaceafter=, + sidespacebefore=, + default={left,none}] +\stopbuffer + +\typebuffer \getbuffer + +Instead of resetting the side spacing, we could have default to \type {high,low}, +but this way we can overload the default placement and still get zero spacing. + +Throughout this manual we discuss features related to overlays and layers. These +permit you to move content around in ways that either or not depend on the text +flow. We have now come to another trick based on these mechanisms: bleeding. + +When printing a document, you need to take into account that when graphics go +beyond the page boundary, you need to compensate for inaccuracies in cutting the +pages. Such graphics are called bleeding graphics and the amount of bleed is +often a few millimeters. + +The best way to handle such graphics is to use the correct dimensions and play +with the edge widths and distances in combination with backspace and cut space. In +a properly set up layout and by using a well designed set of predefined graphic +placements, you can handle this quite well. A bleeding figure can be defined as +follows: + +\startbuffer +\definefloat + [edgefigure] + [figure] + +\setupfloat + [edgefigure] + [default={inner,height,high,low,none}, + maxwidth=4cm] + +\defineexternalfigure + [edgefigure] + [width=\dimexpr\backspace+4cm-1mm\relax, + lines=4] +\stopbuffer + +\typebuffer \getbuffer + +The default placement is pre|-|configured to have no additional vertical space and +align on the height of a line (this is default behaviour so the \type {height} +key is redundant here. The 1mm in the previous definition simulates what happens +when a page is cut off slightly wrong: we get an annoying gap. + +\startbuffer[a] +\placeedgefigure + {} + {\externalfigure[hacker][edgefigure]} +\stopbuffer + +\typebuffer[a] \getbuffer[a] \fakewords{50}{100} + +One of the nice things about \TEX\ is that you can fine tune dimensions pretty +well. So, instead of the previous placement, which turns out rather ugly, we can +come up with a better one: + +\startbuffer +\setupfloat + [edgefigure] + [default={inner,height,high,low,none}, + maxwidth=4cm, + margin=\strutdepth] + +\defineexternalfigure + [edgefigure] + [width=\dimexpr\backspace+4cm+2mm\relax, + height=\dimexpr3\lineheight+\strutheight\relax] +\stopbuffer + +\typebuffer \getbuffer + +This time we take no risk and add 2mm to the dimensions so that we can be sure +that the edge of the graphic falls outside the page boundary. + +\getbuffer[a] \fakewords{50}{100} + +The \CONTEXT\ resourse library modules provide means to report back the +dimensions of graphics used in a document, so that you can develop (tune) them +with the proper dimensions. In practice a slightly wider than normal graphic +(scaling it horizontally a few millimeters more) does not harm the visual +appearance that much, so adapting a graphic to this kind of bleeding is not +really needed. + +In addition to this (rather natural) way of adding bleed to a graphic, you can +apply the \type {\bleed} macro. In the previously discussed method the figure +placement mechanisms work with the real dimensions. The \type {bleed} macro is +using scaling in a different way: from the perspective of \CONTEXT\ the graphic +remains its original dimensions and the figure placement mechanisms will act +accordingly. We will give a couple of examples of using this macro. + +Permitted bleeding locations are \type {l}, \type {r}, \type {t}, \type {b}, +\type {lr}, \type {bl}, \type {br}, \type {tl} and \type {tr}. + +\startbuffer +\placesomefloat + [left,none,fit] + {} + {\setupbleeding[offset=5mm]% + \bleed[width=5cm,height=1cm,location=l] + {\externalfigure[mill][bleed]}} +\stopbuffer + +\typebuffer \getbuffer \fakewords{50}{100} + +\startbuffer +\placesomefloat + [left,none,fit] + {} + {\setupbleeding[offset=2mm]% + \bleed[width=5cm,height=1cm,location=l] + {\externalfigure[mill][bleed]}} +\stopbuffer + +\typebuffer \getbuffer \fakewords{50}{100} + +The amount of bleeding depends on the postprocessing. In the previous paragraph +we used a bleed offset of 5mm, and here we used 2mm. Because the graphic is +scaled in order to match the bleed, it will be slightly distorted. With small +values this will go unnoticed. You can set the offset with: + +\starttyping +\setupbleeding[offset=5mm] +\stoptyping + +Bleeding itself is accomplished by the \type {\bleed} macro as in: + +\starttyping +\bleed + [width=5cm,height=1cm,location=l] + {\externalfigure[mill][width=\bleedwidth,height=\bleedheight]} +\stoptyping + +It is kind of awkward to pass those two dimensions so here is a shorter way of +doing the same: + +\starttyping +\bleed + [width=5cm,height=1cm,location=l] + {\externalfigure[mill][bleed]} +\stoptyping + +In fact, this uses the following definition: + +\starttyping +\defineexternalfigure[bleed][width=\bleedwidth,height=\bleedheight] +\stoptyping + +You can influence the scaling of a graphic by setting the \type {stretch} +parameters. The location parameter determines the direction of the stretch: \type +{l}~(left), \type {r}~(right), \type {t}~(top), \type {b}~(bottom) or a +combination of these. We will now combine the previous example code with this +knowledge. + +\startbuffer +\placefigure + [left] + {} + {\bleed + [stretch=no,voffset=0pt,hoffset=1cm] + {\externalfigure[detcow][bleed]}} +\stopbuffer + +\typebuffer \getbuffer \fakewords {100} {150} + +\startbuffer +\placefigure + [left] + {} + {\bleed + [width=5cm,height=3cm,location=l] + {\externalfigure[detcow][bleed]}} +\stopbuffer + +\typebuffer \getbuffer \fakewords {100} {150} + +\startbuffer +\placefigure + [right] + {} + {\bleed + [width=5cm,height=3cm,location=r] + {\externalfigure[detcow][bleed]}} +\stopbuffer + +\typebuffer \getbuffer \fakewords {100} {150} + +You can combine this feature with layers. We will now show a few applications +which may look like magic at first glance, but will become natural to your +repertoire once you have played with them. + +The next example moves the graphic to a layer associated with the (current) page. + +\startbuffer +\placefigure + [right,none] + {} + {\setlayer + [graphics] + {\bleed + [width=5cm,height=3cm,location=rb] + {\externalfigure[detcow][bleed]}}} +\stopbuffer + +\typebuffer \getbuffer \fakewords {100} {150} + +You can also predefine locations where graphics (or other content) needs to be +anchored. A direct call to anchor looks as follows: + +\starttyping +\placefigure + [left,none] + {} + {\anchor + [text-1] + [location=lt,hoffset=max,voffset=max] + [width=3cm,height=3cm,frame=on]% + {\externalfigure[detcow][width=5cm,frame=on]}} +\stoptyping + +This will anchor a graphic in one of the text layers, but at the cost of +specifying this in the document source. One way around this is to predefine +anchors. + +\startbuffer +\defineanchor[rightbottom][text-1][location=lt,hoffset=max,voffset=max] +\defineanchor[righttop] [text-1][location=lb,hoffset=max] +\defineanchor[leftbottom] [text-1][location=rt,voffset=max] +\defineanchor[lefttop] [text-1][location=rb] +\stopbuffer + +\startbuffer +\defineanchor[rightbottom][text-1][preset=rightbottom] +\defineanchor[righttop] [text-1][preset=righttop] +\defineanchor[leftbottom] [text-1][preset=leftbottom] +\defineanchor[lefttop] [text-1][preset=lefttop] +\stopbuffer + +\typebuffer \getbuffer + +We will apply this to a predefined float type. + +\startbuffer +\definefloat[myfigure][figure] +\setupfloat[myfigure][sidespaceafter=,sidespacebefore=] +\stopbuffer + +\typebuffer \getbuffer + +Our previous example can now be reduced to: + +\startbuffer +\placemyfigure + [left,none] + {} + {\anchor[rightbottom] + {\externalfigure[detcow][width=5cm,frame=on]}} +\stopbuffer + +\typebuffer \getbuffer \fakewords {100} {150} + +You can still specify dimensions and anchors can be combined with bleeding. Of +course this kind of mixed usage means that you need to have some feeling for what +these mechanisms do. + +\startbuffer +\placemyfigure + [left,none] + {} + {\anchor + [rightbottom] + [width=5cm,height=3cm,frame=on] + {\bleed + [width=5cm,height=3cm,location=l] + {\externalfigure[detcow][bleed]}}} +\stopbuffer + +\typebuffer \getbuffer \fakewords {100} {150} + +\startbuffer +\placemyfigure + [right,none] + {} + {\anchor + [rightbottom] + [width=5cm,height=3cm,frame=on] + {\bleed + [width=5cm,height=3cm,location=r] + {\externalfigure[detcow][bleed]}}} +\stopbuffer + +\typebuffer \getbuffer \fakewords {100} {150} + +\startbuffer +\placemyfigure + [left,none] + {} + {\anchor + [lefttop] + [width=3cm,height=3cm,frame=on] + {\externalfigure[detcow][width=5cm,frame=on]}} +\stopbuffer + +\typebuffer \getbuffer \fakewords {100} {150} + +\startbuffer +\placemyfigure + [left,none] + {} + {\anchor + [lefttop] + [width=3cm,height=3cm,frame=on] + [offset=.5cm] + {\externalfigure[detcow][width=5cm,frame=on]}} +\stopbuffer + +\typebuffer \getbuffer \fakewords {100} {150} + +\blank {\em Todo: parameter specifications of all those macros.} + +\stopchapter + +\stopcomponent diff --git a/doc/context/sources/general/manuals/details/details-floatingaround.tex b/doc/context/sources/general/manuals/details/details-floatingaround.tex new file mode 100644 index 000000000..11fe0601c --- /dev/null +++ b/doc/context/sources/general/manuals/details/details-floatingaround.tex @@ -0,0 +1,1137 @@ +% language=uk + +\environment details-environment + +\startcomponent details-floatingaround + +\startchapter[title={Floating around}] + +\index {floats} + +Graphics, tables and alike are often treated as floating bodies. This means that +when such a body does not fit on the current page, it will be moved to the next +one. In the examples we will use figures, but everything we demonstrate here +applies to all floats. + +A side float is a float which placement one way or another depends on the text +that follows it. In its simplest form, the text flows around it, for instance in: + +\startbuffer +\placefigure[left,none]{caption}{\framed[height=1cm]{graphic}} +\stopbuffer + +\typebuffer + +The first keyword of such a call is treated as a placement directive, so this +figure will be placed left. The \type {none} directive nils the caption. + +\getbuffer \fakewords{60}{80} + +When the figure does not fit on the page, a page break is issued. A figure can +span multiple paragraphs. When a next graphic is placed the previous figure will +be padded if needed. First an example of multiple paragraphs. + +\getbuffer \fakewords{30}{40} \par \fakewords{30}{40} + +Multiple floats in a row will lead to padding. The amount of padding is a +combination of empty lines and the normal white space following the float. The +visual quality of the result depends on the graphic itself. + +\start \tracesidefloatstrue + +\getbuffer \fakewords{30}{40} + +\getbuffer \fakewords{30}{40} \fakewords{30}{40} + +\stop + +Here we show the baseline of the first paragraph after the float as well as the +filler. The whitespace around a graphic also depends on the inter|-|paragraph +whitespace. As with many automated mechanisms, compromises are made. A one point +smaller figure may result in an extra empty line. + +Later we will demonstrate a lot of tuning options, but first we give a few more +examples. Most of the tuning options can be driven by keywords as well as +(global) settings. + +\startbuffer +\placefigure + [left,nonumber] + {caption} {\framed[height=1cm]{graphic}} +\stopbuffer + +\typebuffer + +The \type {nonumber} keyword suppresses the label and figure number. You can do +this for all figures with + +\starttyping +\setupcaption[figure][number=no] +\stoptyping + +The previous placement command results in the following side float. + +\getbuffer \fakewords{80}{100} + +Another handy keyword is \type {none}. + +\startbuffer +\placefigure + [left,none]{quoting knuth} + {\framed[height=1cm]{graphic}} +\stopbuffer + +\typebuffer \getbuffer \fakewords{80}{100} + +Control over spacing is exercised by means of the keywords \type {high}, \type +{low} and \type {fit}. + +\startbuffer +\placefigure + [left,none,high]{} + {\framed[height=1cm]{graphic}} +\stopbuffer + +\typebuffer \getbuffer \fakewords{80}{100} + +\startbuffer +\placefigure + [left,none,high,low]{} + {\framed[height=1cm]{graphic}} +\stopbuffer + +\typebuffer \getbuffer \fakewords{80}{100} + +\startbuffer +\placefigure + [left,none,fit]{} + {\framed[height=1cm]{graphic}} +\stopbuffer + +\typebuffer \getbuffer \fakewords{80}{100} + +In the examples so far, we saw additional spacing around the graphic. We will now +(for a while) disable the surrounding whitespace. + +\startbuffer +\setupfloat + [figure] + [sidespacebefore=none, + sidespaceafter=none] +\stopbuffer + +\typebuffer + +With these settings a simple left placement looks as follows. The top of the side +float aligns with the maximum height of a line. + +\start \getbuffer \tracesidefloatstrue + +\startbuffer +\placefigure + [left,none] + {} {\framed[height=1cm]{graphic}} +\stopbuffer + +\typebuffer \getbuffer \fakewords{30}{40} \par \stop + +You can change the alignment by setting the \type {sidealign} variable, for +instance: + +\starttyping +\setupfloat + [figure] + [sidealign=line] +\stoptyping + +The three keywords \type {height}, \type {line} and \type {depth} can also be +passed directly: + +\startbuffer +\placefigure + [left,none,height]{} + {\framed[height=1cm]{graphic}} +\stopbuffer + +\typebuffer + +The three alignments disable the spacing before the float and show up as follows. + +\bgroup \tracesidefloatstrue \getbuffer \fakewords{30}{40} \par \egroup + +\startbuffer +\placefigure + [left,none,line]{} + {\framed[height=1cm]{graphic}} +\stopbuffer + +\bgroup \tracesidefloatstrue \getbuffer \fakewords{30}{40} \par \egroup + +\startbuffer +\placefigure + [left,none,depth]{} + {\framed[height=1cm]{graphic}} +\stopbuffer + +\bgroup \tracesidefloatstrue \getbuffer \fakewords{30}{40} \par \egroup + +So far the floats took up space in the main text body area. In addition to the +\type {left} (or \type {right}) directive we can use \type {inner} or \type +{outer} to force left or right placement depending in the spread. + +Instead of spoiling paper in the text areas, we can use the margin and edges: +\type {leftmargin} and \type {leftedge}, \type {rightmargin} and \type +{rightedge}, but also \type {innermargin} and \type {outermargin}, \type +{inneredge} and \type {outeredge}. + +The next couple of pages we will highlight the margins and edges so that we can +see what happens. + +\setupbackgrounds [text] [leftedge] [background=color] +\setupbackgrounds [text] [rightedge] [background=color] +\setupbackgrounds [text] [leftmargin] [background=color] +\setupbackgrounds [text] [rightmargin] [background=color] + +\startbuffer +\placefigure + [leftmargin,none] + {} {\framed{!}} +\stopbuffer + +\typebuffer \getbuffer \fakewords{30}{40} + +\startbuffer +\placefigure + [leftmargin,none] + {} {\framed[width=1cm]{!}} +\stopbuffer + +\typebuffer \getbuffer \fakewords{30}{40} + +\startbuffer +\placefigure + [leftmargin,none] + {} {\framed[width=1.5cm]{!}} +\stopbuffer + +\typebuffer \getbuffer \fakewords{30}{40} + +The placement directives can be combined with setting distance and width +parameters, thereby not only opening a world of possibilities, but also creating +confusion. Therefore, we will illustrate these features by cloning floats. + +\startbuffer +\definefloat + [marginfigure] + [figure] + +\setupfloat + [marginfigure] + [leftmargindistance=-\leftmargintotal, + default={left,none,low}] +\stopbuffer + +\typebuffer \getbuffer + +The definition command clones figure into a new class of figures. There are two +ways to use such a float : + +\starttyping +\placefloat + [marginfigure] + {} {\framed[width=1.5cm]{!}} +\stoptyping + +or directly: + +\startbuffer +\placemarginfigure + {} {\framed[width=1.5cm]{!}} +\stopbuffer + +\typebuffer + +Both placement calls will result in a figure sticking into the margin. + +\getbuffer \fakewords{30}{40} + +By manipulating the margin distance, you can align graphics to vertical grid +lines, like the edge: + +\startbuffer +\definefloat + [edgefigure] + [figure] + +\setupfloat + [edgefigure] + [leftmargindistance=-\innercombitotal, + default={left,none,low,high}] +\stopbuffer + +\typebuffer \getbuffer + +The \type {\innercombitotal} is one of the many available dimensions. This +measure is the combined width of the margin and edge. + +\startbuffer +\placeedgefigure + {} {\framed[width=1.5cm]{!}} +\stopbuffer + +\typebuffer \getbuffer \fakewords{30}{40} + +\startbuffer +\placeedgefigure + {} {\framed[width=\innercombitotal]{!}} +\stopbuffer + +\typebuffer \getbuffer \fakewords{30}{40} + +You need to be aware of the fact that the margins and edges are not related to +the backspace and cut space settings. When you set up a layout, you need to think +of the right page as starting point. In a double sided layout, the margins are +swapped in the page composition stage. Unless you explicitly go to a left or +right page, you don't know if your left margin will be swapped or not. + +For this reason \CONTEXT\ provides the inner and outer margin|/|edge dimensions. +These are automatically synchronized when the float is constructed. So, if you +want to automatically adapt the float placement and width to the current left +margin in a double sided document, you can use the inner dimensions. + +\starttabulate[||||] +\NC dimension \NC left page + \NC right page \NC\NR +\NC \type{\outermarginwidth} \NC \type{\leftmarginwidth} + \NC \type{\rightmarginwidth} \NC\NR +\NC \type{\innermarginwidth} \NC \type{\rightmarginwidth} + \NC \type{\leftmarginwidth} \NC\NR +\NC \type{\outermargindistance}\NC \type{\leftmargindistance} + \NC \type{\rightmargindistance}\NC\NR +\NC \type{\innermargindistance}\NC \type{\rightmargindistance} + \NC \type{\leftmargindistance} \NC\NR +\stoptabulate + +Similar dimensions are available for the edges. You can save yourself some +calculations by using the following dimensions: + +\starttabulate[|||||] +\NC \type{\leftmargintotal} \NC left margin width \NC + \NC left margin distance \NC\NR +\NC \type{\rightmargintotal} \NC right margin width \NC + \NC right margin distance \NC\NR +\NC \type{\innermargintotal} \NC inner margin width \NC + \NC inner margin distance \NC\NR +\NC \type{\outermargintotal} \NC outer margin width \NC + \NC outer margin distance \NC\NR +\stoptabulate + +As you may expect, the edge totals are available as well, which leave a few more +totals, namely the combinations of margin and edge. + +\starttabulate[|||] +\NC \type{\leftsidetotal} \NC left margin width \NC + \NC left edge total \NC\NR +\NC \type{\rightsidetotal} \NC right margin width \NC + \NC right edge total \NC\NR +\TB +\NC \type{\innersidetotal} \NC inner margin width \NC + \NC inner edge total \NC\NR +\NC \type{\outersidetotal} \NC outer margin width \NC + \NC outer edge total \NC\NR +\TB +\NC \type{\leftcombitotal} \NC left margin total \NC + \NC left edge total \NC\NR +\NC \type{\rightcombitotal} \NC right margin total \NC + \NC right edge total \NC\NR +\TB +\NC \type{\innercombitotal} \NC inner margin total \NC + \NC inner edge total \NC\NR +\NC \type{\outercombitotal} \NC outer margin total \NC + \NC outer edge total \NC\NR +\stoptabulate + +Adaptive back- and cutspace dimensions are also available: + +\starttabulate[|||||] +\NC \type{\innerspacewidth} \NC adaptive backspace \NC\NR +\NC \type{\outerspacewidth} \NC adaptive cutspace \NC\NR +\stoptabulate + +There is one drawback in using the inner and outer dimensions: if you also change +the height of the float dynamically, you may end up in a kind of loop because a +page break may occur at a non||expected place. + +While negative values move float into the margin, positive values will move the +float into the text. It will be of no surprise that you can also set the right +margin distance. Keep in mind that this distance is not related to the text +margin, but to the float margin. + +\startbuffer +\setupfloat + [edgefigure] + [leftmargindistance=-\outercombitotal, + rightmargindistance=-\outercombitotal, + default={outer,none,low,high}] +\stopbuffer + +\typebuffer \getbuffer + +The locations \type {inner} and \type {outer} change with the left or right page. + +\startbuffer +\placeedgefigure + {} {\framed[width=\outercombitotal]{!}} +\stopbuffer + +\typebuffer \getbuffer \fakewords{30}{40} + +\startbuffer +\placeedgefigure + {} {\framed[width=8cm]{!}} +\stopbuffer + +\typebuffer \getbuffer \fakewords{30}{40} + +As a result of manipulating the floats margin settings, the side floats can start +in the margin (or edge). You should not confuse this with margin floats, i.e.\ +side floats that are explicitly placed in the margins. + +\startbuffer +\placefigure[leftmargin,none] + {} {\framed{!}} +\stopbuffer + +\typebuffer \getbuffer \fakewords{30}{40} + +\startbuffer +\placefigure[leftmargin,none] + {} {\framed[width=.5cm]{!}} +\stopbuffer + +\typebuffer \getbuffer \fakewords{30}{40} + +\startbuffer +\placefigure[leftmargin,none] + {} {\framed[width=1.5cm]{!}} +\stopbuffer + +\typebuffer \getbuffer \fakewords{30}{40} + +\startbuffer +\placefigure[leftmargin,none] + {} {\framed[width=5cm]{!}} +\stopbuffer + +\typebuffer \getbuffer \fakewords{30}{40} + +The margin side floats align to the margin and the edge floats to the edge. This +way you can create bleeding figures. + +\startbuffer +\placefigure[leftedge,none] + {} {\framed{!}} +\stopbuffer + +\typebuffer \getbuffer \fakewords{30}{40} + +There are situations where you don't know the dimensions in advance. In order to +prevent unwanted side effects, for instance part of a graphic disappearing +outside the page boundary, \CONTEXT\ provides a few options. The most crude one +is setting the \type {criterium}, as in: + +\starttyping +\setupfloat + [figure] + [criterium=.25\textwidth] +\stoptyping + +This will automatically turn figures that are wider than 25\% of the text width +into normal floats instead of side floats. But let's not fall back on that +feature now. + +You can use \type {maxwidth} and \type {minwidth} variables to control the +placement in more detail. The exact result depends on the settings of \type +{location}. By default we center, but you can set the location to \type {left} or +\type {right} to achieve a different alignment. + +\startbuffer +\definefloat + [midmarginfigure] + [figure] + +\setupfloat + [midmarginfigure] + [minwidth=\leftmarginwidth, + default={leftmargin,none}] +\stopbuffer + +\typebuffer \getbuffer + +You can use \type {maxwidth} and \type {minwidth} variables to control the +placement in more detail. The exact result depends on the settings of \type +{location}. By default we center, but you can set the location to \type {left} or +\type {right} to achieve a different alignment. + +\startbuffer +\placemidmarginfigure + {} {\framed[width=1.5cm]{!}} +\stopbuffer + +\typebuffer \getbuffer \fakewords{30}{40} + +The meaning of \type {maxwidth} depends on the kind of float. First we place a +left float with a width smaller than \type {maxwidth}. + +\start + +\startbuffer +\setupfloat[figure][maxwidth=2cm] +\stopbuffer + +\typebuffer \getbuffer + +\startbuffer +\placefigure[left,none]{}{\framed[width=1cm]{!}} +\stopbuffer + +\typebuffer \getbuffer \fakewords{30}{40} + +When the width exceeds the maxwidth, the float will be centered. This is because +we have no reference alignment point. + +\startbuffer +\placefigure[left,none]{}{\framed[width=5cm]{!}} +\stopbuffer + +\typebuffer \getbuffer \fakewords{30}{40} + +In margin floats, the \type {maxwidth} settings have a different result. First we +place a small graphic. + +\startbuffer +\setupfloat[figure][maxwidth=\leftmarginwidth] +\stopbuffer + +\typebuffer \getbuffer + +\startbuffer +\placefigure[leftmargin,none]{}{\framed[width=1cm]{!}} +\stopbuffer + +\typebuffer \getbuffer \fakewords{30}{40} + +Because the left and right margin of this document are the same |<|the edges +differ|>| we don't need to use inner and outer dimensions. + +\startbuffer +\setupfloat[figure][maxwidth=\leftmarginwidth] +\stopbuffer + +\typebuffer \getbuffer + +A wider than \type {maxwidth} graphic will behave like a mixture of a margin and +text side float. Watch how we align the float to the margin. + +\startbuffer +\placefigure[leftmargin,none]{}{\framed[width=5cm]{!}} +\stopbuffer + +\typebuffer \getbuffer \fakewords{30}{40} + +\stop + +Instead of setting the width you can give \type {hanging} a try. The next +examples demonstrate this. + +\startbuffer +\placefigure[leftmargin,hanging,none]{}{\framed[width=5cm]{!}} +\stopbuffer + +\typebuffer \getbuffer \fakewords{30}{40} + +\startbuffer +\placefigure[left,hanging,none]{}{\framed[width=5cm]{!}} +\stopbuffer + +\typebuffer \getbuffer \fakewords{30}{40} + +You can move down|/|up margin floats with the \type {\movesidefloat} macro. Such +shifts come in handy when you have multiple side floats near to each other. + +\startbuffer +\movesidefloat [+2*line] +\placemidmarginfigure {} {\framed{!}} +\stopbuffer + +\typebuffer \getbuffer \fakewords{30}{40} + +Given the default placement template, this is equivalent to the following +command. Watch out, a simple \type {line} has a different effect (alignment). + +\starttyping +\placemidmarginfigure + [leftmargin,none,+2*line] + {} {\framed{!}} +\stoptyping + +Another nice keyword is \type {long}: + +\startbuffer +\placefigure + [leftmargin,none,long] + {} {\framed[height=2cm,width=2cm]{!}} + +Watch how we move down. The effect is that we skip over the margin figure. + +\placefigure + [leftmargin,none] + {} {\framed[height=1cm,width=2cm]{!}} +\stopbuffer + +\typebuffer \getbuffer \fakewords{30}{40} + +\startbuffer +\placefigure + [leftmargin,none] + {} {\framed[height=2cm,width=2cm]{!}} + +Do we clash or not? + +\placefigure + [leftmargin,none] + {} {\framed[height=2cm,width=2cm]{!}} + +Did we clash or not? +\stopbuffer + +\typebuffer \getbuffer + +There are a few macros that can be of help with solving clashes in side floats: + +\starttabulate +\NC \tex {flushsidefloats} \NC + This macro moves down as much as is needed to separate the side floats of + each other. \NC \NR +\NC \tex {forgetsidefloats} \NC + this macro kind of forgets that a side float is in progress. \NC \NR +\stoptabulate + +Use these macros with care. If you change the dimensions of the graphic and|/|or +content involved, reconsider the use of these directives. + +The next couple of spreads we will demonstrate some example definitions. These +placements are taken from one of the styles we made for typesetting a series of +school math books which illustrations and tables all over the pages. + +First we fine tune the spacing around side floats and verbatim text. + +\startbuffer[setupa] +\setupfloats + [sidespacebefore=none, + sidespaceafter=depth] + +\setuptyping + [margin=] +\stopbuffer + +\typebuffer[setupa] + +The placements have rather verbose names. In this case the word \quote {edge} is +used to identify bleeding floats (with an cut||off margin of 3mm). The \quote +{text} floats are side floats positioned in the main text flow. + +\startbuffer[setupb] +\definefloat [marginfigure] [marginfigures] [figure] +\definefloat [middlemarginfigure] [middlemarginfigures] [figure] +\definefloat [middlefigure] [middlefigures] [figure] +\definefloat [textfigure] [textfigures] [figure] +\definefloat [leftfigure] [leftfigures] [figure] +\definefloat [rightfigure] [rightfigures] [figure] +\definefloat [bleedfigure] [bleedfigures] [figure] +\stopbuffer + +\typebuffer[setupa] + +Watch how we define fall backs for too wide content (\type +{criterium} as well as use \type {maxwidth} to manipulate +the placement of content that falls off the margins. + +The black rules are set up with: + +\startbuffer[setupc] +\setupblackrules[color=tred,depth=0pt,height=1.5cm] +\stopbuffer + +\typebuffer[setupc] + +\page[left] + +\startbuffer[series] + +\startbuffer +\setupfloat + [marginfigure] + [criterium=.5\textwidth, + maxwidth=\rightmarginwidth, + default={outermargin,none}] +\stopbuffer + +\getbuffer \typebuffer + +\startbuffer +\placemarginfigure{}{\blackrule[width=.25cm]} +\stopbuffer + +\getbuffer \typebuffer \flushsidefloats + +\startbuffer +\placemarginfigure{}{\blackrule[width=.5cm]} +\stopbuffer + +\getbuffer \typebuffer \flushsidefloats + +\startbuffer +\placemarginfigure{}{\blackrule[width=1cm]} +\stopbuffer + +\getbuffer \typebuffer \flushsidefloats + +\startbuffer +\placemarginfigure{}{\blackrule[width=2cm]} +\stopbuffer + +\getbuffer \typebuffer \flushsidefloats + +\startbuffer +\placemarginfigure{}{\blackrule[width=4cm]} +\stopbuffer + +\getbuffer \typebuffer \flushsidefloats + +\startbuffer +\placemarginfigure{}{\blackrule[width=8cm]} +\stopbuffer + +\getbuffer \typebuffer \flushsidefloats + +\startbuffer +\placemarginfigure{}{\blackrule[width=16cm]} +\stopbuffer + +\getbuffer \typebuffer \flushsidefloats + +\stopbuffer + +{\getbuffer[setupa,setupb,setupc,series]} \page +{\getbuffer[setupa,setupb,setupc,series]} \page + +\startbuffer[series] + +\startbuffer +\setupfloat + [middlemarginfigure] + [minwidth=\rightmarginwidth, + criterium=\backspace, + location=middle, + default={outermargin,none}] +\stopbuffer + +\getbuffer \typebuffer + +\startbuffer +\placemiddlemarginfigure{}{\blackrule[width=.25cm]} +\stopbuffer + +\getbuffer \typebuffer \flushsidefloats + +\startbuffer +\placemiddlemarginfigure{}{\blackrule[width=.5cm]} +\stopbuffer + +\getbuffer \typebuffer \flushsidefloats + +\startbuffer +\placemiddlemarginfigure{}{\blackrule[width=1cm]} +\stopbuffer + +\getbuffer \typebuffer \flushsidefloats + +\startbuffer +\placemiddlemarginfigure{}{\blackrule[width=2cm]} +\stopbuffer + +\getbuffer \typebuffer \flushsidefloats + +\startbuffer +\placemiddlemarginfigure{}{\blackrule[width=4cm]} +\stopbuffer + +\getbuffer \typebuffer \flushsidefloats + +\startbuffer +\placemiddlemarginfigure{}{\blackrule[width=8cm]} +\stopbuffer + +\getbuffer \typebuffer \flushsidefloats + +\startbuffer +\placemiddlemarginfigure{}{\blackrule[width=16cm]} +\stopbuffer + +\getbuffer \typebuffer \flushsidefloats + +\stopbuffer + +{\getbuffer[setupa,setupb,setupc,series]} \page +{\getbuffer[setupa,setupb,setupc,series]} \page + +\startbuffer[series] + +\startbuffer +\setupfloat + [middlefigure] + [default={here,none}] +\stopbuffer + +\getbuffer \typebuffer + +\startbuffer +\placemiddlefigure{}{\blackrule[width=.25cm]} +\stopbuffer + +\getbuffer \typebuffer + +\startbuffer +\placemiddlefigure{}{\blackrule[width=.5cm]} +\stopbuffer + +\getbuffer \typebuffer + +\startbuffer +\placemiddlefigure{}{\blackrule[width=1cm]} +\stopbuffer + +\getbuffer \typebuffer + +\startbuffer +\placemiddlefigure{}{\blackrule[width=2cm]} +\stopbuffer + +\getbuffer \typebuffer + +\startbuffer +\placemiddlefigure{}{\blackrule[width=4cm]} +\stopbuffer + +\getbuffer \typebuffer + +\startbuffer +\placemiddlefigure{}{\blackrule[width=8cm]} +\stopbuffer + +\getbuffer \typebuffer + +%\startbuffer +%\placemiddlefigure{}{\blackrule[width=16cm]} +%\stopbuffer +% +%\getbuffer \typebuffer + +\stopbuffer + +{\getbuffer[setupa,setupb,setupc,series]} \page +{\getbuffer[setupa,setupb,setupc,series]} \page + +\startbuffer[series] + +\startbuffer +\setupfloat + [textfigure] + [criterium=.5\textwidth, + default={outer,none}] +\stopbuffer + +\getbuffer \typebuffer + +\startbuffer +\placetextfigure{}{\blackrule[width=.25cm]} +\stopbuffer + +\getbuffer \typebuffer + +\startbuffer +\placetextfigure{}{\blackrule[width=.5cm]} +\stopbuffer + +\getbuffer \typebuffer + +\startbuffer +\placetextfigure{}{\blackrule[width=1cm]} +\stopbuffer + +\getbuffer \typebuffer + +\startbuffer +\placetextfigure{}{\blackrule[width=2cm]} +\stopbuffer + +\getbuffer \typebuffer + +\startbuffer +\placetextfigure{}{\blackrule[width=4cm]} +\stopbuffer + +\getbuffer \typebuffer + +\startbuffer +\placetextfigure{}{\blackrule[width=8cm]} +\stopbuffer + +\getbuffer \typebuffer + +\startbuffer +\placetextfigure{}{\blackrule[width=16cm]} +\stopbuffer + +\getbuffer \typebuffer + +\stopbuffer + +{\getbuffer[setupa,setupb,setupc,series]} \page +{\getbuffer[setupa,setupb,setupc,series]} \page + +\startbuffer[series] + +\startbuffer +\setupfloat + [leftfigure] + [criterium=.5\textwidth, + default={left,none}] +\stopbuffer + +\getbuffer \typebuffer + +\startbuffer +\placeleftfigure{}{\blackrule[width=.25cm]} +\stopbuffer + +\getbuffer \typebuffer \flushsidefloats + +\startbuffer +\placeleftfigure{}{\blackrule[width=.5cm]} +\stopbuffer + +\getbuffer \typebuffer \flushsidefloats + +\startbuffer +\placeleftfigure{}{\blackrule[width=1cm]} +\stopbuffer + +\getbuffer \typebuffer \flushsidefloats + +\startbuffer +\placeleftfigure{}{\blackrule[width=2cm]} +\stopbuffer + +\getbuffer \typebuffer \flushsidefloats + +\startbuffer +\placeleftfigure{}{\blackrule[width=4cm]} +\stopbuffer + +\getbuffer \typebuffer \flushsidefloats + +\startbuffer +\placeleftfigure{}{\blackrule[width=8cm]} +\stopbuffer + +\getbuffer \typebuffer \flushsidefloats + +\startbuffer +\placeleftfigure{}{\blackrule[width=16cm]} +\stopbuffer + +\getbuffer \typebuffer \flushsidefloats + +\stopbuffer + +{\getbuffer[setupa,setupb,setupc,series]} \page +{\getbuffer[setupa,setupb,setupc,series]} \page + +\startbuffer[series] + +\startbuffer +\setupfloat + [rightfigure] + [criterium=.5\textwidth, + default={right,none}] +\stopbuffer + +\getbuffer \typebuffer + +\startbuffer +\placerightfigure{}{\blackrule[width=.25cm]} +\stopbuffer + +\getbuffer \typebuffer \flushsidefloats + +\startbuffer +\placerightfigure{}{\blackrule[width=.5cm]} +\stopbuffer + +\getbuffer \typebuffer \flushsidefloats + +\startbuffer +\placerightfigure{}{\blackrule[width=1cm]} +\stopbuffer + +\getbuffer \typebuffer \flushsidefloats + +\startbuffer +\placerightfigure{}{\blackrule[width=2cm]} +\stopbuffer + +\getbuffer \typebuffer \flushsidefloats + +\startbuffer +\placerightfigure{}{\blackrule[width=4cm]} +\stopbuffer + +\getbuffer \typebuffer \flushsidefloats + +\startbuffer +\placerightfigure{}{\blackrule[width=8cm]} +\stopbuffer + +\getbuffer \typebuffer \flushsidefloats + +\startbuffer +\placerightfigure{}{\blackrule[width=16cm]} +\stopbuffer + +\getbuffer \typebuffer \flushsidefloats + +\stopbuffer + +{\getbuffer[setupa,setupb,setupc,series]} \page +{\getbuffer[setupa,setupb,setupc,series]} \page + +\startbuffer[series] + +\startbuffer +\setupfloat + [bleedfigure] + [criterium=.5\textwidth, + leftmargindistance=-1mm, + rightmargindistance=-1mm, + default={backspace,none}] +\stopbuffer + +\getbuffer \typebuffer + +\startbuffer +\placebleedfigure{}{\blackrule[width=.25cm]} +\stopbuffer + +\getbuffer \typebuffer \flushsidefloats + +\startbuffer +\placebleedfigure{}{\blackrule[width=.5cm]} +\stopbuffer + +\getbuffer \typebuffer \flushsidefloats + +\startbuffer +\placebleedfigure{}{\blackrule[width=1cm]} +\stopbuffer + +\getbuffer \typebuffer \flushsidefloats + +\startbuffer +\placebleedfigure{}{\blackrule[width=2cm]} +\stopbuffer + +\getbuffer \typebuffer \flushsidefloats + +\startbuffer +\placebleedfigure{}{\blackrule[width=4cm]} +\stopbuffer + +\getbuffer \typebuffer \flushsidefloats + +\startbuffer +\placebleedfigure{}{\blackrule[width=8cm]} +\stopbuffer + +\getbuffer \typebuffer \flushsidefloats + +\startbuffer +\placebleedfigure{}{\blackrule[width=16cm]} +\stopbuffer + +\getbuffer \typebuffer \flushsidefloats + +\stopbuffer + +{\getbuffer[setupa,setupb,setupc,series]} \page +{\getbuffer[setupa,setupb,setupc,series]} \page + +\startbuffer[series] + +\startbuffer +\setupfloat + [bleedfigure] + [criterium=.5\textwidth, + leftmargindistance=-1mm, + rightmargindistance=-1mm, + default={cutspace,none}] +\stopbuffer + +\getbuffer \typebuffer + +\startbuffer +\placebleedfigure{}{\blackrule[width=.25cm]} +\stopbuffer + +\getbuffer \typebuffer \flushsidefloats + +\startbuffer +\placebleedfigure{}{\blackrule[width=.5cm]} +\stopbuffer + +\getbuffer \typebuffer \flushsidefloats + +\startbuffer +\placebleedfigure{}{\blackrule[width=1cm]} +\stopbuffer + +\getbuffer \typebuffer \flushsidefloats + +\startbuffer +\placebleedfigure{}{\blackrule[width=2cm]} +\stopbuffer + +\getbuffer \typebuffer \flushsidefloats + +\startbuffer +\placebleedfigure{}{\blackrule[width=4cm]} +\stopbuffer + +\getbuffer \typebuffer \flushsidefloats + +\startbuffer +\placebleedfigure{}{\blackrule[width=8cm]} +\stopbuffer + +\getbuffer \typebuffer \flushsidefloats + +\startbuffer +\placebleedfigure{}{\blackrule[width=16cm]} +\stopbuffer + +\getbuffer \typebuffer \flushsidefloats + +\stopbuffer + +{\getbuffer[setupa,setupb,setupc,series]} \page +{\getbuffer[setupa,setupb,setupc,series]} \page + +\page + +\setupbackgrounds [text] [leftedge] [background=] +\setupbackgrounds [text] [rightedge] [background=] +\setupbackgrounds [text] [leftmargin] [background=] +\setupbackgrounds [text] [rightmargin] [background=] + +\stopchapter + +\stopcomponent diff --git a/doc/context/sources/general/manuals/details/details-frontpage.tex b/doc/context/sources/general/manuals/details/details-frontpage.tex new file mode 100644 index 000000000..0c7df22f5 --- /dev/null +++ b/doc/context/sources/general/manuals/details/details-frontpage.tex @@ -0,0 +1,43 @@ +% language=uk + +\environment details-environment + +\startcomponent details-frontpage + +\startpagemakeup[doublesided=no,pagestate=stop,page=no] + \startMPcode + StartPage ; + % todo: calculate p[3] from the text dimensions as now it's a gamble + path p[] ; picture q[] ; + p[1] := Page ; + p[2] := Page xscaled .60 shifted (.2PaperWidth,0) ; + p[3] := Page yscaled .22 shifted (0,.69PaperHeight) ; + q[1] := textext.raw("\color[white] {DETAILS}") xsized(.98PaperWidth) ; + q[2] := textext.raw("\color[white] {IT'S IN THE}") xsized(.98PaperWidth) ; + q[3] := textext.raw("\color[twhite]{\tt HANS HAGEN}") xsized(.60PaperWidth) ; + q[4] := textext.raw("\color[twhite]{\tt PRAGMA ADE}") xsized(.60PaperWidth) ; + q[5] := textext.raw("\color[twhite]{\tt HASSELT NL}") xsized(.60PaperWidth) ; + q[2] := q[2] shifted (0,- bbheight(q[2])) ; + q[3] := q[3] shifted (0,+1.5bbheight(q[3])) ; + q[5] := q[5] shifted (0,-1.5bbheight(q[5])) ; + fill p[1] withcolor \MPcolor{blue} ; % .5blue + fill p[2] withcolor \MPcolor{red} ; % .5red + fill p[3] withcolor \MPcolor{gray} withtransparency(1,.5) ; % .6white + draw q[1] shifted (.01PaperWidth,.7PaperHeight) ; + draw q[2] shifted (.01PaperWidth,.9PaperHeight) ; + draw q[3] shifted (.20PaperWidth,.2PaperHeight) ; + draw q[4] shifted (.20PaperWidth,.2PaperHeight) ; + draw q[5] shifted (.20PaperWidth,.2PaperHeight) ; + StopPage ; + \stopMPcode +\stoppagemakeup + +\startpagemakeup[doublesided=no,pagestate=stop,page=no] + \startMPcode + StartPage ; + fill Page withcolor \MPcolor{blue} ; % .5blue ; + StopPage ; + \stopMPcode +\stoppagemakeup + +\stopcomponent diff --git a/doc/context/sources/general/manuals/details/details-gridtrickery.tex b/doc/context/sources/general/manuals/details/details-gridtrickery.tex new file mode 100644 index 000000000..f37c7bd4b --- /dev/null +++ b/doc/context/sources/general/manuals/details/details-gridtrickery.tex @@ -0,0 +1,161 @@ +% language=uk + +\environment details-environment + +\startcomponent details-gridtrickery + +\startchapter[title={Grid trickery}] + +In this manual we pay quite some words on ways to snap your content on a grid. +When dealing with grids, we often run into conflicting situations where we have +to make the best of it. Let's again deal with an aspect of graphics. + +One of the strong points of \TEX\ is that it can deal with graphics +automatically, which means that you seldom have to tweak dimensions or placements +unless \unknown\ you're dealing with grids. In that case you need to make sure +that the height of graphics consistently match the height of lines (or multiples +of lines). It is for this purpose that the graphic inclusion macro has a \type +{grid} entry. + +We will illustrate its usage using a dedicated figure class where we have set the +space between figure and caption to zero. + +\startbuffer +\definefloat[tightfigure][tightfigures][figure] +\setupcaption[tightfigure][inbetween=] +\stopbuffer + +\typebuffer \getbuffer + +The \type {grid} parameter controls rounding of the height of a graphic in the +following way: + +\starttabulate + +\NC \type {yes} \NC safe rounding to an equal number of lines \NC \NR +\NC \type {fit} \NC tight rounding to an equal number of lines \NC \NR +\NC \type {height} \NC same as \type {yes} but incremented by linedepth \NC \NR +\stoptabulate + +On the next pages we demonstrate the effects of these settings. At the bottom of +a page we show the placement commands. On the last pages we've hidden the +captions with: + +\starttyping +\setupfloat[tightfigure][default={here,none}] +\stoptyping + +As you will notice, the \type {height} option is handy when the caption is +positioned directly under the graphic. + +\start \page + +\fakewords{20}{30} \placetightfigure{}{\externalfigure[dummy][width=.5\hsize,lines=1.3,grid=yes]} +\fakewords{20}{30} \placetightfigure{}{\externalfigure[dummy][width=.5\hsize,lines=1.4,grid=yes]} +\fakewords{20}{30} \placetightfigure{}{\externalfigure[dummy][width=.5\hsize,lines=1.5,grid=yes]} +\fakewords{20}{30} \placetightfigure{}{\externalfigure[dummy][width=.5\hsize,lines=1.6,grid=yes]} +\fakewords{20}{30} \placetightfigure{}{\externalfigure[dummy][width=.5\hsize,lines=1.7,grid=yes]} +\fakewords{20}{30} + +\starttyping +\placetightfigure{}{\externalfigure[dummy][lines=1.3,grid=yes]} +\placetightfigure{}{\externalfigure[dummy][lines=1.4,grid=yes]} +\placetightfigure{}{\externalfigure[dummy][lines=1.5,grid=yes]} +\placetightfigure{}{\externalfigure[dummy][lines=1.6,grid=yes]} +\placetightfigure{}{\externalfigure[dummy][lines=1.7,grid=yes]} +\stoptyping + +\page + +\fakewords{20}{30} \placetightfigure{}{\externalfigure[dummy][width=.5\hsize,lines=1.3,grid=fit]} +\fakewords{20}{30} \placetightfigure{}{\externalfigure[dummy][width=.5\hsize,lines=1.4,grid=fit]} +\fakewords{20}{30} \placetightfigure{}{\externalfigure[dummy][width=.5\hsize,lines=1.5,grid=fit]} +\fakewords{20}{30} \placetightfigure{}{\externalfigure[dummy][width=.5\hsize,lines=1.6,grid=fit]} +\fakewords{20}{30} \placetightfigure{}{\externalfigure[dummy][width=.5\hsize,lines=1.7,grid=fit]} +\fakewords{20}{30} + +\starttyping +\placetightfigure{}{\externalfigure[dummy][lines=1.3,grid=fit]} +\placetightfigure{}{\externalfigure[dummy][lines=1.4,grid=fit]} +\placetightfigure{}{\externalfigure[dummy][lines=1.5,grid=fit]} +\placetightfigure{}{\externalfigure[dummy][lines=1.6,grid=fit]} +\placetightfigure{}{\externalfigure[dummy][lines=1.7,grid=fit]} +\stoptyping + +\page + +\fakewords{20}{30} \placetightfigure{}{\externalfigure[dummy][width=.5\hsize,lines=1.3,grid=height]} +\fakewords{20}{30} \placetightfigure{}{\externalfigure[dummy][width=.5\hsize,lines=1.4,grid=height]} +\fakewords{20}{30} \placetightfigure{}{\externalfigure[dummy][width=.5\hsize,lines=1.5,grid=height]} +\fakewords{20}{30} \placetightfigure{}{\externalfigure[dummy][width=.5\hsize,lines=1.6,grid=height]} +\fakewords{20}{30} \placetightfigure{}{\externalfigure[dummy][width=.5\hsize,lines=1.7,grid=height]} +\fakewords{20}{30} + +\starttyping +\placetightfigure{}{\externalfigure[dummy][lines=1.3,grid=height]} +\placetightfigure{}{\externalfigure[dummy][lines=1.4,grid=height]} +\placetightfigure{}{\externalfigure[dummy][lines=1.5,grid=height]} +\placetightfigure{}{\externalfigure[dummy][lines=1.6,grid=height]} +\placetightfigure{}{\externalfigure[dummy][lines=1.7,grid=height]} +\stoptyping + +\page + +\setupfloat[tightfigure][default={here,none}] + +\fakewords{20}{30} \placetightfigure{}{\externalfigure[dummy][width=.5\hsize,lines=1.3,grid=yes]} +\fakewords{20}{30} \placetightfigure{}{\externalfigure[dummy][width=.5\hsize,lines=1.4,grid=yes]} +\fakewords{20}{30} \placetightfigure{}{\externalfigure[dummy][width=.5\hsize,lines=1.5,grid=yes]} +\fakewords{20}{30} \placetightfigure{}{\externalfigure[dummy][width=.5\hsize,lines=1.6,grid=yes]} +\fakewords{20}{30} \placetightfigure{}{\externalfigure[dummy][width=.5\hsize,lines=1.7,grid=yes]} +\fakewords{20}{30} + +\starttyping +\placetightfigure{}{\externalfigure[dummy][lines=1.3,grid=yes]} +\placetightfigure{}{\externalfigure[dummy][lines=1.4,grid=yes]} +\placetightfigure{}{\externalfigure[dummy][lines=1.5,grid=yes]} +\placetightfigure{}{\externalfigure[dummy][lines=1.6,grid=yes]} +\placetightfigure{}{\externalfigure[dummy][lines=1.7,grid=yes]} +\stoptyping + +\page + +\fakewords{20}{30} \placetightfigure{}{\externalfigure[dummy][width=.5\hsize,lines=1.3,grid=fit]} +\fakewords{20}{30} \placetightfigure{}{\externalfigure[dummy][width=.5\hsize,lines=1.4,grid=fit]} +\fakewords{20}{30} \placetightfigure{}{\externalfigure[dummy][width=.5\hsize,lines=1.5,grid=fit]} +\fakewords{20}{30} \placetightfigure{}{\externalfigure[dummy][width=.5\hsize,lines=1.6,grid=fit]} +\fakewords{20}{30} \placetightfigure{}{\externalfigure[dummy][width=.5\hsize,lines=1.7,grid=fit]} +\fakewords{20}{30} + +\starttyping +\placetightfigure{}{\externalfigure[dummy][lines=1.3,grid=fit]} +\placetightfigure{}{\externalfigure[dummy][lines=1.4,grid=fit]} +\placetightfigure{}{\externalfigure[dummy][lines=1.5,grid=fit]} +\placetightfigure{}{\externalfigure[dummy][lines=1.6,grid=fit]} +\placetightfigure{}{\externalfigure[dummy][lines=1.7,grid=fit]} +\stoptyping + +\page + +\fakewords{20}{30} \placetightfigure{}{\externalfigure[dummy][width=.5\hsize,lines=1.3,grid=height]} +\fakewords{20}{30} \placetightfigure{}{\externalfigure[dummy][width=.5\hsize,lines=1.4,grid=height]} +\fakewords{20}{30} \placetightfigure{}{\externalfigure[dummy][width=.5\hsize,lines=1.5,grid=height]} +\fakewords{20}{30} \placetightfigure{}{\externalfigure[dummy][width=.5\hsize,lines=1.6,grid=height]} +\fakewords{20}{30} \placetightfigure{}{\externalfigure[dummy][width=.5\hsize,lines=1.7,grid=height]} +\fakewords{20}{30} + +\starttyping +\placetightfigure{}{\externalfigure[dummy][lines=1.3,grid=height]} +\placetightfigure{}{\externalfigure[dummy][lines=1.4,grid=height]} +\placetightfigure{}{\externalfigure[dummy][lines=1.5,grid=height]} +\placetightfigure{}{\externalfigure[dummy][lines=1.6,grid=height]} +\placetightfigure{}{\externalfigure[dummy][lines=1.7,grid=height]} +\stoptyping + +\page \stop + +\stopchapter + +\page + +\stopcomponent diff --git a/doc/context/sources/general/manuals/details/details-index.tex b/doc/context/sources/general/manuals/details/details-index.tex new file mode 100644 index 000000000..9b6940f0b --- /dev/null +++ b/doc/context/sources/general/manuals/details/details-index.tex @@ -0,0 +1,13 @@ +% language=uk + +\environment details-environment + +\startcomponent details-index + +\startchapter[title={Document index}] + +\placeregister[index] + +\stopchapter + +\stopcomponent diff --git a/doc/context/sources/general/manuals/details/details-introduction.tex b/doc/context/sources/general/manuals/details/details-introduction.tex new file mode 100644 index 000000000..8e64ba4ed --- /dev/null +++ b/doc/context/sources/general/manuals/details/details-introduction.tex @@ -0,0 +1,42 @@ +% language=uk + +\startcomponent details-introduction + +\environment details-environment + +\starttitle[title={Introduction}] + +On the \CONTEXT\ mailing list, occasionally a user asks if we can post a complete +document with the associated style. One reason for not honouring this request is +that we want users to cook up their own styles. Besides that, there are a couple +of styles in the regular \CONTEXT\ distribution. + +When browsing through this document, a \CONTEXT\ user may wonder what style was +used to achieve its look and feel. We hope that while reading the text and +playing with the examples, the reader will accomplish the skills to define more +than just simple layouts. + +This document is not easy reading. Occasionally we spend some time explaining +features not described in other manuals. The design of this document is to a +large extent determined by its purpose, and as a result not always functional. +For instance, we typeset on a grid which doesn't look too good. Also the order of +presenting features, tips and tricks is kind of random and unstructured. The idea +is that the visual effects will draw you to the right trick. Also, if you really +want to benefit from these features, there is no way but to read the whole story. + +In spite of all its shortcomings, I hope that you enjoy reading this (yet +unfinished) manual. Keep in mind that this manual is far from finished. + +\blank + +\startlines +Hans Hagen +Hasselt NL +\blank +2002\high{+} MkII +2015\high{+} MkIV +\stoplines + +\stoptitle + +\stopcomponent diff --git a/doc/context/sources/general/manuals/details/details-ornaments.tex b/doc/context/sources/general/manuals/details/details-ornaments.tex new file mode 100644 index 000000000..35d23c8b4 --- /dev/null +++ b/doc/context/sources/general/manuals/details/details-ornaments.tex @@ -0,0 +1,585 @@ +% language=uk + +\environment details-environment + +\startcomponent details-ornaments + +\startchapter[title={Ornaments everywhere}] + +The background mechanisms present in \CONTEXT\ have evolved over time and with +computers becoming faster, you can expect new functionality to show up and +existing functionality to start using this technology. A simple background +consist of a colored area. Many commands accept settings like: + +\starttyping +...[background=color,backgroundcolor=red,backgroundoffset=3pt] +\stoptyping + +Instead of such an area you can define one or more so called +overlays: + +\starttyping +\defineoverlay[one][...] +\defineoverlay[two][...] + +...[background={one,two}] +\stoptyping + +The name overlay comes from the fact that you stack them on top of each other. A +special overlay is \type {foreground}, and deep down in \CONTEXT\ there are more +predefined overlays. + +In the \METAFUN\ manual you will find example of usage, so here we stick to a +simple code snippet for testing this functionality: + +\startbuffer +\defineoverlay[one][\green A] +\defineoverlay[two][\red B] + +\framed[background=one] {1} +\framed[background={one,two}] {1---2} +\stopbuffer + +\typebuffer + +The rather ugly result is: + +\startlinecorrection +\hbox{\getbuffer} +\stoplinecorrection + +You can construct overlays by using \TEX\ boxing primitives or commands like +\type {\framed}. Alternatively you can use another mechanism: layers. Layers +collect content and flush that when asked, for instance when an overlay is +constructed. Layers can be independent of a page, or bound to a specific page +number, left or right hand pages. Here we look at independent layers. + +All these mechanisms are fine tuned for cooperating with the output routine (the +part of \TEX\ that deals with composing pages) and are well interact quite well +with \METAPOST\ graphics. Details of usage and tricks are revealed in this manual +as well as in styles that come with \CONTEXT. In this chapter we will apply +layers to graphics. For this we need a few setups, like: + +\starttyping +\setupbackgrounds + [page] + [background=pagegraphics] +\stoptyping + +Here we have set up the page background to use an overlay called \type +{pagegraphics}. However, instead of an overlay, we will use a layer. This layer +will collect content that goes into the page background. Whenever a layer is +defined, an overlay is automatically defined as well. + +\startbuffer +\definelayer + [pagegraphics] + [x=-2mm, + y=-2mm, + width=\paperwidth, + height=\paperheight] +\stopbuffer + +\typebuffer \getbuffer + +When you fill a layer with content, you can influence the placement with the +\type {x} and \type {y} parameters as well as \type {hoffset} and \type +{voffset}, whichever you prefer. The reference point and alignment are set with +\type {corner} and \type {location}. + +Live can be made easier by using presets, especially for our intended usage. The +following presets are predefined. + +\startbuffer +\definelayerpreset + [lefttop] [corner={left,top}, location={right,bottom}] +\definelayerpreset + [righttop] [corner={right,top}, location={left,bottom}] +\definelayerpreset + [leftbottom] [corner={left,bottom}, location={right,top}] +\definelayerpreset + [rightbottom] [corner={right,bottom},location={left,top}] +\stopbuffer + +\typebuffer \getbuffer + +Because for this layer we have also preset the \type {x} and \type {y}, those +corners are laying a few millimeters outside the page area. We have preset the +size as well, otherwise all corners would end up in the top left corner. + +We will now fill this layer. Because the layer is hooked into the page, it will +be flushed when the page is constructed. After the page is written to the output +file, the layer is emptied, unless its \type {state} is set to \type {repeat}. + +\startbuffer +\setlayer [extras] [preset=lefttop] {\externalfigure[hacker]} +\setlayer [extras] [preset=righttop] {\externalfigure[hacker]} +\setlayer [extras] [preset=leftbottom] {\externalfigure[hacker]} +\setlayer [extras] [preset=rightbottom] {\externalfigure[hacker]} +\stopbuffer + +\testpage[5] \typebuffer \getbuffer + +Once you got the picture of layering, you will start using this mechanism for all +kind of tasks. Instead of putting layers in a background, you can also directly +place them, by using one of the two (equivalent) commands: + +\starttyping +\composedlayer{identifier} +\placelayer[identifier] +\stoptyping + +Layer are quite convenient for defining title pages, colophons, and special +section heads, especially in combination with \type {\framed}. + +On top of the layer mechanism we have build a few more mechanisms, like +ornaments. You can use ornaments to annotate graphics in such a way that the +dimensions stay unchanged. + +\startbuffer +\defineornament + [affiliation] + [rotation=90,corner={right,bottom},location={right,top}, + hoffset=-.25ex] + [frame=on,background=color,backgroundcolor=red,offset=0pt] +\stopbuffer + +\typebuffer \getbuffer + +The negative offset will overlay the text outside the graphic. The meaning of the +sign of coordinates and offsets depends on the corner. \in {Figure} [fig:affi-1] +shows the result. We have put the reference point in the right bottom corner. The +ornament is anchored at the right top corner of the dot you can picture at the +reference point. The ornament is shifted .25ex outwards. + +\starttyping +\placefigure + {} + {\affiliation{graphic}{\externalfigure[hacker][width=3cm]}} +\stoptyping + +\placefigure + [here] [fig:affi-1] {Number 1} + {\affiliation{graphic}{\externalfigure[hacker][width=3cm]}} + +There are two ways to handle the placement. Alternative \type {a} will change the +dimensions of the graphic according to the size of the ornament, while +alternative \type {b} acts as a pure overlay. In \in {figure} [fig:affi-2] the +ornament is not taken into account when calculating the dimensions of the +graphic. This is often the preferred placement, because this way the (often +small) ornament will not it will not spoil visual alignment of similar graphics. + +\startbuffer +\defineornament + [affiliation] + [rotation=90,corner={right,bottom},location={right,top}, + hoffset=-.25ex,alternative=b] + [frame=on,background=color,backgroundcolor=red,offset=0pt] +\stopbuffer + +\typebuffer \getbuffer + +\placefigure + [here] [fig:affi-2] {Number 2} + {\affiliation{graphic}{\externalfigure[hacker][width=3cm]}} + +A positive offset will place the ornament on top of the graphic (see \in {figure} +[fig:affi-3]). + +\startbuffer +\defineornament + [affiliation] + [rotation=90,corner={right,bottom},location={left,top}, + hoffset=.25ex,voffset=.25ex,alternative=a] + [background=color,style=\ss\tfxx,backgroundcolor=white,offset=0pt] +\stopbuffer + +\typebuffer \getbuffer + +\placefigure + [here] [fig:affi-3] {Number 3} + {\affiliation{graphic}{\externalfigure[hacker][width=3cm]}} + +You need to play a bit with this mechanism in order to get a feeling for what the +parameters do. + +\startbuffer +\defineornament + [affiliation] + [rotation=90,corner={right,bottom},location={left,top}, + hoffset=.25ex,voffset=.25ex,alternative=b] + [background=color,style=\ss\tfxx,backgroundcolor=white,offset=0pt] +\stopbuffer + +\typebuffer \getbuffer + +\placefigure + [here] [fig:affi-4] {Number 4} + {\affiliation{graphic}{\externalfigure[hacker][width=3cm]}} + +Because the text is normally typeset quite small, you'd better use a font that +can be scaled down a lot. + +\startbuffer +\definefont[AffiliationFont][Sans sa .25] + +\defineornament + [SomeAffiliation] + [rotation=90,corner={right,bottom},location={right,top}, + hoffset=-.125ex,alternative=b] + [style=AffiliationFont,offset=0pt] +\stopbuffer + +\typebuffer \getbuffer + +This affiliation is used as: + +\startbuffer +\placefigure + {Affiliations normally are typeset pretty small.} + {\SomeAffiliation + {author: Hester De Weert} + {\externalfigure[hacker]}} +\stopbuffer + +\typebuffer \getbuffer + +Ornaments are implemented in terms of layers and collectors. A few examples +demonstrate how these can be used. + +\startbuffer +\layeredtext + [corner={right,bottom},location={left,top}] + [background=color,backgroundcolor=white,offset=0pt] + {graphic} + {\externalfigure[hacker][width=3cm]} +\stopbuffer + +\typebuffer \startlinecorrection \getbuffer \stoplinecorrection + +\startbuffer +\layeredtext + [rotation=90,corner={right,bottom},location={right,top}] + [frame=on,offset=0pt] + {graphic} + {\externalfigure[hacker][width=3cm]} +\stopbuffer + +\typebuffer \startlinecorrection \getbuffer \stoplinecorrection + +\startbuffer +\layeredtext + [rotation=90,corner={left,bottom},location={left,top}] + [frame=on,offset=0pt] + {graphic} + {\externalfigure[hacker][width=3cm]} +\stopbuffer + +\typebuffer \startlinecorrection \getbuffer \stoplinecorrection + +\startbuffer +\collectedtext + [corner={right,bottom},location={left,top}] + [background=color,backgroundcolor=white,offset=0pt] + {graphic} + {\externalfigure[hacker][width=3cm]} +\stopbuffer + +\typebuffer \startlinecorrection \getbuffer \stoplinecorrection + +\startbuffer +\collectedtext + [rotation=90,corner={right,bottom},location={right,top}] + [frame=on,offset=0pt] + {graphic} + {\externalfigure[hacker][width=3cm]} +\stopbuffer + +\typebuffer \startlinecorrection \getbuffer \stoplinecorrection + +\startbuffer +\collectedtext + [rotation=90,corner={left,bottom},location={left,top}] + [frame=on,offset=0pt] + {graphic} + {\externalfigure[hacker][width=3cm]} +\stopbuffer + +\typebuffer \startlinecorrection \getbuffer \stoplinecorrection + +There are several methods to construct title pages, headers, and other +compositions. Of course there are the low level box constructors like \type +{\hbox}, \type {\vbox} and positioning primitives like \type {\hskip}, \type +{\hfill} and alike. + +Another option is to fall back on the low level box macros in the \CONTEXT\ +support file \type {supp-box} or the higher level \type {\framed} macro. You can +use \type {\framed} nested and by cleverly using the offsets and dimensions you +can do a lot. + +Layers are another means. You can or instance construct a title page in the +following way: + +\starttyping +\definelayer + [titlepage] + [width=\textwidth, + height=\textheight] + +\setlayer + [titlepage] + [preset=righttop,location={left,bottom},y=1cm,x=1cm] + {\definedfont[Regular at 60pt]Welcome} + +\setlayer + [titlepage] + [preset=rightbottom,location={right,top},y=2cm,x=2cm] + {\definedfont[Regular at 30pt]By Me} +\stoptyping + +This just fills the layer. Placement is done with: + +\starttyping +\startstandardmakeup + \flushlayer[titlepage] +\stopstandardmakeup +\stoptyping + +or alternatively: + +\starttyping +\setupbackgrounds[text][background=titlepage] +\startstandardmakeup \stopstandardmakeup +\setupbackgrounds[text][background=] +\stoptyping + +Another way to collect content is to use a collector. A collector starts out +empty with: + +\startbuffer +\definecollector[test][state=repeat] +\stopbuffer + +\typebuffer \getbuffer + +We can now stepwise fill this collector. For educational purposes we've turn of +tracing so that you can see what the anchor points. + +\startbuffer +\setcollector[test] + [location={right,bottom}] + {\externalfigure[detcow][frame=on,width=3cm]} +\stopbuffer + +\typebuffer {\traceboxplacementtrue \getbuffer} + +\startlinecorrection[blank] \flushcollector[test] \stoplinecorrection + +\startbuffer +\setcollector[test] + [corner={right,bottom},location={left,top}] + {\framed[background=color,backgroundcolor=tyellow]{this is a cow}} +\stopbuffer + +\typebuffer {\traceboxplacementtrue \getbuffer} + +\startlinecorrection[blank] \flushcollector[test] \stoplinecorrection + +\startbuffer +\setcollector[test] + [corner={right,bottom},location={right,bottom}] + {\framed[background=color,backgroundcolor=tblue]{that's for sure}} +\stopbuffer + +\typebuffer {\traceboxplacementtrue \getbuffer} + +\startlinecorrection[blank] \flushcollector[test] \stoplinecorrection + +\startbuffer +\setcollector[test] + [corner={left,top},location={left,top}] + {\framed[background=color,backgroundcolor=tgreen]{a dutch cow}} +\stopbuffer + +\typebuffer {\traceboxplacementtrue \getbuffer} + +\startlinecorrection[blank] \flushcollector[test] \stoplinecorrection + +\startbuffer +\setcollector[test] + [corner=middle, + location=middle] + {\framed[background=color,backgroundcolor=tred]{nearly done}} +\stopbuffer + +\typebuffer {\traceboxplacementtrue \getbuffer} + +\startlinecorrection[blank] \flushcollector[test] \stoplinecorrection + +In addition to the parameters shown here, you can also provide additional ones: +\type {x}, \type {y}, \type {offset}, \type {hoffset} and \type {voffset} for +positioning and \type {rotation} for (as expected) rotating the content in steps +of 90 degrees. As with layers, the coordinates and offsets can be used +intermixed. + +\startbuffer +\setcollector[test] + [hoffset=4cm, + voffset=-1cm, + corner=middle, + location=middle] + {\framed{now}} +\stopbuffer + +\typebuffer {\traceboxplacementtrue \getbuffer} + +\startlinecorrection[blank] \flushcollector[test] \stoplinecorrection + +We can show the intermediate results because we have set the state of this +collector to repeat. In this case you need to erase the content manually, using: + +\startbuffer +\resetcollector[test] +\stopbuffer + +\typebuffer \getbuffer + +The chapter titles of this document are (as usual in a \CONTEXT\ document) +typeset by the \type {\chapter} macro. When thinking about implementing a non +standard head, those familiar with \CONTEXT's head macros will probably first +think of using one of the hooks, like: + +\starttyping +\setuphead[chapter][command=\MyChapterHead] +\stoptyping + +Here we have followed a different approach. First we set up the chapter head. The +\type {empty} directive instructs \CONTEXT\ not to place the head itself, but +still to include the associated data in the text stream. This means that we will +not see a chapter title, but that there will be an entry in the table of +contents, that references will be set up, that so called marks will be available, +etc. + +\starttyping +\setuphead + [chapter] + [placehead=empty, + header=chapter, + style=\BigText, + numberstyle=\BigNumber] +\stoptyping + +The \type {header} parameters instructs the head handler to mark this page as +special with regards to header texts. This text is set up as follows: + +\starttyping +\definetext + [chapter] + [header] + [\setups{chapter}] + [] +\stoptyping + +The setups are just series of typesetting instructions. For the sake of +readability, we have split them up. + +\starttyping +\startsetups chapter + \setups[chapter:title] + \setups[chapter:number] + \setups[chapter:finish] +\stopsetups +\stoptyping + +The setups will use a dedicated layer for the chapter title: + +\starttyping +\definelayer + [chapter] + [width=\dimexpr\makeupwidth+\cutspace\relax, + height=\headerheight] +\stoptyping + +The following code uses a macro \type {\setlayerframed}. This is a combination +between \type {\setlayer} and \type {\framed}. We use two placement macros to +typeset the title and number. When doing so, we need to take care of both +numbered chapters and unnumbered titles. + +\starttyping +\startsetups chapter:title + + \setlayerframed + [chapter] + [x=\dimexpr\makeupwidth+\cutspace\relax,location={left,bottom}] + [height=\headerheight, + foregroundcolor=white, + background=color, + backgroundcolor=blue, + frame=off, + offset=none, + align={right,lohi}] + {\hbox spread .5\cutspace + {\hss + \doiftextelse{\placeheadtext[chapter]}% + {\placeheadtext[chapter]}% + {\placeheadtext[title]}% + \hss}\space + \vskip.5cm} + +\stopsetups +\stoptyping + +Definitions like these may look complicated but in practice you will construct +them piece|-|wise. + +\starttyping +\startsetups chapter:number + + \setlayerframed + [chapter] + [x=\dimexpr\makeupwidth+\cutspace\relax, + y=\vsize, + location={left,bottom}] + [width=\dimexpr\cutspace-\rightmargindistance\relax, + height=\dimexpr\cutspace-\rightmargindistance\relax, + foregroundcolor=white, + background=color, + backgroundcolor=red, + frame=off, + offset=none, + align={middle,lohi}] + {\hbox to \hsize + {\hskip.5cm\hss + \doifmode{*bodypart}{\placeheadnumber[chapter]}% + \hss}} + +\stopsetups +\stoptyping + +The finishing touch is just a dummy frame with the chapter background. We could +have used the header text background instead. + +\starttyping +\startsetups chapter:finish + + \framed + [width=\makeupwidth, + height=\headerheight, + background=chapter, + frame=off] + {} + +\stopsetups +\stoptyping + +As the title of this manual suggests: it's in the details. Most of our time is +spent in optimizing spacing issues. If you're designing the layout yourself, for +a large part you can fall back on the consistent spacing provided by \TEX, i.e.\ +think in terms of \type {em}'s, \type {ex}'s and fractions or multiples of \type +{\bodyfontsize}, as well as base you're dimensions on those provided by the +layout. When dealing with translating a \DTP\ layout into something \TEX, +definitions like the above will often look more messy. + +\stopchapter + +\stopcomponent diff --git a/doc/context/sources/general/manuals/details/details-pseudocolumns.tex b/doc/context/sources/general/manuals/details/details-pseudocolumns.tex new file mode 100644 index 000000000..f30ffaeab --- /dev/null +++ b/doc/context/sources/general/manuals/details/details-pseudocolumns.tex @@ -0,0 +1,155 @@ +% language=uk + +\environment details-environment + +\startcomponent details-pseudocolumns + +\start \page[right] + +\definelayout + [temp] + [columndistance=12pt, + columns=3] + +\setuplayout + [temp] + +\startchapter[title={Pseudo columns}] + +\index {grid snapping+columns} +\index {pseudo columns} +\index {layers} +\index {backgrounds} + +In desk top publishing applications the grid is pretty dominant in defining +layouts. On the other hand, \TEX\ is pretty good defining layouts in terms of +relative dimensions. This means that mapping a desk top publishing layout into +its \TEX\ (or \CONTEXT) counterpart takes some effort. For what it's worth, +personally I don't like grids that much, specially not in complex documents, +unless one makes sure that all elements are suitable sized for the grid used. + +We not only have to deal with vertical grids, but also with horizontal ones. Here +we focus on the second category. When implementing designs, it is best first to +look into the normal page layout areas. For most documents these are sufficient, +but occasionally we need a more detailed approach. + +When playing with grids, you need to make sure that grid snapping is turned on. +It helps if you turn on the grid so that you can see where things end up. When a +horizontal grid is defined, gray vertical rules show their boundaries. + +\starttyping +\setuplayout[grid=yes] \showgrid +\stoptyping + +The \type {\setuplayout} command has a few settings that have to do with so +called pseudo columns. These are in no sense related to multi|-|column +typesetting and only play a role in placing text on specific locations. + +\starttyping +\setuplayout + [columndistance=12pt, + columns=3] +\stoptyping + +You can use \type {\layoutcolumnoffset} for positioning relative to the left +boundary of the running text: + +\startbuffer +\hskip\layoutcolumnoffset{2}{\red Text positioned in column 2!} +\stopbuffer + +\typebuffer \getbuffer + +This mechanism is actually meant to ease the definition of complicated (title) +pages where many text and graphic elements need to be anchored at well defined +places. The layer mechanism is the most natural candidate for this. + +\startbuffer +\definelayer [text] \setupbackgrounds [text] [background=text] +\stopbuffer + +\typebuffer + +When anchoring elements on a layer, you can specify absolute positions using the +\type {x} and \type {y} keys but grid based positioning is possible with the +\type {column} and \type {line} keys. We need to pass \type {grid} as location +specifier. + +\startbuffer +\setlayer[text][column=1,line=48,location=grid]{these are not} +\setlayer[text][column=2,line=47,location=grid]{real columns} +\setlayer[text][column=3,line=48,location=grid]{but fake ones} +\stopbuffer + +\typebuffer \getbuffer + +\page + +\startbuffer +\setlayer [text] [column=1,line=32,location=grid] + {\ruledvtop {\hsize\layoutcolumnwidth + \style[regular:3]{nitty\par gritty}}} + +\setlayer [text] [column=2,line=37,location=grid] + {\ruledvbox {\hsize\layoutcolumnwidth + \style[regular:3]{nitty\par gritty}}} + +\setlayer [text] [column=3,line=42,location=grid] + {\ruledvcenter {\hsize\layoutcolumnwidth + \style[regular:3]{nitty\par gritty}}} +\stopbuffer + +\typebuffer \getbuffer + +The data that goes into the layer is collected and flushed as soon as \TEX\ +builds the page. The buffer associated to the layer is then ready for new data +(for the next page). + +In this example, you can see that the baselines of the boxes (here visualized by +dashed rules) are put at the specified lines. You can use the \TEX\ box commands +\type {\vbox}, \type {\vtop} and \type {\vcenter} to specify where the main +baseline of the box content is positioned (at the top or bottom line, or +centered). + +\startbuffer +\setlayer + [text] + [column=2,line=48,x=\layoutcolumnwidth,location=left] + {\framed + [background=color,backgroundcolor=red, + foregroundstyle=regular:2,foregroundcolor=white, + frame=off] + {Why ain't I framed?}} +\stopbuffer + +\typebuffer \getbuffer + +\page + +On the previous page we demonstrated a more complicated call to \type {\setlayer} +and more features will be introduced in later chapters. We position the framed +text in column~2 and at line~48. In addition we shift the text over the pseudo +column width, i.e. we position the text at the right of the column. The location +specifier aligns the text left from the point of positioning. + +When we have set up the pseudo columns, we have access to a couple of variables: + +\starttabulate[|l|l|l|] +\NC \type {\layoutcolumns} \NC counter \NC number of columns \NC \NR +\NC \type {\layoutlines} \NC counter \NC number of gridlines \NC \NR +\NC \type {\layoutcolumnwidth} \NC dimension \NC width of one column \NC \NR +\NC \type {\layoutcolumnoffset{n}} \NC macro \NC position of column n \NC \NR +\stoptabulate + +This is typically a feature that has been there for quite a while but that I forget +about. It's probably because I never have to use grids myself. + +In the examples before we used some predefined (font) styles: + +\typebuffer[regular:sizes] + +\page \setuplayout[reset] \stop + +\stopchapter + +\stopcomponent diff --git a/doc/context/sources/general/manuals/details/details-snappingheads.tex b/doc/context/sources/general/manuals/details/details-snappingheads.tex new file mode 100644 index 000000000..26f4dfbc4 --- /dev/null +++ b/doc/context/sources/general/manuals/details/details-snappingheads.tex @@ -0,0 +1,276 @@ +% language=uk + +\environment details-environment + +\startcomponent details-snappingheads + +\startchapter[title={Snapping heads}] + +The grid snapper in \MKIV\ is quite different from the one in \MKII. For not too +complex layouts the old grid snapper was quite ok, but the new one should be a +bit more robust. In the old situation the running text was assumed to fit on the +grid and the normal baseline skip should do the job in combination with the grid +aware spacing features and placement mechanisms like tables and figures. + +Snapping on a fixed grid is sort of counter intuitive in \TEX\ because it has an a +advanced spacing model with glue. Publishers however love grids so we do need to +support it. Of course when complex layouts are involved in a later stage of +document preparation the grid is often abandoned. This manual uses the grid but I +personally never use the grid. There are better ways to make your document look +good and often a grid snapped document doesn't look that great anyway, because +all elements should somehow fit in multiples of the line height. + +The \MKIV\ snapper does more analysis and therefore can compensate for the more +nasty cases. Of course it can still fail but we hope to fix those cases when we +run into them. Grids are controlled by keywords or a combination of them. + +\starttabulate[|tCT{blue}||] +\NC none \NC don't enlarge \NC \NR +\NC halfline \NC enlarge by halfline/halfline \NC \NR +\NC line \NC enlarge by line/line \NC \NR +\NC strut \NC enlarge by ht/dp (default) \NC \NR +\NC first \NC align to top line \NC \NR +\NC last \NC align to bottom line \NC \NR +\NC mindepth \NC round depth down \NC \NR +\NC maxdepth \NC round depth up \NC \NR +\NC minheight \NC round height down \NC \NR +\NC maxheight \NC round height up \NC \NR +\NC local \NC use local interline space \NC \NR +\NC offset:-3tp \NC vertical shift within box \NC \NR +\NC bottom:lines \NC \NC \NR +\NC top:lines \NC \NC \NR +\NC box \NC centers a box rounded upwards (box:.5 -> tolerance) \NC \NR +\NC min \NC centers a box rounded downwards \NC \NR +\NC max \NC centers a box rounded upwards \NC \NR +\stoptabulate + +We combine these directives in so called grid options: + +\starttyping +\definegridsnapping [normal] [maxheight,maxdepth,strut] +\definegridsnapping [standard] [maxheight,maxdepth,strut] +\definegridsnapping [yes] [maxheight,maxdepth,strut] + +\definegridsnapping [strict] [maxdepth:0.8,maxheight:0.8,strut] +\definegridsnapping [tolerant] [maxdepth:1.2,maxheight:1.2,strut] +\definegridsnapping [math] [maxdepth:1.05,maxheight:1.05,strut] + +\definegridsnapping [top] [minheight,maxdepth,strut] +\definegridsnapping [bottom] [maxheight,mindepth,strut] +\definegridsnapping [both] [minheight,mindepth,strut] + +\definegridsnapping [broad] [maxheight,maxdepth,strut,0.8] +\definegridsnapping [fit] [maxheight,maxdepth,strut,1.2] + +\definegridsnapping [first] [first] +\definegridsnapping [last] [last] +\definegridsnapping [high] [minheight,maxdepth,none] +\definegridsnapping [one] [minheight,mindepth] +\definegridsnapping [low] [maxheight,mindepth,none] +\definegridsnapping [none] [none] +\definegridsnapping [line] [line] +\definegridsnapping [strut] [strut] +\definegridsnapping [box] [box] +\definegridsnapping [min] [min] +\definegridsnapping [max] [max] + +\definegridsnapping [middle] [maxheight,maxdepth] +\stoptyping + +As you can see, keys like \type {maxdepth} can take a criterium as extra detail, +separated by a colon. These options look obscure and often you need to trial and +error a bit to get what you want. This is no real problem because most cases are +handles automatically. Only headings and structuring elements that exceed a +line height might need some treatment. For instance you might want to be more +tolerant for (fractions of) a point overflow or when you know that always a blank +follows you can decide to limit the height of some element to a line. Some of +the options, like \type {math} and \type {middle} are used internally. + +On the next pages we show how the \type {maxheight} and \type {maxdepth} +fractions work on a sample line. + +\page + +\bgroup + \page + \enabledirectives[visualizers.fraction=.5] + \dostepwiserecurse {0} {10} {1} { + \edef\one{\ifnum#1=10 10\else0.#1\fi} + \dostepwiserecurse {0} {10} {1} { + \edef\two{\ifnum##1=10 10\else0.##1\fi} + \definegridsnapping [test:\one:\two][maxdepth:\one,maxheight:\two,strut] + \par + \blackrule[height=1pt,depth=1pt,width=\textwidth,color=green] + \par + \par + \snaptogrid[test:\one:\two] + \ruledhbox{\backgroundline[red]{\white\bf maxdepth:\one,maxheight:\two}} + \par + } + } + \par + \blackrule[height=1pt,depth=1pt,width=\textwidth,color=green] + \par + \page + \enabledirectives[visualizers.fraction] +\egroup + +Next we show some of the options in action. For practical reasons we start a new +page each time. The sample is input as: + +\startbuffer +\bf none \par +\bfb \hskip2cm none \par +\bfd \hskip6cm none \par +\bf test \par +\bfb \hskip2cm test \par +\bfd \hskip6cm test \par +\bf grid \par +\bfb \hskip2cm grid \par +\bfd \hskip6cm grid \par +\bf \strut strut \par +\bfb \hskip2cm \strut strut \par +\bfd \hskip6cm \strut strut \par +\bfb \hskip2cm \setstrut \strut setstrut \par +\bfd \hskip6cm \setstrut \strut setstrut \par +\stopbuffer + +\typebuffer + +\unexpanded\def\SampleGrid#1% + {\page + \section{Grid snapping method \quotation{#1}} + This is just a line to start with but next we % + show what method \type {#1} does. \par + \start + \setuplayout[grid=#1] % the demo value + \showstruts + \getbuffer + \stop + And here we end the demo. + \setuplayout[grid=yes] % the document default + \page} + +\SampleGrid{normal} +\SampleGrid{strict} +\SampleGrid{tolerant} +\SampleGrid{top} +\SampleGrid{bottom} +\SampleGrid{both} +\SampleGrid{broad} +\SampleGrid{fit} +\SampleGrid{first} +\SampleGrid{last} +\SampleGrid{high} +\SampleGrid{one} +\SampleGrid{low} +\SampleGrid{none} +\SampleGrid{line} +\SampleGrid{strut} +\SampleGrid{box} +\SampleGrid{min} +\SampleGrid{max} +\SampleGrid{middle} + +We now come to the topic of this chapter: snapping heads. The problem with +section heads is that they often exceed the line height. Even worse, they can +be more than one line high. + +The next pages show some ways to control snapping around heads. The result can be +confusing, even when we use a font that we assume behaves like a regular style. +For instance in Latin Modern the bold style has larger heights and depths than +the regular style and even 0.1pt can force the snapper to add a line. The +examples use that font. + +The grid option of \type {setuphead} normally takes one keyword that refers to +the local snapper. However, the result gets then snapped again. This is because +the local snapper can use a different line height. Historically the local snapper is +the default but you can force global snapping by prefixing with the \type +{global} keyword. The next table summarizes the ways you can control snapping: + +\starttabulate +\NC \type {(nothing)} \NC local snapping plus global snapping \NC \NR +\NC \type {local} \NC local snapping plus global snapping \NC \NR +\NC \type {foo} \NC local \type {foo} snapping cf.\ font style plus global snapping \NC \NR +\NC \type {local:foo} \NC local \type {foo} snapping cf.\ font style plus global snapping \NC \NR +\NC \type {global} \NC global snapping \NC \NR +\NC \type {global:foo} \NC global \type {foo} snapping \NC \NR +\stoptabulate + +\startbuffer[demo] +\setuppapersize + [A5][A5] + +\setuplayout + [grid=yes, + width=middle, + height=middle, + backspace=1cm, + topspace=2mm, + lines=38, + bottomspace=2mm, + footer=0cm, + header=4mm, + headerdistance=5mm] + +\definehead + [MyHead] + [subsubsubject] + [style=\tf, + textstyle=, + numberstyle=, + before=, + after=] + +\showgrid + +\starttext + +\starttexdefinition TestHead #1 + \page + \setupheadertexts[\type{#1}] + \setuphead[MyHead][grid={#1},style=\tf,interlinespace=] + \MyHead{some head 1.1} + \hskip1cm line following 1.1 + \MyHead{some head 1.2} + \hskip1cm line following 1.2 + \MyHead{some head 1.3a\par some head 1.3b} + \hskip1cm line following 1.3 + \setuphead[MyHead][grid={#1},style=\bf,interlinespace=] + \MyHead{some head 2.1} + \hskip1cm line following 2.1 + \MyHead{some head 2.2} + \hskip1cm line following 2.2 + \MyHead{some head 2.3a\par some head 2.3b} + \hskip1cm line following 2.3 + \setuphead[MyHead][grid=,style=\bf,interlinespace=4ex] + \MyHead{some head 3.1} + \hskip1cm line following 3.1 + \MyHead{some head 3.2} + \hskip1cm line following 3.2 + \MyHead{some head 3.3a\par some head 3.3b} + \hskip1cm line following 3.3 + \setuphead[MyHead][grid={#1},style=\bfb,interlinespace=] + \MyHead{some head 4.1} + \hskip1cm line following 4.1 + \MyHead{some head 4.2} + \hskip1cm line following 4.2 + \page +\stoptexdefinition + +\TestHead{yes} +\TestHead{tolerant} +\TestHead{global:tolerant} + +\stoptext +\stopbuffer + +\typebuffer + +\placefigure[page]{}{\typesetbuffer[demo][page=1,background=color,backgroundcolor=white,width=\textwidth]} +\placefigure[page]{}{\typesetbuffer[demo][page=2,background=color,backgroundcolor=white,width=\textwidth]} +\placefigure[page]{}{\typesetbuffer[demo][page=3,background=color,backgroundcolor=white,width=\textwidth]} + +\stopchapter + +\stopcomponent diff --git a/doc/context/sources/general/manuals/details/details-textbackgrounds.tex b/doc/context/sources/general/manuals/details/details-textbackgrounds.tex new file mode 100644 index 000000000..0f3962fff --- /dev/null +++ b/doc/context/sources/general/manuals/details/details-textbackgrounds.tex @@ -0,0 +1,687 @@ +% language=uk + +\environment details-environment + +\startcomponent details-textbackgrounds + +\start \setuphead [chapter] [after=] \startchapter[title={Backgrounds behind text}] + +\startbuffer[setup-a] +\definetextbackground + [intro] + [backgroundcolor=infogray, + backgroundoffset=.25cm, + frame=off, + location=paragraph, + color=red] +\stopbuffer + +\startbuffer[setup-b] +\definetextbackground + [subintro] + [backgroundcolor=textgray, + backgroundoffset=0pt, + frame=off, + location=text, + color=blue] +\stopbuffer + +\startbuffer[demo-a] +\starttextbackground[intro] +A rather common way to draw attention to a passage, is to add a +background. In this chapter we will therefore discuss how to enhance your +document with \starttextbackground [subintro] those colorful areas that either +or not follow the shape of your paragraph. \stoptextbackground\ Be +warned: this chapter has so many backgrounds that you might start to +dislike them. +\stoptextbackground +\stopbuffer + +\getbuffer[setup-a,setup-b,demo-a] + +\blank + +In the previous paragraph we demonstrated two important features of the +background handler: you can nest backgrounds and backgrounds can be tight or +wide. Features like this will often be used in combination with others, like +special section headers. The raw coding of the previous paragraph is therefore +not representative. + +\typebuffer[demo-a] + +The outer background commands is defined as follows: + +\typebuffer[setup-a] + +Here, the \type {paragraph} option ensures that the background covers the width +of the body text. The inner background is defined in a similar way, but this time +we choose \type {text} location. + +\typebuffer[setup-b] + +In this document we use protruding characters (hanging punctuation) so we've +chosen a rather large offset, one that also matches the rest of the page design. + +Those who are familiar with the way \TEX\ works will probably see what problems +can occur with backgrounds like this. What happens for instance when we cross +page boundaries, and how will more complicated paragraph shapes be handled? + +The current implementation tries to handle page breaks and paragraph shapes as +good as possible. This works well in normal one||column mode as well as in +columns. + +\startbuffer[setup-c] +\definetextbackground [A] [backgroundcolor=infogray] +\definetextbackground [B] [backgroundcolor=textgray] + +\setuptextbackground + [backgroundoffset=0pt, + offset=0pt, + frame=off, + location=text] +\stopbuffer + +\getbuffer[setup-c] + +\startbuffer[demo-b] +\placefigure[left]{}{\externalfigure[detcow][width=2cm]} + +\starttextbackground [A] + In this example, the paragraph shape is determined by the graphic placed + left of the text. + \starttextbackground [B] + This feature is implemented using the \type {\hangindent} and \type + {\hangafter} primitives, which means that we need to keep track of + their state. In addition, we need to handle the indentation directives + \type {\leftskip}, \type {\rightskip} and \type {\parindent}. + \stoptextbackground\ + Because backgrounds end up in a different background overlay, nesting + them is no problem, and it is even possible to move them to the front + and back, as we will demonstrate later on. While the mechanism discussed + here will always be improved when we find border cases, the fundaments + it is built upon are quite stable. +\stoptextbackground +\stopbuffer + +{\setupalign[nothanging]\getbuffer[demo-b]\par} + +\typebuffer[demo-b] + +The backgrounds were defined as: + +\typebuffer[setup-c] + +\startbuffer[setup-d] +\setuptextbackground [B] [backgroundcolor=darkgray,level=+2] +\stopbuffer + +{\setupalign[nothanging]\getbuffer[setup-d,demo-b]\par} + +This time we moved the inner background a few levels up. By default they reside +at \type {level=-1}. This way, by using a non transparent color, we can hide +information. + +\typebuffer[setup-d] + +Unless you mess around too much with boxes, backgrounds work as expected in most +situations. According to the Merriam||Webster on the authors laptop: + +\startbuffer +\starttabulate[|l|p|l|] +\NC background \NC \starttextbackground [A] the part of a + painting representing what lies behind objects is the + \starttextbackground [B] foreground \stoptextbackground + \stoptextbackground \NC one \NC \NR +\TB [halfline] +\NC foreground \NC \starttextbackground [A] the part of a + scene or representation that is nearest to and in front + of the \starttextbackground [B] spectator + \stoptextbackground \stoptextbackground \NC two \NC \NR +\TB [halfline] +\NC spectator \NC \starttextbackground [A] one who looks + on or watches \stoptextbackground \NC three \NC \NR +\stoptabulate +\stopbuffer + +\getbuffer + +This is coded similar to normal running text. A table like this is in a way still +part of the text flow. As floating body (see \in {table} [tab:back]) it can +virtually end up everywhere. We add a frame to make clear where the boundaries are. + +\start + + \setupfloat + [table] + [frame=on,framecolor=red,rulethickness=1pt] + + \placetable + [here] [tab:back] + {} {\hsize.75\textwidth\getbuffer} + + \definefloat + [mytable] + [table] + + \setupfloat + [mytable] + [leftmargindistance=-\innermargintotal] + + \placemytable + [left,high,low] + [tab:back-m] + {} + {\hsize.5\textwidth\getbuffer} + + Keeping track of the state of a paragraph in a table in combination with + background is not entirely trivial. The current implementation evolved from + less clever ones and, unless you start doing complicated box manipulations + with the float content, works quite well. One reason why we made backgrounds + work in tables (and especially floating tables) is that is was needed for + typesetting books for primary and secundary education. In there, we want to + be able to hide the answers that students are supposed to fill in. + + \flushsidefloats + +\stop + +In \in {figure} [fig:columns:1] you can see an advanced example of backgrounds +running over columns. If you look carefully, you will notice that the background +depends on the kind of background at hand: + +\startitemize[n,packed] +\item the text starts and flows on +\item the text flows on (or stands alone) +\item the text flows on and ends +\stopitemize + +This information is available when you want to draw your own backgrounds. Here +the graphic was defined as follows: + +\startplacefigure [reference=fig:columns:1] + \startcombination[4*1] + {\externalfigure[back-4.pdf][page=1,width=\distributedhsize\textwidth\emwidth4]}{Page 1} + {\externalfigure[back-4.pdf][page=2,width=\distributedhsize\textwidth\emwidth4]}{Page 2} + {\externalfigure[back-4.pdf][page=3,width=\distributedhsize\textwidth\emwidth4]}{Page 3} + {\externalfigure[back-4.pdf][page=4,width=\distributedhsize\textwidth\emwidth4]}{Page 4} + \stopcombination +\stopplacefigure + +\starttyping +\startuseMPgraphic{mpos:par:color} + for i=1 upto nofmultipars : + fill multipars[i] withcolor + if multikind[i]="single" : "darkgray" ; + elseif multikind[i]="first" : "red" ; + elseif multikind[i]="middle" : "green" ; + elseif multikind[i]="last" : "blue" ; + else : "black" ; + fi ; + endfor ; +\stopuseMPgraphic +\stoptyping + +This graphic is hooked into the background setup by setting the \type {mp} +variable. + +\starttyping +\definetextbackground + [shade] + [location=paragraph, + mp=mpos:par:color, + before=\blank, + after=\blank] +\stoptyping + +A variant is the following. This time we use a shade: + +\starttyping +\startuseMPgraphic{mpos:par:columnset:shade} + numeric h ; + for i=1 upto nofmultipars : + h := bbheight(p) ; + if multikind[i] = "single" : + fill multipars[i] topenlarged -.5h + withshademethod "linear" + withshadedirection shadedup + withcolor boxfillcolor shadedinto .8white ; + fill multipars[i] bottomenlarged -.5h + withshademethod "linear" + withshadedirection shadedup + withcolor .8white shadedinto boxfillcolor ; + elseif multikind[i] = "first" : + fill multipars[i] + withshademethod "linear" + withshadedirection shadedup + withcolor boxfillcolor shadedinto .8white ; + elseif multikind[i] = "middle" : + fill multipars[i] topenlarged -.5h + withshademethod "linear" + withshadedirection shadedup + withcolor boxfillcolor shadedinto .8white ; + fill multipars[i] bottomenlarged -.5h + withshademethod "linear" + withshadedirection shadedup + withcolor .8white shadedinto boxfillcolor ; + elseif multikind[i] = "last" : + fill multipars[i] + withshademethod "linear" + withshadedirection shadedup + withcolor .8white shadedinto boxfillcolor ; + fi ; + endfor ; +\stopuseMPgraphic +\stoptyping + +When we hook it into the background we get \in {figure} [fig:columns:2] as result: + +\starttyping +\definetextbackground + [shade] + [location=paragraph, + backgroundcolor=shadecolor, + mp=mpos:par:columnset:shade, + before=\blank, + after=\blank] +\stoptyping + +\startplacefigure [reference=fig:columns:2] + \startcombination[4*1] + {\externalfigure[back-5.pdf][page=1,width=\distributedhsize\textwidth\emwidth4]}{Page 1} + {\externalfigure[back-5.pdf][page=2,width=\distributedhsize\textwidth\emwidth4]}{Page 2} + {\externalfigure[back-5.pdf][page=3,width=\distributedhsize\textwidth\emwidth4]}{Page 3} + {\externalfigure[back-5.pdf][page=4,width=\distributedhsize\textwidth\emwidth4]}{Page 4} + \stopcombination +\stopplacefigure + +The complexity of the backgrounds mechanism is partly due to the fact that we +want to use arbitrary \METAPOST\ code to render the background. For instance, we +want to have a proper shape so that not only the filled shape but also the drawn +shape comes out right. You can compare this to a glyph in a font: when rendered +filled the outline can be anything as it will not be drawn but when we use the +outline we can run into overlaps and such. Where glyphs can use the odd|-|even +filling methods, background can only use that for simple cases. + +When a background is rectangular it's all quite easy but as soon as some holes +occur we need to do more work. Holes can be the result of a image placed next to +the running text, or an image flushed at a page break or in the middle of a +background. Paragraph shapes are another example. Backgrounds can cross page +boundaries too. Yet another property is nesting and in such cases the shape is +a bit more complex as we cross lines partially. + +In \MKII\ the background mechanism already was quite useable but it had some +limitations. Calculating the background was mostly delegated to \METAPOST\ which +is reasonable. In \MKIV\ some work is delegated to \LUA\ instead but that doesn't +mean that the code is cleaner or easier to understand. So, to summarize, there +are several cases that we need to take into account, like: + +\startitemize + \startitem + A background can run behind a paragraph in which case the start is + leftmost and end rightmost. In this case inserts (like floats) have to be + dealt with after the shape has been calculated. + \stopitem + \startitem + A background can be in|-|line (the \type {text} location variant) in + which case we need to follow the paragraph shape, if set. In that case we + have a mix of calculating the background shape and afterwards + compensating for inserts. + \stopitem + \startitem + A third case is tabulation and tables where we have dedicated regions to + deal with. When these float we need to make sure that the backgrounds are + adapted to the where they end up. + \stopitem + \startitem + Yet another case is in columns, where we hape multiple regions to deal + with. + \stopitem + \startitem + As mentioned, floats need special treatment and they can be part of the + page flow but also end up left or right of the text (either or not + shifted) but also in the margins, edges, back- or cutspace. Their + placement influences the way backgrounds are calculated so additional + information needs to travel with them. + \stopitem + +\stopitemize + +We distinguish between a paragraph background, which runs between the left and right skip +areas and a text background which follows a shape. In \in {figure} [fig:columns:3] we see a +test case with several such shapes. + +\startplacefigure [reference=fig:columns:3] + \startcombination[4*3] + {\externalfigure[back-2.pdf][page=1, width=\distributedhsize\textwidth\emwidth4]}{Page 1} + {\externalfigure[back-2.pdf][page=2, width=\distributedhsize\textwidth\emwidth4]}{Page 2} + {\externalfigure[back-2.pdf][page=3, width=\distributedhsize\textwidth\emwidth4]}{Page 3} + {\externalfigure[back-2.pdf][page=4, width=\distributedhsize\textwidth\emwidth4]}{Page 4} + {\externalfigure[back-2.pdf][page=5, width=\distributedhsize\textwidth\emwidth4]}{Page 5} + {\externalfigure[back-2.pdf][page=6, width=\distributedhsize\textwidth\emwidth4]}{Page 6} + {\externalfigure[back-2.pdf][page=7, width=\distributedhsize\textwidth\emwidth4]}{Page 7} + {\externalfigure[back-2.pdf][page=8, width=\distributedhsize\textwidth\emwidth4]}{Page 8} + {\externalfigure[back-2.pdf][page=9, width=\distributedhsize\textwidth\emwidth4]}{Page 9} + {\externalfigure[back-2.pdf][page=10,width=\distributedhsize\textwidth\emwidth4]}{Page 10} + {\externalfigure[back-2.pdf][page=11,width=\distributedhsize\textwidth\emwidth4]}{Page 11} + {\externalfigure[back-2.pdf][page=12,width=\distributedhsize\textwidth\emwidth4]}{Page 12} + \stopcombination +\stopplacefigure + +In the case of side floats the following cases occur. Of course multiple such +cases can follow each order so in practice we have to deal with an accumulation. + +\startlinecorrection[blank] +\startMPcode + linejoin := linecap := butt ; + + numeric u ; u := 1mm ; + numeric lw ; lw := u/2 ; + + pickup pencircle scaled 2lw ; + + def example (expr n) (text t) (text l) = + path b ; b := boundingbox image ( + for i=t : draw ( 0u,i*2u) -- (20u,i*2u) ; endfor ; + for i=l : draw ( 0u,i*2u) -- (20u,i*2u) ; endfor ; + ) ; + picture p ; p := image ( + for i=t : draw ( 0u,i*2u) -- (20u,i*2u) ; endfor ; + for i=l : draw (11u,i*2u) -- (20u,i*2u) ; endfor ; + ) ; + setbounds p to b ; + path q ; q := unitsquare xysized(10u,10u) shifted (0,4u) ; + draw image ( + fill boundingbox p leftenlarged -lw rightenlarged -lw withcolor "blue" ; + draw p withcolor .5white ; + fill q withcolor "red" ; + draw textext("\bf " & decimal n) shifted (center q) withcolor white ; + ) shifted ((n-1)*30u,0) ; + enddef ; + + example (1) (1) (2,3,4) ; + example (2) (1,8) (2,3,4,5,6,7) ; + example (3) (8) (5,6,7) ; + example (4) () (3,4,5,6) ; + + currentpicture := currentpicture ysized(3*LineHeight- StrutDepth) ; + +\stopMPcode +\stoplinecorrection + +As often in \TEX\ coming up with a solution is not a the problem but interference +is. You can cook up a solution for one case that fails in another. Backgrounds +fall into this category, as do side floats. In the next pages we will demonstrate +a few cases. In practice you can probably always come up with something that +works out well, but in an automated workflow (like unattended \XML\ to \PDF\ +conversion) you can best play safe. We show some examples on the next pages. + +\blank + +\definetextbackground + [demobg] + [backgroundcolor=blue, + color=white, + frame=off, + location=paragraph] + +\setupfloatcaption + [color=black] + +\definesimulatewords + [demo] + [n=50, + m=\simulatewordsparameter{n}, + min=1, + max=5, + color=text, + line=yes, + random=100] + +\startbuffer +\placefigure + [left] + {case 1} + {\blackrule[width=12cm,height=1cm,color=red]} +\simulatewords[demo][n=10] +\starttextbackground[demobg] + \simulatewords[demo][n=30] +\stoptextbackground +\flushsidefloats + +\blank + +\starttextbackground[demobg] + \simulatewords[demo][n=40] + \placefigure + [left] + {case 2} + {\blackrule[width=12cm,height=1cm,color=red]} + \simulatewords[demo][n=40] +\stoptextbackground +\flushsidefloats + +\blank + +\placefigure + [left] + {case 3} + {\blackrule[width=4cm,height=15mm,color=red]} +\starttextbackground[demobg] + \simulatewords[demo][n=40] +\stoptextbackground +\simulatewords[demo][n=40] +\flushsidefloats + +\blank + +\simulatewords[demo][n=35] +\placefigure + [left] + {case 4} + {\blackrule[width=4cm,height=1cm,color=red]} +\simulatewords[demo][n=20] +\starttextbackground[demobg] + \simulatewords[demo][n=25] +\stoptextbackground +\simulatewords[demo][n=40] +\flushsidefloats + +\blank + +\stopbuffer + +\start \setupwhitespace[none] \getbuffer \stop \blank + +The previous examples were typeset with: + +\typebuffer + +Regular (page flow) floats are a different story. Here we have the problem that a +float might be postpones because there is no room on the current page and they +are moved forward (which is why they're called float). Again we show some +examples. + +% \page + +\startbuffer[sample] +One problem introduced by the internet is that one can view music online. Well, +it's actually not really a problem as it is fun to do, but it does interfere with +development of code: one can enter distraction mode quite easily. +\stopbuffer + +\startbuffer +\starttextbackground[demobg] + \par \getbuffer[sample] \par + \placefigure{}{\blackrule[width=4cm,height=1cm,color=red]} + \par \getbuffer[sample] \par + \placefigure{}{\blackrule[width=4cm,height=3cm,color=red]} + \par \getbuffer[sample] \par + \placefigure{}{\blackrule[width=4cm,height=2cm,color=red]} + \par \getbuffer[sample] \par +\stoptextbackground +\stopbuffer + +\blank \getbuffer \blank + +The input is: + +\typebuffer + +A combination of both background avoiding mechanisms is shown on the next page +(we flush a few more grapohics so that we cross a page boundary): + +% \page + +\startbuffer +\starttextbackground[demobg] + \placefigure{}{\blackrule[width=4cm,height=2cm,color=red]} + \par \input ward \par + \placefigure[left]{}{\blackrule[width=4cm,height=2cm,color=red]} + \par \input ward \par + \placefigure{}{\blackrule[width=4cm,height=2cm,color=red]} + \placefigure{}{\blackrule[width=4cm,height=2cm,color=red]} + \placefigure{}{\blackrule[width=4cm,height=2cm,color=red]} + \placefigure{}{\blackrule[width=4cm,height=2cm,color=red]} + \placefigure{}{\blackrule[width=4cm,height=2cm,color=red]} + \placefigure{}{\blackrule[width=4cm,height=2cm,color=red]} + \par \input ward \par + \placefigure{}{\blackrule[width=4cm,height=2cm,color=red]} + \par \input ward \par +\stoptextbackground +\stopbuffer + +\blank \getbuffer \blank + +This is the result from: + +\typebuffer + +You can control the interaction between backgrounds and floars with the \type +{freeregion} parameter. + +\startbuffer +\starttextbackground[demobg] + \simulatewords[demo][n=40] + \startplacefigure + [location=left, + title={free}] + \blackrule[width=12cm,height=1cm,color=red] + \stopplacefigure + \simulatewords[demo][n=40] + \startplacefigure + [location=left, + title={non|-|free}, + freeregion=no, + color=textcolor] + \blackrule[width=12cm,height=1cm,color=red] + \stopplacefigure + \simulatewords[demo][n=40] + \startplacefigure + [location=here, + title={free}] + \blackrule[width=12cm,height=1cm,color=red] + \stopplacefigure + \simulatewords[demo][n=40] + \startplacefigure + [location=here, + title={non|-|free}, + freeregion=no, + color=textcolor] + \blackrule[width=12cm,height=1cm,color=red] + \stopplacefigure + \simulatewords[demo][n=40] +\stoptextbackground +\stopbuffer + +\typebuffer + +The next pages show the result, first with some tracing enabled sop that you +can see what gets freed. This visual effect is enabled with: + +\starttyping +\enabletrackers[floats.freeregion] +\stoptyping + +We now move to the next page. + +\page + \getbuffer +\page + \enabletrackers[floats.freeregion] + \getbuffer + \disabletrackers[floats.freeregion] +\page + +We have some control over side float placement and of course that will interfere +with backgrounds. Say that we have this: + +\startbuffer +\definefloat + [demofigureleft] + [figure] + [default=left, + margin=1cm, + leftmargindistance=2cm, + rightmargindistance=2cm] + +\definefloat + [demofigureright] + [demofigureleft] + [default=right] +\stopbuffer + +\typebuffer \getbuffer + +Combined with the following we get the result on the next pages. + +\startbuffer +\starttextbackground[demobg] + \startplacefloat[figure][location=left] + \blackrule[width=12cm,height=1cm,color=red] + \stopplacefigure + \simulatewords[demo][n=40] + \blank + \startplacefloat[figure][location=right] + \blackrule[width=12cm,height=1cm,color=red] + \stopplacefigure + \simulatewords[demo][n=40] + \blank + \startplacefloat[demofigureleft] + \blackrule[width=10cm,height=1cm,color=red] + \stopplacefigure + \simulatewords[demo][n=40] + \blank + \startplacefloat[demofigureright] + \blackrule[width=10cm,height=1cm,color=red] + \stopplacefigure + \simulatewords[demo][n=40] + \startplacefloat[figure] % [freeregion=no] + \blackrule[width=12cm,height=1cm,color=red] + \stopplacefigure + \simulatewords[demo][n=40] +\stoptextbackground +\stopbuffer + +\typebuffer + +\page + +\start + \enabletrackers[floats.freeregion] + \setupwhitespace[none] + \getbuffer + \disabletrackers[floats.freeregion] +\stop + +\page + +\start + \setupwhitespace[none] + \getbuffer +\stop + +\page + +\stop \stopchapter + +\stopcomponent diff --git a/doc/context/sources/general/manuals/details/details-tuningformulas.tex b/doc/context/sources/general/manuals/details/details-tuningformulas.tex new file mode 100644 index 000000000..b36320769 --- /dev/null +++ b/doc/context/sources/general/manuals/details/details-tuningformulas.tex @@ -0,0 +1,212 @@ +% language=uk + +\environment details-environment + +\startcomponent details-tuningformulas + +\startchapter[title={Tuning math formulas}] + +Because of its look and feel, a math formula can look too widely spaced when put +on a grid. There are a few ways to control this. First of all, the default grid +option bound to math is already more tolerant. But you can control it locally +too. Take the following formula: + +\startbuffer +\startformula + a = b^c +\stopformula +\stopbuffer + +\blank \fakeline \getbuffer \fakeline \blank + +This has been entered as: + +\typebuffer + +and because it is just a line of math it comes out as expected. The next code + +\startbuffer +\startformula + a = \frac {a} {b} +\stopformula +\stopbuffer + +\typebuffer + +produces a higher line: + +\blank \fakeline \getbuffer \fakeline \blank + +as does: + +\startbuffer +\startformula + a = \frac {\frac {b} {c}} {\frac {d} {e}} +\stopformula +\stopbuffer + +\typebuffer + +\blank \fakeline \getbuffer \fakeline \blank + +We will now demonstrate three ways to compensate fo rexcessive spacing. The first +variant just sets a grid parameter: + +\startbuffer +\startformula[grid=math:-halfline] + a = \frac {\frac {b} {c}} {\frac {d} {e}} +\stopformula +\stopbuffer + +\typebuffer + +\blank \fakeline \getbuffer \fakeline \blank + +You can also pass this as an option. Only a few such grid related options are +defined: \type {halfline}, \type {line}, \type {-halfline} and \type {-grid}. + +\startbuffer +\startformula[-halfline] + a = \frac {\frac {b} {c}} {\frac {d} {e}} +\stopformula +\stopbuffer + +\typebuffer + +\blank \fakeline \getbuffer \fakeline \blank + +If you need to compensate frequently you can consider defining an instance: + +\startbuffer +\defineformula[tight][grid=math:-halfline] + +\starttightformula + a = \frac {\frac {b} {c}} {\frac {d} {e}} +\stoptightformula +\stopbuffer + +\typebuffer + +\blank \fakeline \getbuffer \fakeline \blank + +The result can be somewhat unexpected at the top and bottom of a page. When we +subtract half a line from the height we can end up above the text area. This is +where the \type {split} directive comes in. So, the compensations are actually +defined as + +\starttabulate[|TCT{blue}|T|] +\NC math \NC \theexpandedsnapperset{math} \NC \NR +\NC math:line \NC \theexpandedsnapperset{math:line} \NC \NR +\NC math:halfline \NC \theexpandedsnapperset{math:halfline} \NC \NR +\NC math:-line \NC \theexpandedsnapperset{math:-line} \NC \NR +\NC math:-halfline \NC \theexpandedsnapperset{math:-halfline} \NC \NR +\stoptabulate + +You can define your own variants building on top of an existing one: + +\starttyping +\definegridsnapping[math:my][math,....] +\stoptyping + +We demonstrate the effect of the \type {split} directive here. It triggers a +check at the page boundaries but you need to keep in mind that this is not always +robust as such boundaries themselves can be triggered by and inject anything. + +\startbuffer[a] +\dorecurse {15} { + \startformula[grid={math,-halfline}] + a = \frac {\frac {b} {c}} {\frac {d} {e}} + (\hbox{top #1 default}) + \stopformula + \blank[samepage] + \fakeline +} +\stopbuffer + +\startbuffer[b] +\dorecurse {15} { + \startformula[grid={math,-halfline,split}] + a = \frac {\frac {b} {c}} {\frac {d} {e}} + (\hbox{top #1 compensated}) + \stopformula + \blank[samepage] + \fakeline +} +\stopbuffer + +\getbuffer[a] +\getbuffer[b] + +As said, the compensation is achieved with the \type {page} directive. The +previous pages were rendered using: + +\typebuffer[a] + +and + +\typebuffer[b] + +In order to get a consistent result we keep the depth of the formula the same but +effectively shift it down a bit, still honouring the grid. So what about the +bottom. + +We can decide that the snapped formula doesn't fit and force a new page but we +can also accept that it sticks out to the bottom, which is less worse than the +top|-|of|-|the|-|page case. + +\startbuffer[a] +\dorecurse{45}{\fakeline} +\startformula[grid={math,-halfline}] + a = \frac {\frac {b} {c}} {\frac {d} {e}} + (\hbox{bottom default}) +\stopformula +\stopbuffer + +\startbuffer[b] +\dorecurse{45}{\fakeline} +\startformula[grid={math,-halfline,split}] + a = \frac {\frac {b} {c}} {\frac {d} {e}} + (\hbox{bottom compensated}) +\stopformula +\stopbuffer + +\page \getbuffer[a] % fits on the page +\page \getbuffer[b] % forces a new page + +These mechanisms might be improved over time but as we don't use it frequently +that might take a while. + +The following formula was posted at the \CONTEXT\ mailing list in a grid snapping +thread and we will use it to demonstrate how you can mess a bit with the +snapping. + +\startbuffer +g(x_{*}) = \lim_{n\to\infty} g(a_{n}) \leq 0 \leq \lim_{n\to\infty} g(b_{n}) = g(x_{*}) +\stopbuffer + +\typebuffer + +We show the given grid parameter as well as its expansion into the low level grid +directives. + +\unexpanded\def\SampleFormula#1% + {\definegridsnapping[math:temp][#1] + \blank + \type{grid=#1} \hfill expanded: \normalexpanded{\type{\theexpandedsnapperset{math:temp}}} + \blank[samepage] + \fakeline + \blank[samepage] + \startformula[grid={#1}] + \getbuffer + \stopformula + \blank[samepage] + \fakeline + \blank} + +\SampleFormula{math} +\SampleFormula{low,halfline} +\SampleFormula{math,nodepth} + +\stopchapter + +\stopcomponent diff --git a/doc/context/sources/general/manuals/details/details.tex b/doc/context/sources/general/manuals/details/details.tex new file mode 100644 index 000000000..6319721e5 --- /dev/null +++ b/doc/context/sources/general/manuals/details/details.tex @@ -0,0 +1,50 @@ +% interface=english modes=screen + +% author : Hans Hagen +% copyright : PRAGMA ADE & ConTeXt Development Team +% license : Creative Commons Attribution ShareAlike 4.0 International +% reference : pragma-ade.nl | contextgarden.net | texlive (related) distributions +% origin : the ConTeXt distribution +% +% comment : Because this manual is distributed with TeX distributions it comes with a rather +% liberal license. We try to adapt these documents to upgrades in the (sub)systems +% that they describe. Using parts of the content otherwise can therefore conflict +% with existing functionality and we cannot be held responsible for that. Many of +% the manuals contain characteristic graphics and personal notes or examples that +% make no sense when used out-of-context. +% +% comment : Some chapters might have been published in TugBoat, the NTG Maps, the ConTeXt +% Group journal or otherwise. Thanks to the editors for corrections. Also thanks +% to users for testing, feedback and corrections. + +\startproduct details + +\environment details-environment + +\component details-frontpage + +\startfrontmatter + \component details-introduction + \component details-contents +\stopfrontmatter + +\startbodymatter + \component details-snappingheads + \component details-pseudocolumns + \component details-textbackgrounds + \component details-tuningformulas + \component details-floatingaround + \component details-finetuningfloats + \component details-ornaments + \component details-gridtrickery + \component details-captiontrickery +\stopbodymatter + +\startbackmatter + % \component details-index + \component details-colofon +\stopbackmatter + +\component details-backpage + +\stopproduct diff --git a/doc/context/sources/general/manuals/details/detcow.mp b/doc/context/sources/general/manuals/details/detcow.mp new file mode 100644 index 000000000..18fc570e5 --- /dev/null +++ b/doc/context/sources/general/manuals/details/detcow.mp @@ -0,0 +1,297 @@ +% Converted from PostScript(TM) to MetaPost by pstoedit +% +% copyright=pragma-ade readme=readme.pdf licence=cc-by-nc-sa + +% MetaPost backend contributed by Scott Pakin <pakin@uiuc.edu> +% pstoedit is Copyright (C) 1993 - 1999 Wolfgang Glunz <wglunz@geocities.com> + +% Generate structured PostScript +prologues := 1; + +% Display a given string with its *baseline* at a given location +% and with a given rotation angle +vardef showtext(expr origin)(expr angle)(expr string) = + draw string infont defaultfont scaled defaultscale + rotated angle shifted origin; +enddef; + +beginfig(1); +drawoptions (withcolor (1,1,1)); +fill (84.3799,618.55)..controls (88.3398,624.38) and (92.5898,622.94)..(96.3398,615.67) + ..controls (101.23,615.6) and (102.46,612.43)..(104.98,610.78) + ..controls (122.62,598.39) and (147.46,607.18)..(167.9,601.92) + ..controls (180.94,598.54) and (190.87,599.76)..(200.09,602.06) + ..controls (220.32,607.25) and (246.1,596.16)..(263.74,603.86) + ..controls (274.75,608.62) and (284.76,605.66)..(292.97,600.91) + ..controls (297.58,597.96) and (299.59,596.09)..(300.96,591.26) + ..controls (306.29,572.54) and (306.29,551.02)..(309.53,530.57) + ..controls (309.53,528.84) and (312.19,526.1)..(312.48,522.07) + ..controls (315.79,511.34) and (316.08,510.12)..(317.16,502.2) + ..controls (317.16,501.34) and (326.52,488.45)..(325.01,479.02) + ..controls (323.93,481.25) and (323.86,482.83)..(321.62,481.68) + ..controls (320.33,479.3) and (320.9,473.9)..(322.56,471.74) + ..controls (320.83,470.81) and (318.46,473.47)..(317.52,475.2) + ..controls (318.17,473.04) and (317.81,470.81)..(316.73,469.3) + ..controls (315.86,472.25) and (316.58,473.18)..(315.36,473.9) + ..controls (313.99,472.9) and (314.21,469.3)..(314.28,466.2) + ..controls (313.49,468.07) and (311.47,472.46)..(312.55,476.42) + ..controls (312.48,484.2) and (308.81,489.1)..(310.32,499.1) + ..controls (310.1,504.43) and (307.3,521.06)..(304.56,524.3) + ..controls (303.12,526.25) and (306.36,510.77)..(306.36,506.16) + ..controls (306.65,500.9) and (307.08,468.72)..(306.43,463.1) + ..controls (306.43,459.22) and (306.22,453.96)..(307.08,452.16) + ..controls (308.74,450.79) and (309.38,450.5)..(309.6,447.98) + ..controls (309.24,446.62) and (308.74,446.04)..(307.73,445.54) + ..controls (306.07,444.6) and (307.37,441.79)..(306.07,439.85) + ..controls (304.49,438.77) and (304.13,441.86)..(303.34,441.86) + ..controls (302.69,441) and (303.05,437.98)..(302.47,436.18) + ..controls (299.66,433.8) and (292.18,432.5)..(289.15,434.66) + ..controls (289.73,440.64) and (291.74,441.58)..(295.63,446.62) + ..controls (298.66,452.59) and (297,460.94)..(296.93,468.14) + ..controls (295.49,480.38) and (289.22,487.3)..(289.44,496.44) + ..controls (287.86,495.72) and (286.42,494.57)..(284.26,494.86) + ..controls (283.39,489.46) and (286.42,484.56)..(284.83,480.82) + ..controls (281.95,471.96) and (277.06,446.62)..(279,437.76) + ..controls (280.01,434.74) and (278.21,433.15)..(277.06,433.94) + ..controls (276.77,433.94) and (276.55,433.94)..(276.41,433.94) + ..controls (276.41,433.94) and (276.55,431.42)..(275.69,430.92) + ..controls (274.1,430.34) and (273.67,431.71)..(272.66,432.14) + ..controls (271.22,430.85) and (272.52,429.48)..(271.15,428.04) + ..controls (267.19,428.04) and (261.36,425.38)..(257.98,428.26) + ..controls (257.33,434.16) and (263.3,436.68)..(266.47,440.71) + ..controls (268.63,446.62) and (271.08,462.89)..(267.77,474.62) + ..controls (267.77,475.56) and (264.38,485.28)..(261.43,488.66) + ..controls (258.7,487.66) and (257.33,485.5)..(253.22,486.29) + ..controls (252.58,484.34) and (253.3,482.33)..(252.22,480.1) + ..controls (251.86,479.52) and (249.34,478.58)..(249.19,481.39) + ..controls (248.98,483.05) and (248.9,486.36)..(248.26,486.72) + ..controls (243.65,486.72) and (233.71,487.08)..(231.77,493.92) + ..controls (219.89,492.34) and (215.93,491.26)..(206.57,493.42) + ..controls (196.63,489.67) and (183.24,506.16)..(174.53,502.2) + ..controls (172.51,496.15) and (173.09,485.64)..(171.65,481.39) + ..controls (169.34,474.77) and (171.14,467.14)..(171.14,456.41) + ..controls (170.57,455.4) and (169.85,454.46)..(168.48,454.46) + ..controls (168.48,453.1) and (169.34,450.86)..(168.62,449.42) + ..controls (167.18,447.62) and (165.89,451.8)..(165.02,444.6) + ..controls (163.15,443.74) and (157.75,442.22)..(155.59,445.18) + ..controls (155.88,448.99) and (158.33,451.3)..(160.13,453.38) + ..controls (161.42,456.91) and (160.99,458.28)..(160.7,461.81) + ..controls (160.99,464.98) and (161.71,468.58)..(161.86,470.09) + ..controls (161.86,473.04) and (162.5,479.3)..(161.14,481.18) + --(159.41,482.69)..controls (157.18,487.22) and (158.33,494.64)..(157.61,500.26) + ..controls (155.81,500.69) and (155.81,500.98)..(154.01,498.31) + ..controls (154.01,494.42) and (153.5,486.36)..(152.35,483.84) + ..controls (149.69,479.81) and (150.84,459.65)..(151.42,448.56) + ..controls (151.78,446.47) and (149.69,447.7)..(149.76,444.74) + ..controls (150.05,442.8) and (147.89,443.59)..(146.09,444.6) + ..controls (145.15,445.18) and (146.59,439.78)..(145.37,439.56) + ..controls (142.34,438.84) and (136.87,438.19)..(135.22,440.71) + ..controls (134.57,444.6) and (137.88,448.06)..(140.62,451.01) + ..controls (143.14,455.83) and (140.9,465.7)..(140.47,476.28) + --(138.89,478.22)..controls (134.86,483.19) and (139.61,496.94)..(136.51,506.23) + ..controls (120.02,514.87) and (122.11,519.19)..(118.73,537.62) + ..controls (115.13,557.64) and (93.3799,567.65)..(79.0598,567.65) + ..controls (73.4399,563.04) and (66.24,563.62)..(58.5398,567.65) + ..controls (55.6599,569.23) and (54.4299,573.19)..(54.5,576.5) + ..controls (52.6299,580.75) and (55.22,582.19)..(59.6199,583.49) + ..controls (62.71,587.81) and (68.6199,594.65)..(69.1899,597.74) + ..controls (70.3398,601.92) and (75.5298,608.11)..(77.7598,609.77) + ..controls (75.8198,613.01) and (74.8098,615.17)..(77.1099,618.55) + ..controls (79.5598,620.14) and (81.7898,616.61)..(84.3799,618.55) + --cycle; +drawoptions (withcolor (0,0,0)); +pickup pencircle scaled 0.636492bp; +draw (84.3799,618.55)..controls (88.3398,624.38) and (92.5898,622.94)..(96.3398,615.67) + ..controls (101.23,615.6) and (102.46,612.43)..(104.98,610.78) + ..controls (122.62,598.39) and (147.46,607.18)..(167.9,601.92) + ..controls (180.94,598.54) and (190.87,599.76)..(200.09,602.06) + ..controls (220.32,607.25) and (246.1,596.16)..(263.74,603.86) + ..controls (274.75,608.62) and (284.76,605.66)..(292.97,600.91) + ..controls (297.58,597.96) and (299.59,596.09)..(300.96,591.26) + ..controls (306.29,572.54) and (306.29,551.02)..(309.53,530.57) + ..controls (309.53,528.84) and (312.19,526.1)..(312.48,522.07) + ..controls (315.79,511.34) and (316.08,510.12)..(317.16,502.2) + ..controls (317.16,501.34) and (326.52,488.45)..(325.01,479.02) + ..controls (323.93,481.25) and (323.86,482.83)..(321.62,481.68) + ..controls (320.33,479.3) and (320.9,473.9)..(322.56,471.74) + ..controls (320.83,470.81) and (318.46,473.47)..(317.52,475.2) + ..controls (318.17,473.04) and (317.81,470.81)..(316.73,469.3) + ..controls (315.86,472.25) and (316.58,473.18)..(315.36,473.9) + ..controls (313.99,472.9) and (314.21,469.3)..(314.28,466.2) + ..controls (313.49,468.07) and (311.47,472.46)..(312.55,476.42) + ..controls (312.48,484.2) and (308.81,489.1)..(310.32,499.1) + ..controls (310.1,504.43) and (307.3,521.06)..(304.56,524.3) + ..controls (303.12,526.25) and (306.36,510.77)..(306.36,506.16) + ..controls (306.65,500.9) and (307.08,468.72)..(306.43,463.1) + ..controls (306.43,459.22) and (306.22,453.96)..(307.08,452.16) + ..controls (308.74,450.79) and (309.38,450.5)..(309.6,447.98) + ..controls (309.24,446.62) and (308.74,446.04)..(307.73,445.54) + ..controls (306.07,444.6) and (307.37,441.79)..(306.07,439.85) + ..controls (304.49,438.77) and (304.13,441.86)..(303.34,441.86) + ..controls (302.69,441) and (303.05,437.98)..(302.47,436.18) + ..controls (299.66,433.8) and (292.18,432.5)..(289.15,434.66) + ..controls (289.73,440.64) and (291.74,441.58)..(295.63,446.62) + ..controls (298.66,452.59) and (297,460.94)..(296.93,468.14) + ..controls (295.49,480.38) and (289.22,487.3)..(289.44,496.44) + ..controls (287.86,495.72) and (286.42,494.57)..(284.26,494.86) + ..controls (283.39,489.46) and (286.42,484.56)..(284.83,480.82) + ..controls (281.95,471.96) and (277.06,446.62)..(279,437.76) + ..controls (280.01,434.74) and (278.21,433.15)..(277.06,433.94) + ..controls (276.77,433.94) and (276.55,433.94)..(276.41,433.94) + ..controls (276.41,433.94) and (276.55,431.42)..(275.69,430.92) + ..controls (274.1,430.34) and (273.67,431.71)..(272.66,432.14) + ..controls (271.22,430.85) and (272.52,429.48)..(271.15,428.04) + ..controls (267.19,428.04) and (261.36,425.38)..(257.98,428.26) + ..controls (257.33,434.16) and (263.3,436.68)..(266.47,440.71) + ..controls (268.63,446.62) and (271.08,462.89)..(267.77,474.62) + ..controls (267.77,475.56) and (264.38,485.28)..(261.43,488.66) + ..controls (258.7,487.66) and (257.33,485.5)..(253.22,486.29) + ..controls (252.58,484.34) and (253.3,482.33)..(252.22,480.1) + ..controls (251.86,479.52) and (249.34,478.58)..(249.19,481.39) + ..controls (248.98,483.05) and (248.9,486.36)..(248.26,486.72) + ..controls (243.65,486.72) and (233.71,487.08)..(231.77,493.92) + ..controls (219.89,492.34) and (215.93,491.26)..(206.57,493.42) + ..controls (196.63,489.67) and (183.24,506.16)..(174.53,502.2) + ..controls (172.51,496.15) and (173.09,485.64)..(171.65,481.39) + ..controls (169.34,474.77) and (171.14,467.14)..(171.14,456.41) + ..controls (170.57,455.4) and (169.85,454.46)..(168.48,454.46) + ..controls (168.48,453.1) and (169.34,450.86)..(168.62,449.42) + ..controls (167.18,447.62) and (165.89,451.8)..(165.02,444.6) + ..controls (163.15,443.74) and (157.75,442.22)..(155.59,445.18) + ..controls (155.88,448.99) and (158.33,451.3)..(160.13,453.38) + ..controls (161.42,456.91) and (160.99,458.28)..(160.7,461.81) + ..controls (160.99,464.98) and (161.71,468.58)..(161.86,470.09) + ..controls (161.86,473.04) and (162.5,479.3)..(161.14,481.18) + --(159.41,482.69)..controls (157.18,487.22) and (158.33,494.64)..(157.61,500.26) + ..controls (155.81,500.69) and (155.81,500.98)..(154.01,498.31) + ..controls (154.01,494.42) and (153.5,486.36)..(152.35,483.84) + ..controls (149.69,479.81) and (150.84,459.65)..(151.42,448.56) + ..controls (151.78,446.47) and (149.69,447.7)..(149.76,444.74) + ..controls (150.05,442.8) and (147.89,443.59)..(146.09,444.6) + ..controls (145.15,445.18) and (146.59,439.78)..(145.37,439.56) + ..controls (142.34,438.84) and (136.87,438.19)..(135.22,440.71) + ..controls (134.57,444.6) and (137.88,448.06)..(140.62,451.01) + ..controls (143.14,455.83) and (140.9,465.7)..(140.47,476.28) + --(138.89,478.22)..controls (134.86,483.19) and (139.61,496.94)..(136.51,506.23) + ..controls (120.02,514.87) and (122.11,519.19)..(118.73,537.62) + ..controls (115.13,557.64) and (93.3799,567.65)..(79.0598,567.65) + ..controls (73.4399,563.04) and (66.24,563.62)..(58.5398,567.65) + ..controls (55.6599,569.23) and (54.4299,573.19)..(54.5,576.5) + ..controls (52.6299,580.75) and (55.22,582.19)..(59.6199,583.49) + ..controls (62.71,587.81) and (68.6199,594.65)..(69.1899,597.74) + ..controls (70.3398,601.92) and (75.5298,608.11)..(77.7598,609.77) + ..controls (75.8198,613.01) and (74.8098,615.17)..(77.1099,618.55) + ..controls (79.5598,620.14) and (81.7898,616.61)..(84.3799,618.55) + --cycle; +pickup pencircle scaled 0bp; +fill (305.28,560.95)..controls (304.63,560.95) and (299.95,561.24)..(299.38,561.24) + ..controls (302.4,550.44) and (303.98,536.47)..(304.2,525.31) + ..controls (303.7,521.35) and (299.81,517.46)..(299.38,525.67) + ..controls (295.85,530.86) and (296.42,540.07)..(293.4,540.29) + ..controls (287.35,539.64) and (285.34,513.22)..(280.01,509.33) + ..controls (276.26,512.28) and (280.73,524.02)..(275.54,524.74) + ..controls (270.5,524.02) and (264.31,526.68)..(266.69,534.46) + ..controls (270.29,543.02) and (268.34,554.76)..(266.54,561.6) + ..controls (262.37,578.59) and (264.02,587.09)..(271.58,596.09) + --(267.48,604.51)..controls (275.4,608.26) and (285.62,604.58)..(290.02,602.21) + ..controls (294.62,600.26) and (300.24,595.94)..(301.1,587.38) + ..controls (303.34,578.88) and (304.42,569.74)..(305.28,560.95) + --cycle; +fill (245.45,600.34)..controls (242.78,599.4) and (239.62,596.02)..(237.67,594.07) + ..controls (236.74,584.42) and (244.58,583.63)..(250.2,577.44) + ..controls (258.77,573.7) and (251.21,567.72)..(256.18,557.42) + ..controls (257.04,550.94) and (257.9,543.89)..(255.31,539.78) + ..controls (249.48,538.92) and (247.97,540.22)..(246.89,531.43) + ..controls (246.31,526.97) and (231.77,529.06)..(229.03,538.27) + ..controls (227.09,544.97) and (221.33,546.7)..(217.8,543.17) + ..controls (213.77,538.06) and (215.78,531.22)..(217.8,527.47) + ..controls (224.93,517.32) and (212.04,511.42)..(205.13,516.74) + ..controls (199.73,508.68) and (211.39,500.04)..(207.43,494.5) + ..controls (205.78,493.99) and (204.77,489.17)..(185.47,500.54) + ..controls (180.36,504.14) and (167.83,500.76)..(168.77,520.63) + ..controls (168.77,525.82) and (165.6,543.53)..(162.14,555.91) + ..controls (159.41,561.24) and (156.74,559.08)..(156.89,553.9) + ..controls (157.18,547.85) and (162.94,531.22)..(155.52,540.22) + ..controls (153.58,539.21) and (156.89,523.58)..(156.89,521.64) + ..controls (162,517.03) and (157.39,513.58)..(154.73,512.28) + ..controls (151.27,518.33) and (149.62,518.04)..(147.17,514.44) + ..controls (141.7,514.08) and (144.58,528.19)..(140.26,528.62) + ..controls (137.02,527.76) and (139.18,520.06)..(138.24,518.76) + ..controls (132.98,524.74) and (130.9,529.27)..(127.01,521.64) + ..controls (126.14,521.64) and (122.11,519.19)..(120.96,526.54) + ..controls (117.65,552.74) and (107.06,558.36)..(93.8198,565.13) + ..controls (92.0198,565.63) and (84.24,566.71)..(79.3398,568.15) + ..controls (73.5098,560.88) and (58.3198,565.63)..(56.23,570.31) + ..controls (54.7898,572.69) and (54.6499,575.21)..(54.7898,576.5) + ..controls (52.3398,580.1) and (55.8699,582.7)..(59.6199,583.06) + ..controls (62.8599,587.16) and (68.5398,594.94)..(71.2798,601.56) + ..controls (72.2898,603.07) and (74.95,609.34)..(78.1899,609.55) + ..controls (74.95,612.94) and (74.2998,622.51)..(82.6599,617.33) + ..controls (87.1199,624.02) and (92.0898,624.31)..(95.7598,615.82) + ..controls (102.89,615.38) and (102.31,608.69)..(115.78,605.52) + ..controls (122.76,602.86) and (132.77,604.58)..(140.26,603.72) + ..controls (136.22,596.88) and (127.44,566.86)..(132.98,559.8) + ..controls (140.76,564.7) and (141.84,605.38)..(157.03,595.66) + ..controls (160.56,593.93) and (159.91,590.04)..(164.09,590.18) + ..controls (170.42,587.45) and (169.13,600.77)..(172.51,600.77) + ..controls (176.47,599.76) and (183.02,599.04)..(186.98,599.54) + ..controls (197.71,600.77) and (206.93,604.08)..(223.92,602.5) + ..controls (231.12,601.78) and (238.25,601.06)..(245.45,600.34) + --cycle; +pickup pencircle scaled 0.636492bp; +draw (305.28,560.95)..controls (304.63,560.95) and (299.95,561.24)..(299.38,561.24) + ..controls (302.4,550.44) and (303.98,536.47)..(304.2,525.31) + ..controls (303.7,521.35) and (299.81,517.46)..(299.38,525.67) + ..controls (295.85,530.86) and (296.42,540.07)..(293.4,540.29) + ..controls (287.35,539.64) and (285.34,513.22)..(280.01,509.33) + ..controls (276.26,512.28) and (280.73,524.02)..(275.54,524.74) + ..controls (270.5,524.02) and (264.31,526.68)..(266.69,534.46) + ..controls (270.29,543.02) and (268.34,554.76)..(266.54,561.6) + ..controls (262.37,578.59) and (264.02,587.09)..(271.58,596.09) + --(267.48,604.51)..controls (275.4,608.26) and (285.62,604.58)..(290.02,602.21) + ..controls (294.62,600.26) and (300.24,595.94)..(301.1,587.38) + ..controls (303.34,578.88) and (304.42,569.74)..(305.28,560.95) + --cycle; +draw (245.45,600.34)..controls (242.78,599.4) and (239.62,596.02)..(237.67,594.07) + ..controls (236.74,584.42) and (244.58,583.63)..(250.2,577.44) + ..controls (258.77,573.7) and (251.21,567.72)..(256.18,557.42) + ..controls (257.04,550.94) and (257.9,543.89)..(255.31,539.78) + ..controls (249.48,538.92) and (247.97,540.22)..(246.89,531.43) + ..controls (246.31,526.97) and (231.77,529.06)..(229.03,538.27) + ..controls (227.09,544.97) and (221.33,546.7)..(217.8,543.17) + ..controls (213.77,538.06) and (215.78,531.22)..(217.8,527.47) + ..controls (224.93,517.32) and (212.04,511.42)..(205.13,516.74) + ..controls (199.73,508.68) and (211.39,500.04)..(207.43,494.5) + ..controls (205.78,493.99) and (204.77,489.17)..(185.47,500.54) + ..controls (180.36,504.14) and (167.83,500.76)..(168.77,520.63) + ..controls (168.77,525.82) and (165.6,543.53)..(162.14,555.91) + ..controls (159.41,561.24) and (156.74,559.08)..(156.89,553.9) + ..controls (157.18,547.85) and (162.94,531.22)..(155.52,540.22) + ..controls (153.58,539.21) and (156.89,523.58)..(156.89,521.64) + ..controls (162,517.03) and (157.39,513.58)..(154.73,512.28) + ..controls (151.27,518.33) and (149.62,518.04)..(147.17,514.44) + ..controls (141.7,514.08) and (144.58,528.19)..(140.26,528.62) + ..controls (137.02,527.76) and (139.18,520.06)..(138.24,518.76) + ..controls (132.98,524.74) and (130.9,529.27)..(127.01,521.64) + ..controls (126.14,521.64) and (122.11,519.19)..(120.96,526.54) + ..controls (117.65,552.74) and (107.06,558.36)..(93.8198,565.13) + ..controls (92.0198,565.63) and (84.24,566.71)..(79.3398,568.15) + ..controls (73.5098,560.88) and (58.3198,565.63)..(56.23,570.31) + ..controls (54.7898,572.69) and (54.6499,575.21)..(54.7898,576.5) + ..controls (52.3398,580.1) and (55.8699,582.7)..(59.6199,583.06) + ..controls (62.8599,587.16) and (68.5398,594.94)..(71.2798,601.56) + ..controls (72.2898,603.07) and (74.95,609.34)..(78.1899,609.55) + ..controls (74.95,612.94) and (74.2998,622.51)..(82.6599,617.33) + ..controls (87.1199,624.02) and (92.0898,624.31)..(95.7598,615.82) + ..controls (102.89,615.38) and (102.31,608.69)..(115.78,605.52) + ..controls (122.76,602.86) and (132.77,604.58)..(140.26,603.72) + ..controls (136.22,596.88) and (127.44,566.86)..(132.98,559.8) + ..controls (140.76,564.7) and (141.84,605.38)..(157.03,595.66) + ..controls (160.56,593.93) and (159.91,590.04)..(164.09,590.18) + ..controls (170.42,587.45) and (169.13,600.77)..(172.51,600.77) + ..controls (176.47,599.76) and (183.02,599.04)..(186.98,599.54) + ..controls (197.71,600.77) and (206.93,604.08)..(223.92,602.5) + ..controls (231.12,601.78) and (238.25,601.06)..(245.45,600.34) + --cycle; +endfig; +end diff --git a/doc/context/sources/general/manuals/details/detcow.tex b/doc/context/sources/general/manuals/details/detcow.tex new file mode 100644 index 000000000..c3698e335 --- /dev/null +++ b/doc/context/sources/general/manuals/details/detcow.tex @@ -0,0 +1,15 @@ +% content=tex +% +% copyright=pragma-ade readme=readme.pdf licence=cc-by-nc-sa + +\setupcolors[state=start] + +\starttext + +\startMPpage + loadfigure "detcow.mp" ; + refill currentpicture withcolor transparent(1,.5,.5red) ; + redraw currentpicture withcolor .5red ; +\stopMPpage + +\stoptext diff --git a/doc/context/sources/general/manuals/details/detcowmp.mps b/doc/context/sources/general/manuals/details/detcowmp.mps new file mode 100644 index 000000000..c5cb7df80 --- /dev/null +++ b/doc/context/sources/general/manuals/details/detcowmp.mps @@ -0,0 +1,295 @@ +%!PS-Adobe-3.0 EPSF-3.0 +%%BoundingBox: 53 426 326 623 +%%Creator: MetaPost +%%CreationDate: 2002.04.10:1235 +%%Pages: 1 +%%EndProlog +%%Page: 1 1 + 1 setgray +newpath 84.3799 618.55 moveto +88.3398 624.38 92.5898 622.94 96.3398 615.67 curveto +101.23 615.6 102.46 612.43 104.98 610.78 curveto +122.62 598.39 147.46 607.18 167.9 601.92 curveto +180.94 598.54 190.87 599.76 200.09 602.06 curveto +220.32 607.25 246.1 596.16 263.74 603.86 curveto +274.75 608.62 284.76 605.66 292.97 600.91 curveto +297.58 597.96 299.59 596.09 300.96 591.26 curveto +306.29 572.54 306.29 551.02 309.53 530.57 curveto +309.53 528.84 312.19 526.1 312.48 522.07 curveto +315.79 511.34 316.08 510.12 317.16 502.2 curveto +317.16 501.34 326.52 488.45 325.01 479.02 curveto +323.93 481.25 323.86 482.83 321.62 481.68 curveto +320.33 479.3 320.9 473.9 322.56 471.74 curveto +320.83 470.81 318.46 473.47 317.52 475.2 curveto +318.17 473.04 317.81 470.81 316.73 469.3 curveto +315.86 472.25 316.58 473.18 315.36 473.9 curveto +313.99 472.9 314.21 469.3 314.28 466.2 curveto +313.49 468.07 311.47 472.46 312.55 476.42 curveto +312.48 484.2 308.81 489.1 310.32 499.1 curveto +310.1 504.43 307.3 521.06 304.56 524.3 curveto +303.12 526.25 306.36 510.77 306.36 506.16 curveto +306.65 500.9 307.08 468.72 306.43 463.1 curveto +306.43 459.22 306.22 453.96 307.08 452.16 curveto +308.74 450.79 309.38 450.5 309.6 447.98 curveto +309.24 446.62 308.74 446.04 307.73 445.54 curveto +306.07 444.6 307.37 441.79 306.07 439.85 curveto +304.49 438.77 304.13 441.86 303.34 441.86 curveto +302.69 441 303.05 437.98 302.47 436.18 curveto +299.66 433.8 292.18 432.5 289.15 434.66 curveto +289.73 440.64 291.74 441.58 295.63 446.62 curveto +298.66 452.59 297 460.94 296.93 468.14 curveto +295.49 480.38 289.22 487.3 289.44 496.44 curveto +287.86 495.72 286.42 494.57 284.26 494.86 curveto +283.39 489.46 286.42 484.56 284.83 480.82 curveto +281.95 471.96 277.06 446.62 279 437.76 curveto +280.01 434.74 278.21 433.15 277.06 433.94 curveto +276.77 433.94 276.55 433.94 276.41 433.94 curveto +276.41 433.94 276.55 431.42 275.69 430.92 curveto +274.1 430.34 273.67 431.71 272.66 432.14 curveto +271.22 430.85 272.52 429.48 271.15 428.04 curveto +267.19 428.04 261.36 425.38 257.98 428.26 curveto +257.33 434.16 263.3 436.68 266.47 440.71 curveto +268.63 446.62 271.08 462.89 267.77 474.62 curveto +267.77 475.56 264.38 485.28 261.43 488.66 curveto +258.7 487.66 257.33 485.5 253.22 486.29 curveto +252.58 484.34 253.3 482.33 252.22 480.1 curveto +251.86 479.52 249.34 478.58 249.19 481.39 curveto +248.98 483.05 248.9 486.36 248.26 486.72 curveto +243.65 486.72 233.71 487.08 231.77 493.92 curveto +219.89 492.34 215.93 491.26 206.57 493.42 curveto +196.63 489.67 183.24 506.16 174.53 502.2 curveto +172.51 496.15 173.09 485.64 171.65 481.39 curveto +169.34 474.77 171.14 467.14 171.14 456.41 curveto +170.57 455.4 169.85 454.46 168.48 454.46 curveto +168.48 453.1 169.34 450.86 168.62 449.42 curveto +167.18 447.62 165.89 451.8 165.02 444.6 curveto +163.15 443.74 157.75 442.22 155.59 445.18 curveto +155.88 448.99 158.33 451.3 160.13 453.38 curveto +161.42 456.91 160.99 458.28 160.7 461.81 curveto +160.99 464.98 161.71 468.58 161.86 470.09 curveto +161.86 473.04 162.5 479.3 161.14 481.18 curveto +159.41 482.69 lineto +157.18 487.22 158.33 494.64 157.61 500.26 curveto +155.81 500.69 155.81 500.98 154.01 498.31 curveto +154.01 494.42 153.5 486.36 152.35 483.84 curveto +149.69 479.81 150.84 459.65 151.42 448.56 curveto +151.78 446.47 149.69 447.7 149.76 444.74 curveto +150.05 442.8 147.89 443.59 146.09 444.6 curveto +145.15 445.18 146.59 439.78 145.37 439.56 curveto +142.34 438.84 136.87 438.19 135.22 440.71 curveto +134.57 444.6 137.88 448.06 140.62 451.01 curveto +143.14 455.83 140.9 465.7 140.47 476.28 curveto +138.89 478.22 lineto +134.86 483.19 139.61 496.94 136.51 506.23 curveto +120.02 514.87 122.11 519.19 118.73 537.62 curveto +115.13 557.64 93.3799 567.65 79.0598 567.65 curveto +73.4399 563.04 66.24 563.62 58.5398 567.65 curveto +55.6599 569.23 54.4299 573.19 54.5 576.5 curveto +52.6299 580.75 55.22 582.19 59.6199 583.49 curveto +62.71 587.81 68.6199 594.65 69.1899 597.74 curveto +70.3398 601.92 75.5298 608.11 77.7598 609.77 curveto +75.8198 613.01 74.8098 615.17 77.1099 618.55 curveto +79.5598 620.14 81.7898 616.61 84.3799 618.55 curveto + closepath fill + 0 setgray 0 0.63649 dtransform truncate idtransform setlinewidth pop [] 0 setdash 1 setlinejoin 10 setmiterlimit +newpath 84.3799 618.55 moveto +88.3398 624.38 92.5898 622.94 96.3398 615.67 curveto +101.23 615.6 102.46 612.43 104.98 610.78 curveto +122.62 598.39 147.46 607.18 167.9 601.92 curveto +180.94 598.54 190.87 599.76 200.09 602.06 curveto +220.32 607.25 246.1 596.16 263.74 603.86 curveto +274.75 608.62 284.76 605.66 292.97 600.91 curveto +297.58 597.96 299.59 596.09 300.96 591.26 curveto +306.29 572.54 306.29 551.02 309.53 530.57 curveto +309.53 528.84 312.19 526.1 312.48 522.07 curveto +315.79 511.34 316.08 510.12 317.16 502.2 curveto +317.16 501.34 326.52 488.45 325.01 479.02 curveto +323.93 481.25 323.86 482.83 321.62 481.68 curveto +320.33 479.3 320.9 473.9 322.56 471.74 curveto +320.83 470.81 318.46 473.47 317.52 475.2 curveto +318.17 473.04 317.81 470.81 316.73 469.3 curveto +315.86 472.25 316.58 473.18 315.36 473.9 curveto +313.99 472.9 314.21 469.3 314.28 466.2 curveto +313.49 468.07 311.47 472.46 312.55 476.42 curveto +312.48 484.2 308.81 489.1 310.32 499.1 curveto +310.1 504.43 307.3 521.06 304.56 524.3 curveto +303.12 526.25 306.36 510.77 306.36 506.16 curveto +306.65 500.9 307.08 468.72 306.43 463.1 curveto +306.43 459.22 306.22 453.96 307.08 452.16 curveto +308.74 450.79 309.38 450.5 309.6 447.98 curveto +309.24 446.62 308.74 446.04 307.73 445.54 curveto +306.07 444.6 307.37 441.79 306.07 439.85 curveto +304.49 438.77 304.13 441.86 303.34 441.86 curveto +302.69 441 303.05 437.98 302.47 436.18 curveto +299.66 433.8 292.18 432.5 289.15 434.66 curveto +289.73 440.64 291.74 441.58 295.63 446.62 curveto +298.66 452.59 297 460.94 296.93 468.14 curveto +295.49 480.38 289.22 487.3 289.44 496.44 curveto +287.86 495.72 286.42 494.57 284.26 494.86 curveto +283.39 489.46 286.42 484.56 284.83 480.82 curveto +281.95 471.96 277.06 446.62 279 437.76 curveto +280.01 434.74 278.21 433.15 277.06 433.94 curveto +276.77 433.94 276.55 433.94 276.41 433.94 curveto +276.41 433.94 276.55 431.42 275.69 430.92 curveto +274.1 430.34 273.67 431.71 272.66 432.14 curveto +271.22 430.85 272.52 429.48 271.15 428.04 curveto +267.19 428.04 261.36 425.38 257.98 428.26 curveto +257.33 434.16 263.3 436.68 266.47 440.71 curveto +268.63 446.62 271.08 462.89 267.77 474.62 curveto +267.77 475.56 264.38 485.28 261.43 488.66 curveto +258.7 487.66 257.33 485.5 253.22 486.29 curveto +252.58 484.34 253.3 482.33 252.22 480.1 curveto +251.86 479.52 249.34 478.58 249.19 481.39 curveto +248.98 483.05 248.9 486.36 248.26 486.72 curveto +243.65 486.72 233.71 487.08 231.77 493.92 curveto +219.89 492.34 215.93 491.26 206.57 493.42 curveto +196.63 489.67 183.24 506.16 174.53 502.2 curveto +172.51 496.15 173.09 485.64 171.65 481.39 curveto +169.34 474.77 171.14 467.14 171.14 456.41 curveto +170.57 455.4 169.85 454.46 168.48 454.46 curveto +168.48 453.1 169.34 450.86 168.62 449.42 curveto +167.18 447.62 165.89 451.8 165.02 444.6 curveto +163.15 443.74 157.75 442.22 155.59 445.18 curveto +155.88 448.99 158.33 451.3 160.13 453.38 curveto +161.42 456.91 160.99 458.28 160.7 461.81 curveto +160.99 464.98 161.71 468.58 161.86 470.09 curveto +161.86 473.04 162.5 479.3 161.14 481.18 curveto +159.41 482.69 lineto +157.18 487.22 158.33 494.64 157.61 500.26 curveto +155.81 500.69 155.81 500.98 154.01 498.31 curveto +154.01 494.42 153.5 486.36 152.35 483.84 curveto +149.69 479.81 150.84 459.65 151.42 448.56 curveto +151.78 446.47 149.69 447.7 149.76 444.74 curveto +150.05 442.8 147.89 443.59 146.09 444.6 curveto +145.15 445.18 146.59 439.78 145.37 439.56 curveto +142.34 438.84 136.87 438.19 135.22 440.71 curveto +134.57 444.6 137.88 448.06 140.62 451.01 curveto +143.14 455.83 140.9 465.7 140.47 476.28 curveto +138.89 478.22 lineto +134.86 483.19 139.61 496.94 136.51 506.23 curveto +120.02 514.87 122.11 519.19 118.73 537.62 curveto +115.13 557.64 93.3799 567.65 79.0598 567.65 curveto +73.4399 563.04 66.24 563.62 58.5398 567.65 curveto +55.6599 569.23 54.4299 573.19 54.5 576.5 curveto +52.6299 580.75 55.22 582.19 59.6199 583.49 curveto +62.71 587.81 68.6199 594.65 69.1899 597.74 curveto +70.3398 601.92 75.5298 608.11 77.7598 609.77 curveto +75.8198 613.01 74.8098 615.17 77.1099 618.55 curveto +79.5598 620.14 81.7898 616.61 84.3799 618.55 curveto + closepath stroke +newpath 305.28 560.95 moveto +304.63 560.95 299.95 561.24 299.38 561.24 curveto +302.4 550.44 303.98 536.47 304.2 525.31 curveto +303.7 521.35 299.81 517.46 299.38 525.67 curveto +295.85 530.86 296.42 540.07 293.4 540.29 curveto +287.35 539.64 285.34 513.22 280.01 509.33 curveto +276.26 512.28 280.73 524.02 275.54 524.74 curveto +270.5 524.02 264.31 526.68 266.69 534.46 curveto +270.29 543.02 268.34 554.76 266.54 561.6 curveto +262.37 578.59 264.02 587.09 271.58 596.09 curveto +267.48 604.51 lineto +275.4 608.26 285.62 604.58 290.02 602.21 curveto +294.62 600.26 300.24 595.94 301.1 587.38 curveto +303.34 578.88 304.42 569.74 305.28 560.95 curveto + closepath fill +newpath 245.45 600.34 moveto +242.78 599.4 239.62 596.02 237.67 594.07 curveto +236.74 584.42 244.58 583.63 250.2 577.44 curveto +258.77 573.7 251.21 567.72 256.18 557.42 curveto +257.04 550.94 257.9 543.89 255.31 539.78 curveto +249.48 538.92 247.97 540.22 246.89 531.43 curveto +246.31 526.97 231.77 529.06 229.03 538.27 curveto +227.09 544.97 221.33 546.7 217.8 543.17 curveto +213.77 538.06 215.78 531.22 217.8 527.47 curveto +224.93 517.32 212.04 511.42 205.13 516.74 curveto +199.73 508.68 211.39 500.04 207.43 494.5 curveto +205.78 493.99 204.77 489.17 185.47 500.54 curveto +180.36 504.14 167.83 500.76 168.77 520.63 curveto +168.77 525.82 165.6 543.53 162.14 555.91 curveto +159.41 561.24 156.74 559.08 156.89 553.9 curveto +157.18 547.85 162.94 531.22 155.52 540.22 curveto +153.58 539.21 156.89 523.58 156.89 521.64 curveto +162 517.03 157.39 513.58 154.73 512.28 curveto +151.27 518.33 149.62 518.04 147.17 514.44 curveto +141.7 514.08 144.58 528.19 140.26 528.62 curveto +137.02 527.76 139.18 520.06 138.24 518.76 curveto +132.98 524.74 130.9 529.27 127.01 521.64 curveto +126.14 521.64 122.11 519.19 120.96 526.54 curveto +117.65 552.74 107.06 558.36 93.8198 565.13 curveto +92.0198 565.63 84.24 566.71 79.3398 568.15 curveto +73.5098 560.88 58.3198 565.63 56.23 570.31 curveto +54.7898 572.69 54.6499 575.21 54.7898 576.5 curveto +52.3398 580.1 55.8699 582.7 59.6199 583.06 curveto +62.8599 587.16 68.5398 594.94 71.2798 601.56 curveto +72.2898 603.07 74.95 609.34 78.1899 609.55 curveto +74.95 612.94 74.2998 622.51 82.6599 617.33 curveto +87.1199 624.02 92.0898 624.31 95.7598 615.82 curveto +102.89 615.38 102.31 608.69 115.78 605.52 curveto +122.76 602.86 132.77 604.58 140.26 603.72 curveto +136.22 596.88 127.44 566.86 132.98 559.8 curveto +140.76 564.7 141.84 605.38 157.03 595.66 curveto +160.56 593.93 159.91 590.04 164.09 590.18 curveto +170.42 587.45 169.13 600.77 172.51 600.77 curveto +176.47 599.76 183.02 599.04 186.98 599.54 curveto +197.71 600.77 206.93 604.08 223.92 602.5 curveto +231.12 601.78 238.25 601.06 245.45 600.34 curveto + closepath fill +newpath 305.28 560.95 moveto +304.63 560.95 299.95 561.24 299.38 561.24 curveto +302.4 550.44 303.98 536.47 304.2 525.31 curveto +303.7 521.35 299.81 517.46 299.38 525.67 curveto +295.85 530.86 296.42 540.07 293.4 540.29 curveto +287.35 539.64 285.34 513.22 280.01 509.33 curveto +276.26 512.28 280.73 524.02 275.54 524.74 curveto +270.5 524.02 264.31 526.68 266.69 534.46 curveto +270.29 543.02 268.34 554.76 266.54 561.6 curveto +262.37 578.59 264.02 587.09 271.58 596.09 curveto +267.48 604.51 lineto +275.4 608.26 285.62 604.58 290.02 602.21 curveto +294.62 600.26 300.24 595.94 301.1 587.38 curveto +303.34 578.88 304.42 569.74 305.28 560.95 curveto + closepath stroke +newpath 245.45 600.34 moveto +242.78 599.4 239.62 596.02 237.67 594.07 curveto +236.74 584.42 244.58 583.63 250.2 577.44 curveto +258.77 573.7 251.21 567.72 256.18 557.42 curveto +257.04 550.94 257.9 543.89 255.31 539.78 curveto +249.48 538.92 247.97 540.22 246.89 531.43 curveto +246.31 526.97 231.77 529.06 229.03 538.27 curveto +227.09 544.97 221.33 546.7 217.8 543.17 curveto +213.77 538.06 215.78 531.22 217.8 527.47 curveto +224.93 517.32 212.04 511.42 205.13 516.74 curveto +199.73 508.68 211.39 500.04 207.43 494.5 curveto +205.78 493.99 204.77 489.17 185.47 500.54 curveto +180.36 504.14 167.83 500.76 168.77 520.63 curveto +168.77 525.82 165.6 543.53 162.14 555.91 curveto +159.41 561.24 156.74 559.08 156.89 553.9 curveto +157.18 547.85 162.94 531.22 155.52 540.22 curveto +153.58 539.21 156.89 523.58 156.89 521.64 curveto +162 517.03 157.39 513.58 154.73 512.28 curveto +151.27 518.33 149.62 518.04 147.17 514.44 curveto +141.7 514.08 144.58 528.19 140.26 528.62 curveto +137.02 527.76 139.18 520.06 138.24 518.76 curveto +132.98 524.74 130.9 529.27 127.01 521.64 curveto +126.14 521.64 122.11 519.19 120.96 526.54 curveto +117.65 552.74 107.06 558.36 93.8198 565.13 curveto +92.0198 565.63 84.24 566.71 79.3398 568.15 curveto +73.5098 560.88 58.3198 565.63 56.23 570.31 curveto +54.7898 572.69 54.6499 575.21 54.7898 576.5 curveto +52.3398 580.1 55.8699 582.7 59.6199 583.06 curveto +62.8599 587.16 68.5398 594.94 71.2798 601.56 curveto +72.2898 603.07 74.95 609.34 78.1899 609.55 curveto +74.95 612.94 74.2998 622.51 82.6599 617.33 curveto +87.1199 624.02 92.0898 624.31 95.7598 615.82 curveto +102.89 615.38 102.31 608.69 115.78 605.52 curveto +122.76 602.86 132.77 604.58 140.26 603.72 curveto +136.22 596.88 127.44 566.86 132.98 559.8 curveto +140.76 564.7 141.84 605.38 157.03 595.66 curveto +160.56 593.93 159.91 590.04 164.09 590.18 curveto +170.42 587.45 169.13 600.77 172.51 600.77 curveto +176.47 599.76 183.02 599.04 186.98 599.54 curveto +197.71 600.77 206.93 604.08 223.92 602.5 curveto +231.12 601.78 238.25 601.06 245.45 600.34 curveto + closepath stroke +showpage +%%EOF diff --git a/doc/context/sources/general/manuals/details/hacker.jpg b/doc/context/sources/general/manuals/details/hacker.jpg Binary files differnew file mode 100644 index 000000000..cbc53a7de --- /dev/null +++ b/doc/context/sources/general/manuals/details/hacker.jpg diff --git a/doc/context/sources/general/manuals/details/mill.png b/doc/context/sources/general/manuals/details/mill.png Binary files differnew file mode 100644 index 000000000..9a1bf14e8 --- /dev/null +++ b/doc/context/sources/general/manuals/details/mill.png diff --git a/doc/context/sources/general/manuals/luatex/luatex-languages.tex b/doc/context/sources/general/manuals/luatex/luatex-languages.tex index a3790cab7..850cddb36 100644 --- a/doc/context/sources/general/manuals/luatex/luatex-languages.tex +++ b/doc/context/sources/general/manuals/luatex/luatex-languages.tex @@ -336,7 +336,7 @@ hyphenated. A side effect is that a leading hyphen can lead to a split but one will seldom run into that situation. Setting a pre and post character makes this more prominent. A value of 1 will prevent this side effect and a value of 2 will not turn the hyphen into a discretionary. Experiments with other options, like -permitting hyphenation, of the words on both sides were discarded. +permitting hyphenation of the words on both sides were discarded. \startbuffer[a] before-after \par diff --git a/doc/context/sources/general/manuals/luatex/luatex.tex b/doc/context/sources/general/manuals/luatex/luatex.tex index 6f69fadc0..79f3ba186 100644 --- a/doc/context/sources/general/manuals/luatex/luatex.tex +++ b/doc/context/sources/general/manuals/luatex/luatex.tex @@ -23,6 +23,10 @@ % "context --nodates --nocompression luatex" can be used for comparison % runs, not that we do it +% \enabledirectives[hyphenator.flatten] + +% \setupsynctex[state=start,method=max] % adds 5 pct overhead + \environment luatex-style \environment luatex-logos diff --git a/doc/context/sources/general/manuals/workflows/workflows-synctex.tex b/doc/context/sources/general/manuals/workflows/workflows-synctex.tex index 1ede3c2e4..d5b73a8e1 100644 --- a/doc/context/sources/general/manuals/workflows/workflows-synctex.tex +++ b/doc/context/sources/general/manuals/workflows/workflows-synctex.tex @@ -4,8 +4,6 @@ \startcomponent workflows-xml -\logo [SYNCTEX] {Sync\TeX} - \startchapter[title=\SYNCTEX] \startsection[title=Introduction] @@ -146,6 +144,28 @@ back to the source at all. \stopsection +\startsection[title=Methods] + +Contrary to the native \SYNCTEX\ we only deal with text which gives reasonable +efficient output. If you enable tracing (see next section) you can what has +become clickable. Instead of words you can also work with ranges, which not only +gives less runtime but also much smaller \type {.synctex} files. Just try: + +\starttyping +\setupsynctex[state=start,method=min] +\stoptyping + +to get words clickable and + +\starttyping +\setupsynctex[state=start,method=max] +\stoptyping + +to get the more efficient ranges. The overhead for \type {min} is some 10 percent +while \type {max} slows down around 5 percent. + +\stopsection + \startsection[title=Tracing] In case you want to see what gets synced you can enable a tracker: @@ -161,12 +181,12 @@ trackers only make sense for developers. \enabletrackers[system.synctex.xml] \stoptyping -At the cost of extra overhead, the next (experimental) directive can be used when -the accuracy is not optimal. - -\starttyping -\enabledirectives[system.synctex.details] -\stoptyping +% At the cost of some extra overhead, the next (experimental) directive can be used +% when the accuracy is not optimal. +% +% \starttyping +% \enabledirectives[system.synctex.details] +% \stoptyping \stopsection diff --git a/scripts/context/lua/mtx-context.lua b/scripts/context/lua/mtx-context.lua index fac310df2..02d942eb0 100644 --- a/scripts/context/lua/mtx-context.lua +++ b/scripts/context/lua/mtx-context.lua @@ -441,10 +441,9 @@ local function pdf_open(name,method) pdfview.setmethod(method) report(pdfview.status()) local pdfname = filenewsuffix(name,"pdf") - if lfs.isfile(pdfname) then - pdfview.open(pdfname) + if not lfs.isfile(pdfname) then + pdfname = name .. ".pdf" -- agressive end - pdfname = name .. ".pdf" -- agressive pdfview.open(pdfname) end diff --git a/scripts/context/lua/mtx-fonts.lua b/scripts/context/lua/mtx-fonts.lua index 3c86125b5..d077e0198 100644 --- a/scripts/context/lua/mtx-fonts.lua +++ b/scripts/context/lua/mtx-fonts.lua @@ -16,7 +16,7 @@ local lower = string.lower local concat = table.concat local write_nl = texio.write_nl -local otlversion = 3.030 +local otlversion = 3.031 local helpinfo = [[ <?xml version="1.0"?> diff --git a/scripts/context/lua/mtx-synctex.lua b/scripts/context/lua/mtx-synctex.lua new file mode 100644 index 000000000..30f3e7d51 --- /dev/null +++ b/scripts/context/lua/mtx-synctex.lua @@ -0,0 +1,255 @@ +if not modules then modules = { } end modules ['mtx-synctex'] = { + version = 1.002, + comment = "companion to mtxrun.lua", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +-- InverseSearchCmdLine = scite.exe "%f" "-goto:%l" $ +-- InverseSearchCmdLine = mtxrun.exe --script synctex --edit --name="%f" --line="%l" $ + +local tonumber = tonumber +local find, match, gsub = string.find, string.match, string.gsub +local isfile = lfs.isfile +local longtostring = string.longtostring + +local helpinfo = [[ +<?xml version="1.0"?> +<application> + <metadata> + <entry name="name">mtx-synctex</entry> + <entry name="detail">SyncTeX Checker</entry> + <entry name="version">1.00</entry> + </metadata> + <flags> + <category name="basic"> + <subcategory> + <flag name="edit"><short>open file at line: --line=.. --editor=.. sourcefile</short></flag> + <flag name="list"><short>show blob: synctexfile</short></flag> + <flag name="goto"><short>open file at position: --page=.. --x=.. --y=.. --editor=.. synctexfile</short></flag> + </subcategory> + </category> + </flags> +</application> +]] + +local application = logs.application { + name = "mtx-synctex", + banner = "ConTeXt SyncTeX Checker 1.00", + helpinfo = helpinfo, +} + +local report = application.report + +local editors = { + scite = sandbox.registerrunner { + name = "scite", + program = { + windows = "scite", + unix = "SciTE", + }, + template = longtostring [[ + "%filename%" + "-goto:%linenumber%" + ]], + }, +} + +local function validfile(filename) + if not filename or not isfile(filename) then + report("invalid synctex log file %a",filename) + return false + else + return true + end +end + +local function editfile(filename,line,editor) + if not validfile(filename) then + return + end + local runner = editors[editor or "scite"] or editors.scite + runner { + filename = filename, + linenumber = tonumber(line) or 1, + } +end + +-- In context we only care about explicitly marked horizontal blobs. And this is +-- only a check script. I know of no viewer that calls the synctex command line +-- version. Otherwise we could provide our own simplified variant and even +-- consider a more compact format (for instance we could use an "=" when the value +-- of x y w h d is the same as before, which is actually often the case for y, h +-- and d). + +local factor = (7200/7227)/65536 -- we assume unit 1 +local quit = true -- we only have one hit anyway + +local function findlocation(filename,page,xpos,ypos) + if not validfile(filename) then + return + elseif not page then + page = 1 + elseif not xpos or not ypos then + report("provide x and y coordinates (unit: basepoints)") + return + end + local files = { } + local found = false + local skip = false + local dx = false + local dy = false + local px = xpos / factor + local py = ypos / factor + local fi = 0 + local ln = 0 + for line in io.lines(filename) do + if found then + if find(line,"^}") then + break + else + -- we only look at positive cases + local f, l, x, y, w, h, d = match(line,"^h(.-),(.-):(.-),(.-):(.-),(.-),(.-)$") + if f and f ~= 0 then + x = tonumber(x) + if px >= x then + w = tonumber(w) + if px <= x + w then + y = tonumber(y) + d = tonumber(d) + if py >= y - d then + h = tonumber(h) + if py <= y + h then + if quit then + -- we have no overlapping boxes + fi = f + ln = l + break + else + local lx = px - x + local rx = x + w - px + local by = py - y + d + local ty = y + h - py + mx = lx < rx and lx or rx + my = by < ty and by or ty + if not dx then + dx = mx + dy = my + fi = f + ln = l + else + if mx < dx then + dx = mx + di = f + ln = l + end + if my < dy then + dy = my + fi = f + ln = l + end + end + end + end + end + end + end + end + end + elseif skip then + if find(line,"^}") then + skip = false + end + elseif find(line,"^{(%d+)") then + local p = tonumber(match(line,"^{(%d+)")) + if p == page then + found = true + else + skip = true + end + elseif find(line,"^Input:") then + local id, name = match(line,"^Input:(.-):(.-)$") + if id then + files[id] = name + end + end + end + if fi ~= 0 then + return files[fi], ln + end +end + +local function showlocation(filename) + if not validfile(filename) then + return + end + local files = { } + local found = false + local page = 0 + for line in io.lines(filename) do + if found then + if find(line,"^}") then + found = false + report("end page: %i",page) + else + local f, l, x, y, w, h, d = match(line,"^h(.-),(.-):(.-),(.-):(.-),(.-),(.-)$") + if f then + x = tonumber(x) + y = tonumber(y) + local llx = factor * ( x ) + local lly = factor * ( y - tonumber(d) ) + local urx = factor * ( x + tonumber(w) ) + local ury = factor * ( y + tonumber(h) ) + f = files[f] + if f then + report(" [% 4i % 4i % 4i % 4i] : % 5i : %s",llx,lly,urx,ury,l,f) + end + end + end + elseif find(line,"^{(%d+)") then + page = tonumber(match(line,"^{(%d+)")) + found = true + report("begin page: %i",page) + elseif find(line,"^Input:") then + local id, name = match(line,"^Input:(.-):(.-)$") + if id then + files[id] = name + end + end + end +end + +local function gotolocation(filename,page,xpos,ypos,editor) + if filename then + local target, line = findlocation(filename,tonumber(page),tonumber(xpos),tonumber(ypos)) + if target and line then + if editor then + editfile(target,line,editor) + else + report("filename=%a linenumber=%a",target,line) + end + end + end +end + +-- print(findlocation("oeps.synctex",4,318,348)) +-- print(findlocation("oeps.synctex",40,378,348)) +-- print(gotolocation("oeps.synctex",4,318,348,"scite")) +-- print(showlocation("oeps.synctex")) + +local argument = environment.argument +local filename = environment.files[1] + +if argument("edit") then + editfile(filename,argument("line"),argument("editor")) +elseif argument("goto") then + gotolocation(filename,argument("page"),argument("x"),argument("y"),argument("editor")) +elseif argument("list") then + showlocation(filename) +elseif argument("exporthelp") then + application.export(argument("exporthelp"),filename) +else + application.help() +end + diff --git a/scripts/context/lua/mtxrun.lua b/scripts/context/lua/mtxrun.lua index bf45d771e..e27b3712c 100644 --- a/scripts/context/lua/mtxrun.lua +++ b/scripts/context/lua/mtxrun.lua @@ -7041,7 +7041,7 @@ do -- create closure to overcome 200 locals limit package.loaded["util-fil"] = package.loaded["util-fil"] or true --- original size: 7567, stripped down to: 5575 +-- original size: 7644, stripped down to: 5642 if not modules then modules={} end modules ['util-fil']={ version=1.001, @@ -7070,7 +7070,10 @@ function files.close(f) f:close() end function files.size(f) - return f:seek("end") + local current=f:seek() + local size=f:seek("end") + f:seek("set",current) + return size end files.getsize=files.size function files.setposition(f,n) @@ -9541,7 +9544,7 @@ do -- create closure to overcome 200 locals limit package.loaded["trac-inf"] = package.loaded["trac-inf"] or true --- original size: 8263, stripped down to: 5685 +-- original size: 8253, stripped down to: 5675 if not modules then modules={} end modules ['trac-inf']={ version=1.001, @@ -9577,7 +9580,7 @@ local ticks=clock local seconds=function(n) return n or 0 end local function starttiming(instance) local timer=timers[instance or "notimer"] - local it=timer.timing or 0 + local it=timer.timing if it==0 then timer.starttime=ticks() if not timer.loadtime then @@ -9607,7 +9610,7 @@ local function stoptiming(instance) end local function elapsed(instance) if type(instance)=="number" then - return instance or 0 + return instance else local timer=timers[instance or "notimer"] return timer and seconds(timer.loadtime) or 0 @@ -20568,8 +20571,8 @@ end -- of closure -- used libraries : l-lua.lua l-sandbox.lua l-package.lua l-lpeg.lua l-function.lua l-string.lua l-table.lua l-io.lua l-number.lua l-set.lua l-os.lua l-file.lua l-gzip.lua l-md5.lua l-url.lua l-dir.lua l-boolean.lua l-unicode.lua l-math.lua util-str.lua util-tab.lua util-fil.lua util-sac.lua util-sto.lua util-prs.lua util-fmt.lua trac-set.lua trac-log.lua trac-inf.lua trac-pro.lua util-lua.lua util-deb.lua util-tpl.lua util-sbx.lua util-mrg.lua util-env.lua luat-env.lua lxml-tab.lua lxml-lpt.lua lxml-mis.lua lxml-aux.lua lxml-xml.lua trac-xml.lua data-ini.lua data-exp.lua data-env.lua data-tmp.lua data-met.lua data-res.lua data-pre.lua data-inp.lua data-out.lua data-fil.lua data-con.lua data-use.lua data-zip.lua data-tre.lua data-sch.lua data-lua.lua data-aux.lua data-tmf.lua data-lst.lua util-lib.lua luat-sta.lua luat-fmt.lua -- skipped libraries : - --- original bytes : 846296 --- stripped bytes : 306216 +-- original bytes : 846363 +-- stripped bytes : 306226 -- end library merge diff --git a/scripts/context/stubs/mswin/mtxrun.lua b/scripts/context/stubs/mswin/mtxrun.lua index bf45d771e..e27b3712c 100644 --- a/scripts/context/stubs/mswin/mtxrun.lua +++ b/scripts/context/stubs/mswin/mtxrun.lua @@ -7041,7 +7041,7 @@ do -- create closure to overcome 200 locals limit package.loaded["util-fil"] = package.loaded["util-fil"] or true --- original size: 7567, stripped down to: 5575 +-- original size: 7644, stripped down to: 5642 if not modules then modules={} end modules ['util-fil']={ version=1.001, @@ -7070,7 +7070,10 @@ function files.close(f) f:close() end function files.size(f) - return f:seek("end") + local current=f:seek() + local size=f:seek("end") + f:seek("set",current) + return size end files.getsize=files.size function files.setposition(f,n) @@ -9541,7 +9544,7 @@ do -- create closure to overcome 200 locals limit package.loaded["trac-inf"] = package.loaded["trac-inf"] or true --- original size: 8263, stripped down to: 5685 +-- original size: 8253, stripped down to: 5675 if not modules then modules={} end modules ['trac-inf']={ version=1.001, @@ -9577,7 +9580,7 @@ local ticks=clock local seconds=function(n) return n or 0 end local function starttiming(instance) local timer=timers[instance or "notimer"] - local it=timer.timing or 0 + local it=timer.timing if it==0 then timer.starttime=ticks() if not timer.loadtime then @@ -9607,7 +9610,7 @@ local function stoptiming(instance) end local function elapsed(instance) if type(instance)=="number" then - return instance or 0 + return instance else local timer=timers[instance or "notimer"] return timer and seconds(timer.loadtime) or 0 @@ -20568,8 +20571,8 @@ end -- of closure -- used libraries : l-lua.lua l-sandbox.lua l-package.lua l-lpeg.lua l-function.lua l-string.lua l-table.lua l-io.lua l-number.lua l-set.lua l-os.lua l-file.lua l-gzip.lua l-md5.lua l-url.lua l-dir.lua l-boolean.lua l-unicode.lua l-math.lua util-str.lua util-tab.lua util-fil.lua util-sac.lua util-sto.lua util-prs.lua util-fmt.lua trac-set.lua trac-log.lua trac-inf.lua trac-pro.lua util-lua.lua util-deb.lua util-tpl.lua util-sbx.lua util-mrg.lua util-env.lua luat-env.lua lxml-tab.lua lxml-lpt.lua lxml-mis.lua lxml-aux.lua lxml-xml.lua trac-xml.lua data-ini.lua data-exp.lua data-env.lua data-tmp.lua data-met.lua data-res.lua data-pre.lua data-inp.lua data-out.lua data-fil.lua data-con.lua data-use.lua data-zip.lua data-tre.lua data-sch.lua data-lua.lua data-aux.lua data-tmf.lua data-lst.lua util-lib.lua luat-sta.lua luat-fmt.lua -- skipped libraries : - --- original bytes : 846296 --- stripped bytes : 306216 +-- original bytes : 846363 +-- stripped bytes : 306226 -- end library merge diff --git a/scripts/context/stubs/unix/mtxrun b/scripts/context/stubs/unix/mtxrun index bf45d771e..e27b3712c 100644 --- a/scripts/context/stubs/unix/mtxrun +++ b/scripts/context/stubs/unix/mtxrun @@ -7041,7 +7041,7 @@ do -- create closure to overcome 200 locals limit package.loaded["util-fil"] = package.loaded["util-fil"] or true --- original size: 7567, stripped down to: 5575 +-- original size: 7644, stripped down to: 5642 if not modules then modules={} end modules ['util-fil']={ version=1.001, @@ -7070,7 +7070,10 @@ function files.close(f) f:close() end function files.size(f) - return f:seek("end") + local current=f:seek() + local size=f:seek("end") + f:seek("set",current) + return size end files.getsize=files.size function files.setposition(f,n) @@ -9541,7 +9544,7 @@ do -- create closure to overcome 200 locals limit package.loaded["trac-inf"] = package.loaded["trac-inf"] or true --- original size: 8263, stripped down to: 5685 +-- original size: 8253, stripped down to: 5675 if not modules then modules={} end modules ['trac-inf']={ version=1.001, @@ -9577,7 +9580,7 @@ local ticks=clock local seconds=function(n) return n or 0 end local function starttiming(instance) local timer=timers[instance or "notimer"] - local it=timer.timing or 0 + local it=timer.timing if it==0 then timer.starttime=ticks() if not timer.loadtime then @@ -9607,7 +9610,7 @@ local function stoptiming(instance) end local function elapsed(instance) if type(instance)=="number" then - return instance or 0 + return instance else local timer=timers[instance or "notimer"] return timer and seconds(timer.loadtime) or 0 @@ -20568,8 +20571,8 @@ end -- of closure -- used libraries : l-lua.lua l-sandbox.lua l-package.lua l-lpeg.lua l-function.lua l-string.lua l-table.lua l-io.lua l-number.lua l-set.lua l-os.lua l-file.lua l-gzip.lua l-md5.lua l-url.lua l-dir.lua l-boolean.lua l-unicode.lua l-math.lua util-str.lua util-tab.lua util-fil.lua util-sac.lua util-sto.lua util-prs.lua util-fmt.lua trac-set.lua trac-log.lua trac-inf.lua trac-pro.lua util-lua.lua util-deb.lua util-tpl.lua util-sbx.lua util-mrg.lua util-env.lua luat-env.lua lxml-tab.lua lxml-lpt.lua lxml-mis.lua lxml-aux.lua lxml-xml.lua trac-xml.lua data-ini.lua data-exp.lua data-env.lua data-tmp.lua data-met.lua data-res.lua data-pre.lua data-inp.lua data-out.lua data-fil.lua data-con.lua data-use.lua data-zip.lua data-tre.lua data-sch.lua data-lua.lua data-aux.lua data-tmf.lua data-lst.lua util-lib.lua luat-sta.lua luat-fmt.lua -- skipped libraries : - --- original bytes : 846296 --- stripped bytes : 306216 +-- original bytes : 846363 +-- stripped bytes : 306226 -- end library merge diff --git a/scripts/context/stubs/win64/mtxrun.lua b/scripts/context/stubs/win64/mtxrun.lua index bf45d771e..e27b3712c 100644 --- a/scripts/context/stubs/win64/mtxrun.lua +++ b/scripts/context/stubs/win64/mtxrun.lua @@ -7041,7 +7041,7 @@ do -- create closure to overcome 200 locals limit package.loaded["util-fil"] = package.loaded["util-fil"] or true --- original size: 7567, stripped down to: 5575 +-- original size: 7644, stripped down to: 5642 if not modules then modules={} end modules ['util-fil']={ version=1.001, @@ -7070,7 +7070,10 @@ function files.close(f) f:close() end function files.size(f) - return f:seek("end") + local current=f:seek() + local size=f:seek("end") + f:seek("set",current) + return size end files.getsize=files.size function files.setposition(f,n) @@ -9541,7 +9544,7 @@ do -- create closure to overcome 200 locals limit package.loaded["trac-inf"] = package.loaded["trac-inf"] or true --- original size: 8263, stripped down to: 5685 +-- original size: 8253, stripped down to: 5675 if not modules then modules={} end modules ['trac-inf']={ version=1.001, @@ -9577,7 +9580,7 @@ local ticks=clock local seconds=function(n) return n or 0 end local function starttiming(instance) local timer=timers[instance or "notimer"] - local it=timer.timing or 0 + local it=timer.timing if it==0 then timer.starttime=ticks() if not timer.loadtime then @@ -9607,7 +9610,7 @@ local function stoptiming(instance) end local function elapsed(instance) if type(instance)=="number" then - return instance or 0 + return instance else local timer=timers[instance or "notimer"] return timer and seconds(timer.loadtime) or 0 @@ -20568,8 +20571,8 @@ end -- of closure -- used libraries : l-lua.lua l-sandbox.lua l-package.lua l-lpeg.lua l-function.lua l-string.lua l-table.lua l-io.lua l-number.lua l-set.lua l-os.lua l-file.lua l-gzip.lua l-md5.lua l-url.lua l-dir.lua l-boolean.lua l-unicode.lua l-math.lua util-str.lua util-tab.lua util-fil.lua util-sac.lua util-sto.lua util-prs.lua util-fmt.lua trac-set.lua trac-log.lua trac-inf.lua trac-pro.lua util-lua.lua util-deb.lua util-tpl.lua util-sbx.lua util-mrg.lua util-env.lua luat-env.lua lxml-tab.lua lxml-lpt.lua lxml-mis.lua lxml-aux.lua lxml-xml.lua trac-xml.lua data-ini.lua data-exp.lua data-env.lua data-tmp.lua data-met.lua data-res.lua data-pre.lua data-inp.lua data-out.lua data-fil.lua data-con.lua data-use.lua data-zip.lua data-tre.lua data-sch.lua data-lua.lua data-aux.lua data-tmf.lua data-lst.lua util-lib.lua luat-sta.lua luat-fmt.lua -- skipped libraries : - --- original bytes : 846296 --- stripped bytes : 306216 +-- original bytes : 846363 +-- stripped bytes : 306226 -- end library merge diff --git a/tex/context/base/mkii/cont-new.mkii b/tex/context/base/mkii/cont-new.mkii index 7bfcf8614..4e4b70b10 100644 --- a/tex/context/base/mkii/cont-new.mkii +++ b/tex/context/base/mkii/cont-new.mkii @@ -11,7 +11,7 @@ %C therefore copyrighted by \PRAGMA. See mreadme.pdf for %C details. -\newcontextversion{2017.06.30 19:45} +\newcontextversion{2017.07.05 23:01} %D This file is loaded at runtime, thereby providing an %D excellent place for hacks, patches, extensions and new diff --git a/tex/context/base/mkii/context.mkii b/tex/context/base/mkii/context.mkii index 48ef7f4cd..b80487453 100644 --- a/tex/context/base/mkii/context.mkii +++ b/tex/context/base/mkii/context.mkii @@ -20,7 +20,7 @@ %D your styles an modules. \edef\contextformat {\jobname} -\edef\contextversion{2017.06.30 19:45} +\edef\contextversion{2017.07.05 23:01} %D For those who want to use this: diff --git a/tex/context/base/mkii/mult-de.mkii b/tex/context/base/mkii/mult-de.mkii index ec1fb10f4..f11749025 100644 --- a/tex/context/base/mkii/mult-de.mkii +++ b/tex/context/base/mkii/mult-de.mkii @@ -687,6 +687,7 @@ \setinterfaceconstant{bottomoffset}{untenoffset} \setinterfaceconstant{bottomspace}{bottomspace} \setinterfaceconstant{bottomstate}{untenstatus} +\setinterfaceconstant{break}{break} \setinterfaceconstant{buffer}{buffer} \setinterfaceconstant{cache}{cache} \setinterfaceconstant{calculate}{berechnen} diff --git a/tex/context/base/mkii/mult-ro.mkii b/tex/context/base/mkii/mult-ro.mkii index 26d0cd9c6..6ae2fe671 100644 --- a/tex/context/base/mkii/mult-ro.mkii +++ b/tex/context/base/mkii/mult-ro.mkii @@ -687,6 +687,7 @@ \setinterfaceconstant{bottomoffset}{offsetjos} \setinterfaceconstant{bottomspace}{spatiujos} \setinterfaceconstant{bottomstate}{starejos} +\setinterfaceconstant{break}{break} \setinterfaceconstant{buffer}{buffer} \setinterfaceconstant{cache}{cache} \setinterfaceconstant{calculate}{calculeaza} diff --git a/tex/context/base/mkiv/cont-new.mkiv b/tex/context/base/mkiv/cont-new.mkiv index 82888546f..da2b24760 100644 --- a/tex/context/base/mkiv/cont-new.mkiv +++ b/tex/context/base/mkiv/cont-new.mkiv @@ -11,7 +11,7 @@ %C therefore copyrighted by \PRAGMA. See mreadme.pdf for %C details. -\newcontextversion{2017.06.30 19:45} +\newcontextversion{2017.07.05 23:01} %D This file is loaded at runtime, thereby providing an excellent place for %D hacks, patches, extensions and new features. diff --git a/tex/context/base/mkiv/cont-run.mkiv b/tex/context/base/mkiv/cont-run.mkiv index 07154196f..ef4992c69 100644 --- a/tex/context/base/mkiv/cont-run.mkiv +++ b/tex/context/base/mkiv/cont-run.mkiv @@ -34,8 +34,11 @@ \unexpanded\def\setupsynctex[#1]% {\begingroup - \getdummyparameters[\c!state=,#1]% - \doifelse{\dummyparameter\c!state}\v!start\clf_synctexenable\clf_synctexdisable + \getdummyparameters[\c!state=\v!stop,\c!method=\v!max,#1]% + \clf_setupsynctex + state {\dummyparameter\c!state}% + method {\dummyparameter\c!method}% + \relax \endgroup} \unexpanded\def\blocksynctexfile[#1]% diff --git a/tex/context/base/mkiv/context.mkiv b/tex/context/base/mkiv/context.mkiv index 73069d51a..c142bbc64 100644 --- a/tex/context/base/mkiv/context.mkiv +++ b/tex/context/base/mkiv/context.mkiv @@ -41,7 +41,7 @@ %D up and the dependencies are more consistent. \edef\contextformat {\jobname} -\edef\contextversion{2017.06.30 19:45} +\edef\contextversion{2017.07.05 23:01} \edef\contextkind {beta} %D For those who want to use this: diff --git a/tex/context/base/mkiv/font-dsp.lua b/tex/context/base/mkiv/font-dsp.lua index f4f04d87e..2e85c2438 100644 --- a/tex/context/base/mkiv/font-dsp.lua +++ b/tex/context/base/mkiv/font-dsp.lua @@ -2511,12 +2511,12 @@ function readers.gdef(f,fontdata,specification) local tableoffset = datatable.offset setposition(f,tableoffset) local version = readulong(f) - local classoffset = tableoffset + readushort(f) - local attachmentoffset = tableoffset + readushort(f) -- used for bitmaps - local ligaturecarets = tableoffset + readushort(f) -- used in editors (maybe nice for tracing) - local markclassoffset = tableoffset + readushort(f) - local marksetsoffset = version >= 0x00010002 and (tableoffset + readushort(f)) - local varsetsoffset = version >= 0x00010003 and (tableoffset + readulong(f)) + local classoffset = readushort(f) + local attachmentoffset = readushort(f) -- used for bitmaps + local ligaturecarets = readushort(f) -- used in editors (maybe nice for tracing) + local markclassoffset = readushort(f) + local marksetsoffset = version >= 0x00010002 and readushort(f) or 0 + local varsetsoffset = version >= 0x00010003 and readulong(f) or 0 local glyphs = fontdata.glyphs local marks = { } local markclasses = setmetatableindex("table") @@ -2525,56 +2525,61 @@ function readers.gdef(f,fontdata,specification) fontdata.markclasses = markclasses fontdata.marksets = marksets -- class definitions - setposition(f,classoffset) - local classformat = readushort(f) - if classformat == 1 then - local firstindex = readushort(f) - local lastindex = firstindex + readushort(f) - 1 - for index=firstindex,lastindex do - local class = classes[readushort(f)] - if class == "mark" then - marks[index] = true - end - glyphs[index].class = class - end - elseif classformat == 2 then - local nofranges = readushort(f) - for i=1,nofranges do + if classoffset ~= 0 then + setposition(f,tableoffset + classoffset) + local classformat = readushort(f) + if classformat == 1 then local firstindex = readushort(f) - local lastindex = readushort(f) - local class = classes[readushort(f)] - if class then - for index=firstindex,lastindex do - glyphs[index].class = class - if class == "mark" then - marks[index] = true + local lastindex = firstindex + readushort(f) - 1 + for index=firstindex,lastindex do + local class = classes[readushort(f)] + if class == "mark" then + marks[index] = true + end + glyphs[index].class = class + end + elseif classformat == 2 then + local nofranges = readushort(f) + for i=1,nofranges do + local firstindex = readushort(f) + local lastindex = readushort(f) + local class = classes[readushort(f)] + if class then + for index=firstindex,lastindex do + glyphs[index].class = class + if class == "mark" then + marks[index] = true + end end end end end end -- mark classes - setposition(f,markclassoffset) - local classformat = readushort(f) - if classformat == 1 then - local firstindex = readushort(f) - local lastindex = firstindex + readushort(f) - 1 - for index=firstindex,lastindex do - markclasses[readushort(f)][index] = true - end - elseif classformat == 2 then - local nofranges = readushort(f) - for i=1,nofranges do + if markclassoffset ~= 0 then + setposition(f,tableoffset + markclassoffset) + local classformat = readushort(f) + if classformat == 1 then local firstindex = readushort(f) - local lastindex = readushort(f) - local class = markclasses[readushort(f)] + local lastindex = firstindex + readushort(f) - 1 for index=firstindex,lastindex do - class[index] = true + markclasses[readushort(f)][index] = true + end + elseif classformat == 2 then + local nofranges = readushort(f) + for i=1,nofranges do + local firstindex = readushort(f) + local lastindex = readushort(f) + local class = markclasses[readushort(f)] + for index=firstindex,lastindex do + class[index] = true + end end end end -- mark sets : todo: just make the same as class sets above - if marksetsoffset and marksetsoffset > tableoffset then -- zero offset means no table + if marksetsoffset ~= 0 then + marksetsoffset = tableoffset + marksetsoffset setposition(f,marksetsoffset) local format = readushort(f) if format == 1 then @@ -2594,9 +2599,9 @@ function readers.gdef(f,fontdata,specification) local factors = specification.factors - if (specification.variable or factors) and varsetsoffset and varsetsoffset > tableoffset then + if (specification.variable or factors) and varsetsoffset ~= 0 then - local regions, deltas = readvariationdata(f,varsetsoffset,factors) + local regions, deltas = readvariationdata(f,tableoffset+varsetsoffset,factors) -- setvariabledata(fontdata,"gregions",regions) diff --git a/tex/context/base/mkiv/font-ext.lua b/tex/context/base/mkiv/font-ext.lua index 85e39e877..cf77ac4eb 100644 --- a/tex/context/base/mkiv/font-ext.lua +++ b/tex/context/base/mkiv/font-ext.lua @@ -749,15 +749,15 @@ registerafmfeature(dimensions_specification) -- -- \definecolor[DummyColor][s=.75,t=.5,a=1] {\DummyColor test} \nopdfcompression -- --- local gray = { "special", "pdf: /Tr1 gs .75 g" } --- local black = { "special", "pdf: /Tr0 gs 0 g" } +-- local gray = { "pdf", "/Tr1 gs .75 g" } +-- local black = { "pdf", "/Tr0 gs 0 g" } -- sort of obsolete as we now have \showglyphs local push = { "push" } local pop = { "pop" } -local gray = { "special", "pdf: .75 g" } -local black = { "special", "pdf: 0 g" } +local gray = { "pdf", ".75 g" } +local black = { "pdf", "0 g" } local downcache = { } -- handy for huge cjk fonts local rulecache = { } -- handy for huge cjk fonts diff --git a/tex/context/base/mkiv/font-fbk.lua b/tex/context/base/mkiv/font-fbk.lua index 60f1a1fdf..8a5c1ebb7 100644 --- a/tex/context/base/mkiv/font-fbk.lua +++ b/tex/context/base/mkiv/font-fbk.lua @@ -300,11 +300,11 @@ end -- vf builder --- {'special', 'pdf: q ' .. s .. ' 0 0 '.. s .. ' 0 0 cm'}, --- {'special', 'pdf: q 1 0 0 1 ' .. -w .. ' ' .. -h .. ' cm'}, --- {'special', 'pdf: /Fm\XX\space Do'}, --- {'special', 'pdf: Q'}, --- {'special', 'pdf: Q'}, +-- { "pdf", "q " .. s .. " 0 0 " .. s .. " 0 0 cm" }, +-- { "pdf", "q 1 0 0 1 " .. -w .. " " .. -h .. " cm" }, +-- { "pdf", "/Fm\XX\space Do" }, +-- { "pdf", "Q" }, +-- { "pdf", "Q" }, -- new and experimental diff --git a/tex/context/base/mkiv/font-mis.lua b/tex/context/base/mkiv/font-mis.lua index 5e4da74e3..024e32831 100644 --- a/tex/context/base/mkiv/font-mis.lua +++ b/tex/context/base/mkiv/font-mis.lua @@ -21,7 +21,7 @@ local readers = otf.readers if readers then - otf.version = otf.version or 3.030 + otf.version = otf.version or 3.031 otf.cache = otf.cache or containers.define("fonts", "otl", otf.version, true) function fonts.helpers.getfeatures(name,save) diff --git a/tex/context/base/mkiv/font-ocl.lua b/tex/context/base/mkiv/font-ocl.lua index b3f368836..aca2c62bb 100644 --- a/tex/context/base/mkiv/font-ocl.lua +++ b/tex/context/base/mkiv/font-ocl.lua @@ -18,8 +18,8 @@ local tounicode = fonts.mappings.tounicode local otf = fonts.handlers.otf -local f_color = formatters["pdf:direct:%f %f %f rg"] -local f_gray = formatters["pdf:direct:%f g"] +local f_color = formatters["%f %f %f rg"] +local f_gray = formatters["%f g"] if context then @@ -49,7 +49,7 @@ end local sharedpalettes = { } local hash = setmetatableindex(function(t,k) - local v = { "special", k } + local v = { "pdf", "direct", k } t[k] = v return v end) @@ -76,11 +76,11 @@ if context then t = transparencies[v] end if c and t then - values[i] = hash["pdf:direct:" .. lpdf.color(1,c) .. " " .. lpdf.transparency(t)] + values[i] = hash[lpdf.color(1,c) .. " " .. lpdf.transparency(t)] elseif c then - values[i] = hash["pdf:direct:" .. lpdf.color(1,c)] + values[i] = hash[lpdf.color(1,c)] elseif t then - values[i] = hash["pdf:direct:" .. lpdf.color(1,t)] + values[i] = hash[lpdf.color(1,t)] end end end @@ -123,6 +123,9 @@ local function convert(t,k) return v end +local start = { "pdf", "page", "q" } +local stop = { "pdf", "raw", "Q" } + local function initializecolr(tfmdata,kind,value) -- hm, always value if value then local resources = tfmdata.resources @@ -157,13 +160,11 @@ local function initializecolr(tfmdata,kind,value) -- hm, always value local getactualtext = otf.getactualtext local default = colorvalues[#colorvalues] local b, e = getactualtext(tounicode(0xFFFD)) - local start = { "special", "pdf:page:q" } - local stop = { "special", "pdf:raw:Q" } - local actualb = { "special", "pdf:page:" .. b } -- saves tables - local actuale = { "special", "pdf:page:" .. e } -- saves tables + local actualb = { "pdf", "page", b } -- saves tables + local actuale = { "pdf", "page", e } -- saves tables -- local cache = setmetatableindex(function(t,k) - local v = { "char", k } + local v = { "char", k } -- could he a weak shared hash t[k] = v return v end) @@ -179,7 +180,7 @@ local function initializecolr(tfmdata,kind,value) -- hm, always value local goback = w ~= 0 and widths[w] or nil -- needs checking: are widths the same local t = { start, - not u and actualb or { "special", "pdf:raw:" .. getactualtext(tounicode(u)) } + not u and actualb or { "pdf", "raw", getactualtext(tounicode(u)) } } local n = 2 local l = nil @@ -328,13 +329,13 @@ local function pdftovirtual(tfmdata,pdfshapes,kind) -- kind = sbix|svg local ht = character.height or 0 local dp = character.depth or 0 character.commands = { - { "special", "pdf:direct:" .. bt }, + { "pdf", "direct", bt }, { "down", dp + dy * hfactor }, { "right", dx * hfactor }, -- setcode and { "lua", setcode } or nop, { "image", { filename = name, width = wd, height = ht, depth = dp } }, -- nilcode and { "lua", nilcode } or nop, - { "special", "pdf:direct:" .. et }, + { "pdf", "direct", et }, } character[kind] = true end diff --git a/tex/context/base/mkiv/font-otl.lua b/tex/context/base/mkiv/font-otl.lua index a338f85a8..2661ac5c1 100644 --- a/tex/context/base/mkiv/font-otl.lua +++ b/tex/context/base/mkiv/font-otl.lua @@ -52,7 +52,7 @@ local report_otf = logs.reporter("fonts","otf loading") local fonts = fonts local otf = fonts.handlers.otf -otf.version = 3.030 -- beware: also sync font-mis.lua and in mtx-fonts +otf.version = 3.031 -- beware: also sync font-mis.lua and in mtx-fonts otf.cache = containers.define("fonts", "otl", otf.version, true) otf.svgcache = containers.define("fonts", "svg", otf.version, true) otf.sbixcache = containers.define("fonts", "sbix", otf.version, true) diff --git a/tex/context/base/mkiv/font-ots.lua b/tex/context/base/mkiv/font-ots.lua index c5fa13abe..a5a039525 100644 --- a/tex/context/base/mkiv/font-ots.lua +++ b/tex/context/base/mkiv/font-ots.lua @@ -114,40 +114,45 @@ local random = math.random local formatters = string.formatters local insert = table.insert -local registertracker = trackers.register - -local logs = logs -local trackers = trackers -local nodes = nodes -local attributes = attributes -local fonts = fonts - -local otf = fonts.handlers.otf -local tracers = nodes.tracers - -local trace_singles = false registertracker("otf.singles", function(v) trace_singles = v end) -local trace_multiples = false registertracker("otf.multiples", function(v) trace_multiples = v end) -local trace_alternatives = false registertracker("otf.alternatives", function(v) trace_alternatives = v end) -local trace_ligatures = false registertracker("otf.ligatures", function(v) trace_ligatures = v end) -local trace_contexts = false registertracker("otf.contexts", function(v) trace_contexts = v end) -local trace_marks = false registertracker("otf.marks", function(v) trace_marks = v end) -local trace_kerns = false registertracker("otf.kerns", function(v) trace_kerns = v end) -local trace_cursive = false registertracker("otf.cursive", function(v) trace_cursive = v end) -local trace_preparing = false registertracker("otf.preparing", function(v) trace_preparing = v end) -local trace_bugs = false registertracker("otf.bugs", function(v) trace_bugs = v end) -local trace_details = false registertracker("otf.details", function(v) trace_details = v end) -local trace_steps = false registertracker("otf.steps", function(v) trace_steps = v end) -local trace_skips = false registertracker("otf.skips", function(v) trace_skips = v end) -local trace_directions = false registertracker("otf.directions", function(v) trace_directions = v end) -local trace_plugins = false registertracker("otf.plugins", function(v) trace_plugins = v end) -local trace_chains = false registertracker("otf.chains", function(v) trace_chains = v end) - -local trace_kernruns = false registertracker("otf.kernruns", function(v) trace_kernruns = v end) -local trace_discruns = false registertracker("otf.discruns", function(v) trace_discruns = v end) -local trace_compruns = false registertracker("otf.compruns", function(v) trace_compruns = v end) -local trace_testruns = false registertracker("otf.testruns", function(v) trace_testruns = v end) - -local optimizekerns = true +local registertracker = trackers.register + +local logs = logs +local trackers = trackers +local nodes = nodes +local attributes = attributes +local fonts = fonts + +local otf = fonts.handlers.otf +local tracers = nodes.tracers + +local trace_singles = false registertracker("otf.singles", function(v) trace_singles = v end) +local trace_multiples = false registertracker("otf.multiples", function(v) trace_multiples = v end) +local trace_alternatives = false registertracker("otf.alternatives", function(v) trace_alternatives = v end) +local trace_ligatures = false registertracker("otf.ligatures", function(v) trace_ligatures = v end) +local trace_contexts = false registertracker("otf.contexts", function(v) trace_contexts = v end) +local trace_marks = false registertracker("otf.marks", function(v) trace_marks = v end) +local trace_kerns = false registertracker("otf.kerns", function(v) trace_kerns = v end) +local trace_cursive = false registertracker("otf.cursive", function(v) trace_cursive = v end) +local trace_preparing = false registertracker("otf.preparing", function(v) trace_preparing = v end) +local trace_bugs = false registertracker("otf.bugs", function(v) trace_bugs = v end) +local trace_details = false registertracker("otf.details", function(v) trace_details = v end) +local trace_steps = false registertracker("otf.steps", function(v) trace_steps = v end) +local trace_skips = false registertracker("otf.skips", function(v) trace_skips = v end) +local trace_directions = false registertracker("otf.directions", function(v) trace_directions = v end) +local trace_plugins = false registertracker("otf.plugins", function(v) trace_plugins = v end) +local trace_chains = false registertracker("otf.chains", function(v) trace_chains = v end) + +local trace_kernruns = false registertracker("otf.kernruns", function(v) trace_kernruns = v end) +local trace_discruns = false registertracker("otf.discruns", function(v) trace_discruns = v end) +local trace_compruns = false registertracker("otf.compruns", function(v) trace_compruns = v end) +local trace_testruns = false registertracker("otf.testruns", function(v) trace_testruns = v end) + +local forcediscretionaries = false +local optimizekerns = true + +directives.register("otf.forcediscretionaries",function(v) + forcediscretionaries = v +end) local report_direct = logs.reporter("fonts","otf direct") local report_subchain = logs.reporter("fonts","otf subchain") @@ -225,7 +230,7 @@ local math_code = nodecodes.math local dir_code = nodecodes.dir local localpar_code = nodecodes.localpar ------ discretionary_code = disccodes.discretionary +local discretionary_code = disccodes.discretionary local ligature_code = glyphcodes.ligature local a_state = attributes.private('state') @@ -566,7 +571,11 @@ local function toligature(head,start,stop,char,dataset,sequence,markflag,discfou -- here components have a pointer so we can't free it! set_components(base,copied) replace = base - setdisc(discfound,pre,post,replace) -- was discretionary_code + if forcediscretionaries then + setdisc(discfound,pre,post,replace,discretionary_code) + else + setdisc(discfound,pre,post,replace) + end base = prev end end diff --git a/tex/context/base/mkiv/font-shp.lua b/tex/context/base/mkiv/font-shp.lua index 6e21848a4..c465ec91b 100644 --- a/tex/context/base/mkiv/font-shp.lua +++ b/tex/context/base/mkiv/font-shp.lua @@ -362,7 +362,7 @@ local function addvariableshapes(tfmdata,key,value) -- we need inline in order to support color local bt, et = getactualtext(char.tounicode or char.unicode or unicode) char.commands = { - { "special", "pdf:" .. segmentstopdf(segments,factor,bt,et) } + { "pdf", segmentstopdf(segments,factor,bt,et) } } end end diff --git a/tex/context/base/mkiv/lang-dis.lua b/tex/context/base/mkiv/lang-dis.lua index e2c0d220e..50150d9e2 100644 --- a/tex/context/base/mkiv/lang-dis.lua +++ b/tex/context/base/mkiv/lang-dis.lua @@ -267,40 +267,58 @@ end local wiped = 0 -local function wipe(head,delayed) - local p, n = getboth(delayed) - local _, _, h, _, _, t = getdisc(delayed,true) - if p or n then - if h then - setlink(p,h) - setlink(t,n) - setfield(delayed,"replace") - else - setlink(p,n) - end +local flatten_discretionaries = node.flatten_discretionaries -- todo in nodes + +if flatten_discretionaries then + + -- This is not that much faster than the lua variant simply because there is + -- seldom a replace list but it fits in the picture. See luatex-todo.w for the + -- code. + + function languages.flatten(head) + local h, n = flatten_discretionaries(head) + wiped = wiped + n + return h, n > 0 end - if head == delayed then - head = h + +else + + local function wipe(head,delayed) + local p, n = getboth(delayed) + local _, _, h, _, _, t = getdisc(delayed,true) + if p or n then + if h then + setlink(p,h) + setlink(t,n) + setfield(delayed,"replace") + else + setlink(p,n) + end + end + if head == delayed then + head = h + end + wiped = wiped + 1 + flush_node(delayed) + return head end - wiped = wiped + 1 - flush_node(delayed) - return head -end -function languages.flatten(head) - local nuthead = tonut(head) - local delayed = nil - for d in traverse_id(disc_code,nuthead) do + function languages.flatten(head) + local nuthead = tonut(head) + local delayed = nil + for d in traverse_id(disc_code,nuthead) do + if delayed then + nuthead = wipe(nuthead,delayed) + end + delayed = d + end if delayed then - nuthead = wipe(nuthead,delayed) + return tonode(wipe(nuthead,delayed)), true + else + return head, false end - delayed = d - end - if delayed then - return tonode(wipe(nuthead,delayed)), true - else - return head, false end + end function languages.nofflattened() diff --git a/tex/context/base/mkiv/lpdf-col.lua b/tex/context/base/mkiv/lpdf-col.lua index b5973ba88..af01c7dd2 100644 --- a/tex/context/base/mkiv/lpdf-col.lua +++ b/tex/context/base/mkiv/lpdf-col.lua @@ -703,29 +703,29 @@ end -- this will move to lpdf-spe.lua -local f_slant = formatters["pdf: q 1 0 %F 1 0 0 cm"] +local f_slant = formatters["q 1 0 %F 1 0 0 cm"] backends.pdf.tables.vfspecials = allocate { -- todo: distinguish between glyph and rule color - red = { "special", 'pdf: 1 0 0 rg 1 0 0 RG' }, - green = { "special", 'pdf: 0 1 0 rg 0 1 0 RG' }, - blue = { "special", 'pdf: 0 0 1 rg 0 0 1 RG' }, - gray = { "special", 'pdf: .75 g .75 G' }, - black = { "special", 'pdf: 0 g 0 G' }, + red = { "pdf", "1 0 0 rg 1 0 0 RG" }, + green = { "pdf", "0 1 0 rg 0 1 0 RG" }, + blue = { "pdf", "0 0 1 rg 0 0 1 RG" }, + gray = { "pdf", ".75 g .75 G" }, + black = { "pdf", "0 g 0 G" }, rulecolors = { - red = { "special", 'pdf: 1 0 0 rg' }, - green = { "special", 'pdf: 0 1 0 rg' }, - blue = { "special", 'pdf: 0 0 1 rg' }, - gray = { "special", 'pdf: .5 g' }, - black = { "special", 'pdf: 0 g' }, - palered = { "special", 'pdf: 1 .75 .75 rg' }, - palegreen = { "special", 'pdf: .75 1 .75 rg' }, - paleblue = { "special", 'pdf: .75 .75 1 rg' }, - palegray = { "special", 'pdf: .75 g' }, + red = { "pdf", '1 0 0 rg' }, + green = { "pdf", '0 1 0 rg' }, + blue = { "pdf", '0 0 1 rg' }, + gray = { "pdf", '.5 g' }, + black = { "pdf", '0 g' }, + palered = { "pdf", '1 .75 .75 rg' }, + palegreen = { "pdf", '.75 1 .75 rg' }, + paleblue = { "pdf", '.75 .75 1 rg' }, + palegray = { "pdf", '.75 g' }, }, - startslant = function(a) return { "special", f_slant(a) } end, - stopslant = { "special", "pdf: Q" }, + startslant = function(a) return { "pdf", f_slant(a) } end, + stopslant = { "pdf", "Q" }, } diff --git a/tex/context/base/mkiv/luat-run.lua b/tex/context/base/mkiv/luat-run.lua index 0d30ad11b..b194e755e 100644 --- a/tex/context/base/mkiv/luat-run.lua +++ b/tex/context/base/mkiv/luat-run.lua @@ -20,11 +20,13 @@ local report_lua = logs.reporter("system","lua") local report_tex = logs.reporter("system","status") local report_tempfiles = logs.reporter("resolvers","tempfiles") -luatex = luatex or { } -local luatex = luatex +luatex = luatex or { } +local luatex = luatex +local synctex = luatex.synctex -if not luatex.synctex then - luatex.synctex = table.setmetatableindex(function() return function() end end) +if not synctex then + synctex = table.setmetatableindex(function() return function() end end) + luatex.synctex = synctex end local startactions = { } @@ -64,6 +66,7 @@ local function stop_run() end local function start_shipout_page() + synctex.start() logs.start_page_number() end @@ -72,7 +75,7 @@ local function stop_shipout_page() for i=1,#pageactions do pageactions[i]() end - luatex.synctex.flush() + synctex.stop() end local function report_output_pages() @@ -96,7 +99,7 @@ local function pre_dump_actions() end local function wrapup_synctex() - luatex.synctex.wrapup() + synctex.wrapup() end -- this can be done later @@ -193,7 +196,7 @@ local function report_start(left,name) level = level + 1 -- report_open("%i > %i > %s",level,total,name or "?") report_open("level %i, order %i, name %a",level,total,name or "?") - luatex.synctex.setfilename(name) + synctex.setfilename(name) end end diff --git a/tex/context/base/mkiv/m-fonts-plugins.mkiv b/tex/context/base/mkiv/m-fonts-plugins.mkiv index ecb311694..7678f820c 100644 --- a/tex/context/base/mkiv/m-fonts-plugins.mkiv +++ b/tex/context/base/mkiv/m-fonts-plugins.mkiv @@ -132,6 +132,8 @@ liga=yes, kern=yes] +% no tlig and no analyze + \definefontfeature [test-node] [mode=node, diff --git a/tex/context/base/mkiv/meta-fnt.lua b/tex/context/base/mkiv/meta-fnt.lua index 95bdfa6d9..ea7f6f2bc 100644 --- a/tex/context/base/mkiv/meta-fnt.lua +++ b/tex/context/base/mkiv/meta-fnt.lua @@ -66,7 +66,7 @@ local flusher = { if inline then characters[slot] = { commands = { - { "special", "pdf:" .. code }, + { "pdf", code }, } } else diff --git a/tex/context/base/mkiv/node-syn.lua b/tex/context/base/mkiv/node-syn.lua index 2fdea49c1..bd8cc7964 100644 --- a/tex/context/base/mkiv/node-syn.lua +++ b/tex/context/base/mkiv/node-syn.lua @@ -6,33 +6,51 @@ if not modules then modules = { } end modules ['node-syn'] = { license = "see context related readme files" } --- Because we have these fields in some node that are used by synctex, I decided (because --- some users seem to like that feature) to implement a variant that might work out better --- for ConTeXt. This is experimental code. I don't use it myself so it will take a while --- to mature. There will be some helpers that one can use in more complex situations like --- included xml files. +-- Because we have these fields in some node that are used by synctex, and because +-- some users seem to like that feature, I decided to implement a variant that might +-- work out better for ConTeXt. This is experimental code. I don't use it myself so +-- it will take a while to mature. There will be some helpers that one can use in +-- more complex situations like included xml files. Currently (somewhere else) we +-- take care of valid files, that is: we prohibit access to files in the tree +-- because we don't want users to mess up styles. -- --- It is unclear how the output gets interpreted. For instance, we only need to be able to --- go back to a place where text is entered, but still we need all that redundant box --- wrapping. +-- It is unclear how the output gets interpreted but by reverse engineering (and +-- stripping) the file generated by generic synctex, I got there eventually. For +-- instance, we only need to be able to go back to a place where text is entered, +-- but still we need all that redundant box wrapping. Anyway, I was able to get a +-- minimal output and cross my fingers that the parser used in editors is not +-- changed in fundamental ways. -- --- Possible optimizations: pack whole lines. - --- InverseSearchCmdLine = mtxrun.exe --script synctex --edit --name="%f" --line="%l" $ - --- Unfortunately syntex always removes the files at the end and not at the start (it --- happens in synctexterminate). This forces us to use an intermediate file, no big deal --- in context (which has a runner) but definitely not nice. +-- I only tested SumatraPDF with SciTE, for which one needs to configure in the +-- viewer: +-- +-- InverseSearchCmdLine = c:\data\system\scite\wscite\scite.exe "%f" "-goto:%l" $ +-- +-- Unfortunately syntex always removes the files at the end and not at the start +-- (this happens in synctexterminate) so we need to work around that by using an +-- intermediate file. This is no big deal in context (which has a runner) but +-- definitely not nice. +-- +-- The visualizer code is only needed for testing so we don't use fancy colors or +-- provide more detail. After all we're only interested in rendered source text +-- anyway. We try to play safe which sometimes means that we'd better no go +-- somewhere than go someplace wrong. +-- +-- A previous version had a mode for exporting boxes and such but I removed that +-- as it made no sense. Also, collecting output in a table was not faster than +-- directly piping to the file, probably because the amount is not that large. We +-- keep some left-overs commented. local type, rawset = type, rawset local concat = table.concat local formatters = string.formatters -local replacesuffix = file.replacesuffix - -local trace = false trackers.register("system.synctex.visualize", function(v) trace = v end) +local replacesuffix, suffixonly, nameonly = file.replacesuffix, file.suffix, file.nameonly +local openfile, renamefile, removefile = io.open, os.rename, os.remove local report_system = logs.reporter("system") +local tex = tex + local nuts = nodes.nuts local tonut = nuts.tonut local tonode = nuts.tonode @@ -48,14 +66,13 @@ local getsubtype = nuts.getsubtype local nodecodes = nodes.nodecodes local kerncodes = nodes.kerncodes +local glyph_code = nodecodes.glyph +local disc_code = nodecodes.disc local glue_code = nodecodes.glue local kern_code = nodecodes.kern -local kern_disc = nodecodes.disc -local rule_code = nodecodes.rule ------ math_code = nodecodes.math +----- rule_code = nodecodes.rule local hlist_code = nodecodes.hlist local vlist_code = nodecodes.vlist -local glyph_code = nodecodes.glyph local fontkern_code = kerncodes.fontkern local insert_before = nuts.insert_before @@ -77,36 +94,31 @@ local force_synctex_tag = tex.force_synctex_tag local force_synctex_line = tex.force_synctex_line ----- get_synctex_tag = tex.get_synctex_tag ----- get_synctex_line = tex.get_synctex_line - -local getcount = tex.getcount -local setcount = tex.setcount +local set_synctex_mode = tex.set_synctex_mode local getpos = function() getpos = backends.codeinjections.getpos return getpos() end +local foundintree = resolvers.foundintree local eol = "\010" -local f_glue = formatters["g%i,%i:%i,%i"] -local f_glyph = formatters["x%i,%i:%i,%i"] -local f_kern = formatters["k%i,%i:%i,%i:%i"] -local f_rule = formatters["r%i,%i:%i,%i:%i,%i,%i"] -local f_hlist = formatters["[%i,%i:%i,%i:%i,%i,%i"] -local f_vlist = formatters["(%i,%i:%i,%i:%i,%i,%i"] -local s_hlist = "]" -local s_vlist = ")" -local f_hvoid = formatters["h%i,%i:%i,%i:%i,%i,%i"] -local f_vvoid = formatters["v%i,%i:%i,%i:%i,%i,%i"] - -local characters = fonts.hashes.characters - -local foundintree = resolvers.foundintree -local suffixonly = file.suffix -local nameonly = file.nameonly - -local synctex = { } +----- f_glue = formatters["g%i,%i:%i,%i\010"] +----- f_glyph = formatters["x%i,%i:%i,%i\010"] +----- f_kern = formatters["k%i,%i:%i,%i:%i\010"] +----- f_rule = formatters["r%i,%i:%i,%i:%i,%i,%i\010"] +----- f_hlist = formatters["[%i,%i:%i,%i:%i,%i,%i\010"] +----- f_vlist = formatters["(%i,%i:%i,%i:%i,%i,%i\010"] +local z_hlist = "[0,0:0,0:0,0,0\010" +local z_vlist = "(0,0:0,0:0,0,0\010" +local s_hlist = "]\010" +local s_vlist = ")\010" +local f_hvoid = formatters["h%i,%i:%i,%i:%i,%i,%i\010"] +----- f_vvoid = formatters["v%i,%i:%i,%i:%i,%i,%i\010"] + +local synctex = luatex.synctex or { } luatex.synctex = synctex -- the file name stuff @@ -168,22 +180,19 @@ end -- the node stuff -local result = { } -local r = 0 -local f = nil +local filehandle = nil local nofsheets = 0 local nofobjects = 0 local last = 0 local filesdone = 0 local enabled = false -local compact = true -local fulltrace = false +local tmpfile = false local logfile = false local used = false local function writeanchor() - local size = f:seek("end") - f:write("!" .. (size-last) ..eol) + local size = filehandle:seek("end") + filehandle:write("!",size-last,eol) last = size end @@ -191,310 +200,295 @@ local function writefiles() local total = #stnums if filesdone < total then for i=filesdone+1,total do - f:write("Input:"..i..":"..stnums[i]..eol) + filehandle:write("Input:",i,":",stnums[i],eol) end filesdone = total end end +local function makenames() + logfile = replacesuffix(tex.jobname,"synctex") + tmpfile = replacesuffix(logfile,"syncctx") +end + local function flushpreamble() - logfile = replacesuffix(tex.jobname,"syncctx") - f = io.open(logfile,"wb") - f:write("SyncTeX Version:1"..eol) - writefiles() - f:write("Output:pdf"..eol) - f:write("Magnification:1000"..eol) - f:write("Unit:1"..eol) - f:write("X Offset:0"..eol) - f:write("Y Offset:0"..eol) - f:write("Content:"..eol) - flushpreamble = writefiles + makenames() + filehandle = openfile(tmpfile,"wb") + if filehandle then + filehandle:write("SyncTeX Version:1",eol) + writefiles() + filehandle:write("Output:pdf",eol) + filehandle:write("Magnification:1000",eol) + filehandle:write("Unit:1",eol) + filehandle:write("X Offset:0",eol) + filehandle:write("Y Offset:0",eol) + filehandle:write("Content:",eol) + flushpreamble = function() + writefiles() + return filehandle + end + else + enabled = false + end + return filehandle end function synctex.wrapup() - if logfile then - os.rename(logfile,replacesuffix(logfile,"synctex")) + if tmpfile then + renamefile(tmpfile,logfile) end end local function flushpostamble() - if not f then + if not filehandle then return end writeanchor() - f:write("Postamble:"..eol) - f:write("Count:"..nofobjects..eol) + filehandle:write("Postamble:",eol) + filehandle:write("Count:",nofobjects,eol) writeanchor() - f:write("Post scriptum:"..eol) - f:close() + filehandle:write("Post scriptum:",eol) + filehandle:close() enabled = false end -local pageheight = 0 -- todo: set before we do this! - -local function b_hlist(head,current,t,l,w,h,d) - return insert_before(head,current,new_latelua(function() - local x, y = getpos() - r = r + 1 - result[r] = f_hlist(t,l,x,tex.pageheight-y,w,h,d) - nofobjects = nofobjects + 1 - end)) -end - -local function b_vlist(head,current,t,l,w,h,d) - return insert_before(head,current,new_latelua(function() - local x, y = getpos() - r = r + 1 - result[r] = f_vlist(t,l,x,tex.pageheight-y,w,h,d) - nofobjects = nofobjects + 1 - end)) -end - -local function e_hlist(head,current) - return insert_after(head,current,new_latelua(function() - r = r + 1 - result[r] = s_hlist - nofobjects = nofobjects + 1 - end)) -end - -local function e_vlist(head,current) - return insert_after(head,current,new_latelua(function() - r = r + 1 - result[r] = s_vlist - nofobjects = nofobjects + 1 - end)) -end - -local function x_hlist(head,current,t,l,w,h,d) - return insert_before(head,current,new_latelua(function() - local x, y = getpos() - r = r + 1 - result[r] = f_hvoid(t,l,x,tex.pageheight-y,w,h,d) - nofobjects = nofobjects + 1 - end)) -end - -local function x_vlist(head,current,t,l,w,h,d) - return insert_before(head,current,new_latelua(function() - local x, y = getpos() - r = r + 1 - result[r] = f_vvoid(t,l,x,tex.pageheight-y,w,h,d) - nofobjects = nofobjects + 1 - end)) -end - --- local function x_glyph(head,current,t,l) --- return insert_before(head,current,new_latelua(function() --- local x, y = getpos() --- r = r + 1 --- result[r] = f_glyph(t,l,x,tex.pageheight-y) --- nofobjects = nofobjects + 1 --- end)) +-- local function doaction(action,t,l,w,h,d) +-- local x, y = getpos() +-- filehandle:write(action(t,l,x,tex.pageheight-y,w,h,d)) +-- nofobjects = nofobjects + 1 -- end - --- local function x_glue(head,current,t,l) --- return insert_before(head,current,new_latelua(function() --- local x, y = getpos() --- r = r + 1 --- result[r] = f_glue(t,l,x,tex.pageheight-y) --- nofobjects = nofobjects + 1 --- end)) +-- +-- local function noaction(action) +-- filehandle:write(action) +-- nofobjects = nofobjects + 1 -- end - --- local function x_kern(head,current,t,l,k) --- return insert_before(head,current,new_latelua(function() --- local x, y = getpos() --- r = r + 1 --- result[r] = f_kern(t,l,x,tex.pageheight-y,k) --- nofobjects = nofobjects + 1 --- end)) +-- +-- local function b_vlist(head,current,t,l,w,h,d) +-- return insert_before(head,current,new_latelua(function() doaction(f_vlist,t,l,w,h,d) end)) -- end - --- local function x_rule(head,current,t,l,w,h,d) --- return insert_before(head,current,new_latelua(function() --- local x, y = getpos() --- r = r + 1 --- result[r] = f_rule(t,l,x,tex.pageheight-y,w,h,d) --- nofobjects = nofobjects + 1 --- end)) +-- +-- local function b_hlist(head,current,t,l,w,h,d) +-- return insert_before(head,current,new_latelua(function() doaction(f_hlist,t,l,w,h,d) end)) +-- end +-- +-- local function e_vlist(head,current) +-- return insert_after(head,current,new_latelua(noaction(s_vlist))) -- end +-- +-- local function e_hlist(head,current) +-- return insert_after(head,current,new_latelua(noaction(s_hlist))) +-- end +-- +-- local function x_vlist(head,current,t,l,w,h,d) +-- return insert_before(head,current,new_latelua(function() doaction(f_vvoid,t,l,w,h,d) end)) +-- end +-- +-- local function x_hlist(head,current,t,l,w,h,d) +-- return insert_before(head,current,new_latelua(function() doaction(f_hvoid,t,l,w,h,d) end)) +-- end + +local function doaction(t,l,w,h,d) + local x, y = getpos() + filehandle:write(f_hvoid(t,l,x,tex.pageheight-y,w,h,d)) + nofobjects = nofobjects + 1 +end --- todo: why not only lines --- todo: larger ranges +local function x_hlist(head,current,t,l,w,h,d) + return insert_before(head,current,new_latelua(function() doaction(t,l,w,h,d) end)) +end -- color is already handled so no colors --- we can have ranges .. more efficient but a bit more complex to analyze ... some day +local collect = nil +local fulltrace = false +local trace = false +local height = 10 * 65536 +local depth = 5 * 65536 +local traceheight = 32768 +local tracedepth = 32768 + +trackers.register("system.synctex.visualize", function(v) + trace = v + fulltrace = v == "real" +end) + +local function inject(head,first,last,tag,line) + local w, h, d = getdimensions(first,getnext(last)) + if h < height then + h = height + end + if d < depth then + d = depth + end + if trace then + head = insert_before(head,first,new_hlist(new_rule(w,fulltrace and h or traceheight,fulltrace and d or tracedepth))) + end + head = x_hlist(head,first,tag,line,w,h,d) + return head +end -local function collect(head,t,l,dp,ht) +local function collect_min(head) local current = head while current do local id = getid(current) if id == glyph_code then local first = current local last = current + local tag = 0 + local line = 0 while true do - id = getid(current) - -- traditionally glyphs have no synctex code which works sort of ok - -- but not when we don't leave hmode cq. have no par - -- - if id == glyph_code or id == disc_code then + if id == glyph_code then local tc, lc = get_synctex_fields(current) if tc and tc > 0 then - t, l = tc, lc + tag = tc + line = lc end last = current - elseif id == kern_code and getsubtype(current) == fontkern_code then - local tc, lc = get_synctex_fields(current) - if tc and tc > 0 then - t, l = tc, lc - end + elseif id == disc_code or (id == kern_code and getsubtype(current) == fontkern_code) then last = current else - if id == glue_code then - -- we could go on when we're in the same t/l run - local tc, lc = get_synctex_fields(current) - if tc > 0 then - t, l = tc, lc - end - id = nil -- so no test later on - end - local w, h, d = getdimensions(first,getnext(last)) - -- local w, h, d = getrangedimensions(head,first,getnext(last)) - if dp and d < dp then d = dp end - if ht and h < ht then h = ht end - if h < 655360 then h = 655360 end - if d < 327680 then d = 327680 end - if trace then - head = insert_before(head,first,new_hlist(new_rule(w,fulltrace and h or 32768,fulltrace and d or 32768))) + if tag > 0 then + head = inject(head,first,last,tag,line) end - head = x_hlist(head,first,t,l,w,h,d) break end current = getnext(current) - if not current then - local w, h, d = getdimensions(first,getnext(last)) - -- local w, h, d = getrangedimensions(head,first,getnext(last)) - if dp and d < dp then d = dp end - if ht and h < ht then h = ht end - if h < 655360 then h = 655360 end - if d < 327680 then d = 327680 end - if trace then - head = insert_before(head,first,new_hlist(new_rule(w,fulltrace and h or 32768,fulltrace and d or 32768))) + if current then + id = getid(current) + else + if tag > 0 then + head = inject(head,first,last,tag,line) end - head = x_hlist(head,first,t,l,w,h,d) return head end end end - if id == hlist_code then + -- pick up (as id can have changed) + if id == hlist_code or id == vlist_code then local list = getlist(current) - local tc, lc = get_synctex_fields(current) - if tc > 0 then - t, l = tc, lc - end - if compact then - if list then - local l = collect(list,t,l) - if l ~= list then - setlist(current,l) - end + if list then + local l = collect(list) + if l ~= list then + setlist(current,l) end - else - local w, h, d = getwhd(current) - if w == 0 or (h == 0 and d == 0) then - if list then - local l = collect(list,t,l) - if l ~= list then - setlist(current,l) + end + end + current = getnext(current) + end + return head +end + +collect = collect_max + +local function inject(parent,head,first,last,tag,line) + local w, h, d = getrangedimensions(parent,first,getnext(last)) + if h < height then + h = height + end + if d < depth then + d = depth + end + if trace then + head = insert_before(head,first,new_hlist(new_rule(w,fulltrace and h or traceheight,fulltrace and d or tracedepth))) + end + head = x_hlist(head,first,tag,line,w,h,d) + return head +end + +local function collect_max(head,parent) + local current = head + while current do + local id = getid(current) + if id == glyph_code then + local first = current + local last = current + local tag = 0 + local line = 0 + while true do + if id == glyph_code then + local tc, lc = get_synctex_fields(current) + if tc and tc > 0 then + if tag > 0 and (tag ~= tc or line ~= lc) then + head = inject(parent,head,first,last,tag,line) + first = current end + tag = tc + line = lc + last = current + else + if tag > 0 then + head = inject(parent,head,first,last,tag,line) + tag = 0 + end + first = nil + last = nil end - elseif list then - -- head = b_hlist(head,current,t,l,w,h,d) - head = b_hlist(head,current,0,0,w,h,d) -- todo: only d h when line - local l = collect(list,t,l,d,h) - if l ~= list then - setlist(current,l) + elseif id == disc_code then + if not first then + first = current end - head, current = e_hlist(head,current) - else - -- head = x_hlist(head,current,t,l,w,h,d) - head = x_hlist(head,current,0,0,w,h,d) -- todo: only d h when line - end - end - elseif id == vlist_code then - local list = getlist(current) - local tc, lc = get_synctex_fields(current) - if tc > 0 then - t, l = tc, lc - end - if compact then - if list then - local l = collect(list,t,l) - if l ~= list then - setlist(current,l) + last = current + elseif id == kern_code and getsubtype(current) == fontkern_code then + if first then + last = current end - end - else - local w, h, d = getwhd(current) - if w == 0 or (h == 0 and d == 0) then - if list then - local l = collect(list,t,l) - if l ~= list then - setlist(current,l) + elseif id == glue_code then + if tag > 0 then + local tc, lc = get_synctex_fields(current) + if tc and tc > 0 then + if tag ~= tc or line ~= lc then + head = inject(parent,head,first,last,tag,line) + tag = 0 + break + end + else + head = inject(parent,head,first,last,tag,line) + tag = 0 + break end + else + tag = 0 + break end - elseif list then - -- head = b_vlist(head,current,t,l,w,h,d) - head = b_vlist(head,current,0,0,w,h,d) - local l = collect(list,t,l) - if l ~= list then - setlist(current,l) + id = nil -- so no test later on + else + if tag > 0 then + head = inject(parent,head,first,last,tag,line) + tag = 0 end - head, current = e_vlist(head,current) + break + end + current = getnext(current) + if current then + id = getid(current) else - -- head = x_vlist(head,current,t,l,w,h,d) - head = x_vlist(head,current,0,0,w,h,d) + if tag > 0 then + head = inject(parent,head,first,last,tag,line) + end + return head end end - elseif id == glue_code then - local tc, lc = get_synctex_fields(current) - if tc > 0 then - t, l = tc, lc + end + -- pick up(as id can have changed) + if id == hlist_code or id == vlist_code then + local list = getlist(current) + if list then + local l = collect(list,current) + if l ~= list then + setlist(current,l) + end end - -- head = x_glue(head,current,t,l) - -- elseif id == kern_code then - -- local tc, lc = get_synctex_fields(current) - -- if tc > 0 then - -- t, l = tc, lc - -- end - -- -- local k = getwidth(current) - -- -- if k ~= 0 then - -- -- head = x_kern(head,current,t,l,k) - -- -- end - -- elseif id == rule_code then - -- local tc, lc = get_synctex_fields(current) - -- if tc > 0 then - -- t, l = tc, lc - -- end - -- -- if t > 0 and l > 0 then - -- -- local w, h, d = getwhd(current) - -- -- head = x_rule(head,current,t,l,w,h,d) - -- -- end end current = getnext(current) end return head end --- range of same numbers - function synctex.collect(head) if enabled then - result, r = { }, 0 - head = collect(tonut(head),0,0) - return tonode(head), true + local h = tonut(head) + h = collect(h,h) + return tonode(h), true else return head, false end @@ -502,106 +496,73 @@ end -- also no solution for bad first file resolving in sumatra -function synctex.flush() +function synctex.start() if enabled then nofsheets = nofsheets + 1 -- could be realpageno - flushpreamble() - writeanchor() - f:write("{"..nofsheets..eol) - if compact then - -- f:write(f_vlist(0,0,0,0,tex.pagewidth,tex.pageheight,0)) - f:write(f_hlist(0,0,0,0,0,0,0)) - f:write(eol) - f:write(f_vlist(0,0,0,0,0,0,0)) - f:write(eol) + if flushpreamble() then + writeanchor() + filehandle:write("{",nofsheets,eol) + filehandle:write(z_hlist,z_vlist) end - f:write(concat(result,eol)) - if compact then - f:write(eol) - f:write(s_vlist) - f:write(eol) - f:write(s_hlist) - end - f:write(eol) + end +end + +function synctex.stop() + if enabled then + filehandle:write(s_vlist,s_hlist) writeanchor() - f:write("}"..nofsheets..eol) + filehandle:write("}",nofsheets,eol) nofobjects = nofobjects + 2 - result, r = { }, 0 end end -local details = 1 -local state = 0 - -directives.register("system.synctex.details",function(v) - details = tonumber(v) or 1 -end) - -local set_synctex_mode = tex.set_synctex_mode - -if set_synctex_mode then - - function synctex.enable() - if not enabled then - enabled = true - state = details or 1 - set_synctex_mode(state) - if not used then - directives.enable("system.synctex.xml") - nodes.tasks.appendaction("shipouts", "after", "nodes.synctex.collect") - report_system("synctex functionality is enabled, expect runtime overhead!") - used = true - end - elseif state > 0 then - set_synctex_mode(state) +function synctex.enable() + if not enabled then + enabled = true + set_synctex_mode(3) -- we want details + if not used then + directives.enable("system.synctex.xml") + nodes.tasks.appendaction("shipouts", "after", "luatex.synctex.collect") + report_system("synctex functionality is enabled, expect 5-10 pct runtime overhead!") + used = true end end +end - function synctex.disable() - if enabled then - set_synctex_mode(0) - report_system("synctex functionality is disabled!") - enabled = false - end +function synctex.disable() + if enabled then + set_synctex_mode(0) + report_system("synctex functionality is disabled!") + enabled = false end +end - function synctex.finish() - if enabled then - flushpostamble() - else - os.remove(replacesuffix(tex.jobname,"syncctx")) - os.remove(replacesuffix(tex.jobname,"synctex")) - end +function synctex.finish() + if enabled then + flushpostamble() + else + makenames() + removefile(logfile) + removefile(tmpfile) end +end - function synctex.pause() - if enabled then - set_synctex_mode(0) - end +function synctex.pause() + if enabled then + set_synctex_mode(0) end +end - function synctex.resume() - if enabled then - set_synctex_mode(state) - end +function synctex.resume() + if enabled then + set_synctex_mode(3) end - -else - - function synctex.enable () end - function synctex.disable() end - function synctex.finish () end - function synctex.pause () end - function synctex.resume () end - end -- not the best place luatex.registerstopactions(synctex.finish) -nodes.tasks.appendaction("shipouts", "after", "luatex.synctex.collect") - directives.register("system.synctex", function(v) if v then synctex.enable() @@ -612,7 +573,8 @@ end) statistics.register("synctex tracing",function() if used then - return string.format("%i referenced files, %i files ignored, logfile: %s",noftags,nofblocked,logfile) + return string.format("%i referenced files, %i files ignored, %i objects flushed, logfile: %s", + noftags,nofblocked,nofobjects,logfile) end end) @@ -634,13 +596,25 @@ interfaces.implement { } interfaces.implement { - name = "synctexenable", - actions = synctex.enable, -} - -interfaces.implement { - name = "synctexdisable", - actions = synctex.disable, + name = "setupsynctex", + arguments = { + { + { "state" }, + { "method" }, + }, + }, + actions = function(t) + if t.method == interfaces.variables.max then + collect = collect_max + else + collect = collect_min + end + if t.state == interfaces.variables.start then + synctex.enable() + else + synctex.disable() + end + end } interfaces.implement { diff --git a/tex/context/base/mkiv/status-files.pdf b/tex/context/base/mkiv/status-files.pdf Binary files differindex 933402892..72baf08cc 100644 --- a/tex/context/base/mkiv/status-files.pdf +++ b/tex/context/base/mkiv/status-files.pdf diff --git a/tex/context/base/mkiv/status-lua.pdf b/tex/context/base/mkiv/status-lua.pdf Binary files differindex 3334c4ae9..b33293a23 100644 --- a/tex/context/base/mkiv/status-lua.pdf +++ b/tex/context/base/mkiv/status-lua.pdf diff --git a/tex/context/base/mkiv/trac-inf.lua b/tex/context/base/mkiv/trac-inf.lua index d09fce77a..99fe30a6e 100644 --- a/tex/context/base/mkiv/trac-inf.lua +++ b/tex/context/base/mkiv/trac-inf.lua @@ -84,7 +84,7 @@ local seconds = function(n) return n or 0 end local function starttiming(instance) local timer = timers[instance or "notimer"] - local it = timer.timing or 0 + local it = timer.timing if it == 0 then timer.starttime = ticks() if not timer.loadtime then @@ -116,7 +116,7 @@ end local function elapsed(instance) if type(instance) == "number" then - return instance or 0 + return instance else local timer = timers[instance or "notimer"] return timer and seconds(timer.loadtime) or 0 diff --git a/tex/context/base/mkiv/util-fil.lua b/tex/context/base/mkiv/util-fil.lua index 01bcd571e..6100f36f6 100644 --- a/tex/context/base/mkiv/util-fil.lua +++ b/tex/context/base/mkiv/util-fil.lua @@ -35,7 +35,10 @@ function files.close(f) end function files.size(f) - return f:seek("end") + local current = f:seek() + local size = f:seek("end") + f:seek("set",current) + return size end files.getsize = files.size diff --git a/tex/context/interface/mkii/keys-de.xml b/tex/context/interface/mkii/keys-de.xml index 404f8da89..aaf0594b2 100644 --- a/tex/context/interface/mkii/keys-de.xml +++ b/tex/context/interface/mkii/keys-de.xml @@ -693,6 +693,7 @@ <cd:constant name='bottomoffset' value='untenoffset'/> <cd:constant name='bottomspace' value='bottomspace'/> <cd:constant name='bottomstate' value='untenstatus'/> + <cd:constant name='break' value='break'/> <cd:constant name='buffer' value='buffer'/> <cd:constant name='cache' value='cache'/> <cd:constant name='calculate' value='berechnen'/> diff --git a/tex/context/interface/mkii/keys-ro.xml b/tex/context/interface/mkii/keys-ro.xml index a4566c4b4..7f7fc14ad 100644 --- a/tex/context/interface/mkii/keys-ro.xml +++ b/tex/context/interface/mkii/keys-ro.xml @@ -693,6 +693,7 @@ <cd:constant name='bottomoffset' value='offsetjos'/> <cd:constant name='bottomspace' value='spatiujos'/> <cd:constant name='bottomstate' value='starejos'/> + <cd:constant name='break' value='break'/> <cd:constant name='buffer' value='buffer'/> <cd:constant name='cache' value='cache'/> <cd:constant name='calculate' value='calculeaza'/> diff --git a/tex/context/interface/mkiv/i-context.pdf b/tex/context/interface/mkiv/i-context.pdf Binary files differindex 365dc0f01..42aaf874c 100644 --- a/tex/context/interface/mkiv/i-context.pdf +++ b/tex/context/interface/mkiv/i-context.pdf diff --git a/tex/context/interface/mkiv/i-readme.pdf b/tex/context/interface/mkiv/i-readme.pdf Binary files differindex f656c5953..1ad38df61 100644 --- a/tex/context/interface/mkiv/i-readme.pdf +++ b/tex/context/interface/mkiv/i-readme.pdf diff --git a/tex/context/modules/common/s-abr-01.tex b/tex/context/modules/common/s-abr-01.tex index 9a6679066..632c902b1 100644 --- a/tex/context/modules/common/s-abr-01.tex +++ b/tex/context/modules/common/s-abr-01.tex @@ -246,6 +246,7 @@ \logo [SVG] {svg} \logo [STIX] {Stix} \logo [SUMATRAPDF] {SumatraPDF} +\logo [SYNCTEX] {Sync\TeX} \logo [SWIG] {swig} \logo [SWIGLIB] {SwigLib} \logo [TABLE] {\TaBlE} diff --git a/tex/generic/context/luatex/luatex-fonts-demo-vf-1.lua b/tex/generic/context/luatex/luatex-fonts-demo-vf-1.lua index 793526f7b..1fc1c79f7 100644 --- a/tex/generic/context/luatex/luatex-fonts-demo-vf-1.lua +++ b/tex/generic/context/luatex/luatex-fonts-demo-vf-1.lua @@ -8,6 +8,14 @@ if not modules then modules = { } end modules ['luatex-fonts-demo-vf-1'] = { local identifiers = fonts.hashes.identifiers +local defaults = { + { "pdf", "0 g" }, + { "pdf", "1 0 0 rg" }, + { "pdf", "0 1 0 rg" }, + { "pdf", "0 0 1 rg" }, + { "pdf", "0 0 1 rg" }, +} + return function(specification) local f1, id1 = fonts.constructors.readanddefine('lmroman10-regular', specification.size) local f2, id2 = fonts.constructors.readanddefine('lmsans10-regular', specification.size) @@ -20,12 +28,8 @@ return function(specification) { id = id2 }, { id = id3 }, } - local color = { [0] = - { "special", "pdf:0 g" }, - { "special", "pdf:1 0 0 rg" }, - { "special", "pdf:0 1 0 rg" }, - { "special", "pdf:0 0 1 rg" }, - { "special", "pdf:0 0 1 rg" }, + local color = { + [0] = defaults, } local chars = { identifiers[id1].characters, diff --git a/tex/generic/context/luatex/luatex-fonts-merged.lua b/tex/generic/context/luatex/luatex-fonts-merged.lua index ed9c29f78..51e10df43 100644 --- a/tex/generic/context/luatex/luatex-fonts-merged.lua +++ b/tex/generic/context/luatex/luatex-fonts-merged.lua @@ -1,6 +1,6 @@ -- merged file : c:/data/develop/context/sources/luatex-fonts-merged.lua -- parent file : c:/data/develop/context/sources/luatex-fonts.lua --- merge date : 06/30/17 19:45:43 +-- merge date : 07/05/17 23:01:18 do -- begin closure to overcome local limits and interference @@ -4306,7 +4306,10 @@ function files.close(f) f:close() end function files.size(f) - return f:seek("end") + local current=f:seek() + local size=f:seek("end") + f:seek("set",current) + return size end files.getsize=files.size function files.setposition(f,n) @@ -16422,12 +16425,12 @@ function readers.gdef(f,fontdata,specification) local tableoffset=datatable.offset setposition(f,tableoffset) local version=readulong(f) - local classoffset=tableoffset+readushort(f) - local attachmentoffset=tableoffset+readushort(f) - local ligaturecarets=tableoffset+readushort(f) - local markclassoffset=tableoffset+readushort(f) - local marksetsoffset=version>=0x00010002 and (tableoffset+readushort(f)) - local varsetsoffset=version>=0x00010003 and (tableoffset+readulong(f)) + local classoffset=readushort(f) + local attachmentoffset=readushort(f) + local ligaturecarets=readushort(f) + local markclassoffset=readushort(f) + local marksetsoffset=version>=0x00010002 and readushort(f) or 0 + local varsetsoffset=version>=0x00010003 and readulong(f) or 0 local glyphs=fontdata.glyphs local marks={} local markclasses=setmetatableindex("table") @@ -16435,54 +16438,59 @@ function readers.gdef(f,fontdata,specification) fontdata.marks=marks fontdata.markclasses=markclasses fontdata.marksets=marksets - setposition(f,classoffset) - local classformat=readushort(f) - if classformat==1 then - local firstindex=readushort(f) - local lastindex=firstindex+readushort(f)-1 - for index=firstindex,lastindex do - local class=classes[readushort(f)] - if class=="mark" then - marks[index]=true - end - glyphs[index].class=class - end - elseif classformat==2 then - local nofranges=readushort(f) - for i=1,nofranges do + if classoffset~=0 then + setposition(f,tableoffset+classoffset) + local classformat=readushort(f) + if classformat==1 then local firstindex=readushort(f) - local lastindex=readushort(f) - local class=classes[readushort(f)] - if class then - for index=firstindex,lastindex do - glyphs[index].class=class - if class=="mark" then - marks[index]=true + local lastindex=firstindex+readushort(f)-1 + for index=firstindex,lastindex do + local class=classes[readushort(f)] + if class=="mark" then + marks[index]=true + end + glyphs[index].class=class + end + elseif classformat==2 then + local nofranges=readushort(f) + for i=1,nofranges do + local firstindex=readushort(f) + local lastindex=readushort(f) + local class=classes[readushort(f)] + if class then + for index=firstindex,lastindex do + glyphs[index].class=class + if class=="mark" then + marks[index]=true + end end end end end end - setposition(f,markclassoffset) - local classformat=readushort(f) - if classformat==1 then - local firstindex=readushort(f) - local lastindex=firstindex+readushort(f)-1 - for index=firstindex,lastindex do - markclasses[readushort(f)][index]=true - end - elseif classformat==2 then - local nofranges=readushort(f) - for i=1,nofranges do + if markclassoffset~=0 then + setposition(f,tableoffset+markclassoffset) + local classformat=readushort(f) + if classformat==1 then local firstindex=readushort(f) - local lastindex=readushort(f) - local class=markclasses[readushort(f)] + local lastindex=firstindex+readushort(f)-1 for index=firstindex,lastindex do - class[index]=true + markclasses[readushort(f)][index]=true + end + elseif classformat==2 then + local nofranges=readushort(f) + for i=1,nofranges do + local firstindex=readushort(f) + local lastindex=readushort(f) + local class=markclasses[readushort(f)] + for index=firstindex,lastindex do + class[index]=true + end end end end - if marksetsoffset and marksetsoffset>tableoffset then + if marksetsoffset~=0 then + marksetsoffset=tableoffset+marksetsoffset setposition(f,marksetsoffset) local format=readushort(f) if format==1 then @@ -16500,8 +16508,8 @@ function readers.gdef(f,fontdata,specification) end end local factors=specification.factors - if (specification.variable or factors) and varsetsoffset and varsetsoffset>tableoffset then - local regions,deltas=readvariationdata(f,varsetsoffset,factors) + if (specification.variable or factors) and varsetsoffset~=0 then + local regions,deltas=readvariationdata(f,tableoffset+varsetsoffset,factors) if factors then fontdata.temporary.getdelta=function(outer,inner) local delta=deltas[outer+1] @@ -19484,7 +19492,7 @@ local trace_defining=false registertracker("fonts.defining",function(v) trace_de local report_otf=logs.reporter("fonts","otf loading") local fonts=fonts local otf=fonts.handlers.otf -otf.version=3.030 +otf.version=3.031 otf.cache=containers.define("fonts","otl",otf.version,true) otf.svgcache=containers.define("fonts","svg",otf.version,true) otf.sbixcache=containers.define("fonts","sbix",otf.version,true) @@ -22304,7 +22312,11 @@ local trace_kernruns=false registertracker("otf.kernruns",function(v) trace_kern local trace_discruns=false registertracker("otf.discruns",function(v) trace_discruns=v end) local trace_compruns=false registertracker("otf.compruns",function(v) trace_compruns=v end) local trace_testruns=false registertracker("otf.testruns",function(v) trace_testruns=v end) +local forcediscretionaries=false local optimizekerns=true +directives.register("otf.forcediscretionaries",function(v) + forcediscretionaries=v +end) local report_direct=logs.reporter("fonts","otf direct") local report_subchain=logs.reporter("fonts","otf subchain") local report_chain=logs.reporter("fonts","otf chain") @@ -22369,6 +22381,7 @@ local disc_code=nodecodes.disc local math_code=nodecodes.math local dir_code=nodecodes.dir local localpar_code=nodecodes.localpar +local discretionary_code=disccodes.discretionary local ligature_code=glyphcodes.ligature local a_state=attributes.private('state') local a_noligature=attributes.private("noligature") @@ -22645,7 +22658,11 @@ local function toligature(head,start,stop,char,dataset,sequence,markflag,discfou setboth(base) set_components(base,copied) replace=base - setdisc(discfound,pre,post,replace) + if forcediscretionaries then + setdisc(discfound,pre,post,replace,discretionary_code) + else + setdisc(discfound,pre,post,replace) + end base=prev end end @@ -27706,8 +27723,8 @@ local setmetatableindex=table.setmetatableindex local formatters=string.formatters local tounicode=fonts.mappings.tounicode local otf=fonts.handlers.otf -local f_color=formatters["pdf:direct:%f %f %f rg"] -local f_gray=formatters["pdf:direct:%f g"] +local f_color=formatters["%f %f %f rg"] +local f_gray=formatters["%f g"] if context then local startactualtext=nil local stopactualtext=nil @@ -27728,7 +27745,7 @@ else end local sharedpalettes={} local hash=setmetatableindex(function(t,k) - local v={ "special",k } + local v={ "pdf","direct",k } t[k]=v return v end) @@ -27752,11 +27769,11 @@ if context then t=transparencies[v] end if c and t then - values[i]=hash["pdf:direct:"..lpdf.color(1,c).." "..lpdf.transparency(t)] + values[i]=hash[lpdf.color(1,c).." "..lpdf.transparency(t)] elseif c then - values[i]=hash["pdf:direct:"..lpdf.color(1,c)] + values[i]=hash[lpdf.color(1,c)] elseif t then - values[i]=hash["pdf:direct:"..lpdf.color(1,t)] + values[i]=hash[lpdf.color(1,t)] end end end @@ -27787,6 +27804,8 @@ local function convert(t,k) t[k]=v return v end +local start={ "pdf","page","q" } +local stop={ "pdf","raw","Q" } local function initializecolr(tfmdata,kind,value) if value then local resources=tfmdata.resources @@ -27817,12 +27836,10 @@ local function initializecolr(tfmdata,kind,value) local getactualtext=otf.getactualtext local default=colorvalues[#colorvalues] local b,e=getactualtext(tounicode(0xFFFD)) - local start={ "special","pdf:page:q" } - local stop={ "special","pdf:raw:Q" } - local actualb={ "special","pdf:page:"..b } - local actuale={ "special","pdf:page:"..e } + local actualb={ "pdf","page",b } + local actuale={ "pdf","page",e } local cache=setmetatableindex(function(t,k) - local v={ "char",k } + local v={ "char",k } t[k]=v return v end) @@ -27837,7 +27854,7 @@ local function initializecolr(tfmdata,kind,value) local goback=w~=0 and widths[w] or nil local t={ start, - not u and actualb or { "special","pdf:raw:"..getactualtext(tounicode(u)) } + not u and actualb or { "pdf","raw",getactualtext(tounicode(u)) } } local n=2 local l=nil @@ -27927,11 +27944,11 @@ local function pdftovirtual(tfmdata,pdfshapes,kind) local ht=character.height or 0 local dp=character.depth or 0 character.commands={ - { "special","pdf:direct:"..bt }, + { "pdf","direct",bt }, { "down",dp+dy*hfactor }, { "right",dx*hfactor }, { "image",{ filename=name,width=wd,height=ht,depth=dp } }, - { "special","pdf:direct:"..et }, + { "pdf","direct",et }, } character[kind]=true end |