import the bidi code from Context (http://tex.stackexchange.com/q/132241); DON’T DO THIS AT HOME, use Context instead!
| ----------------------------------------------------------------------- | |
| -- FILE: import-typo-dir.lua | |
| -- DESCRIPTION: fake enough of Context to load typo-dir.lua | |
| -- REQUIREMENTS: Context MkIV, Luoatfload, Lualibs etc. | |
| -- AUTHOR: Philipp Gesang (Phg), <phg42.2a@gmail.com> | |
| -- VERSION: 0.0 | |
| -- CREATED: 2013-09-08 19:58:40+0200 | |
| ----------------------------------------------------------------------- | |
| -- | |
| local err, warn, info = luatexbase.provides_module { | |
| name = "import-typo-dir", | |
| author = "Philipp Gesang", | |
| description = "fake Context layer for loading typo-dir.lua", | |
| } | |
| info "This is not an excuse for not using Context!" | |
| require "lualibs" -- we need the extended set | |
| local texsprint = tex.sprint | |
| local stringformat = string.format | |
| local tableconcat = table.concat | |
| local copynode = node.copy | |
| ----------------------------------------------------------------------- | |
| --- prepare | |
| ----------------------------------------------------------------------- | |
| --- 1) wrap Luatexbase attribute handler in a Context style interface | |
| attributes = attributes or { } | |
| local texsetattribute = tex.setattribute | |
| local hidden = { | |
| state = luatexbase.new_attribute ("typo-dir:state", true), | |
| directions = luatexbase.new_attribute ("typo-dir:directions", true), | |
| mathbidi = luatexbase.new_attribute ("typo-dir:mathbidi", true), | |
| } | |
| local a_directions = hidden.directions | |
| attributes.private = attributes.private or function (attr_name) | |
| local res = hidden [attr_name] | |
| if not res then | |
| res = luatexbase.new_attribute (attr_name) | |
| end | |
| return res | |
| end | |
| local unsetvalue = luatexbase.get_unset_value () | |
| attributes.unsetvalue = unsetvalue | |
| --- 2) simulate the multilingual interface; safe to purge afterwards | |
| --- since Context uses local copies | |
| interfaces = interfaces or { } | |
| interfaces.variables = interfaces.variables or { } | |
| interfaces.variables.global = "global" | |
| interfaces.variables["local"] = "local" | |
| interfaces.variables.default = "default" | |
| interfaces.variables.on = "on" | |
| interfaces.variables.yes = "yes" | |
| --- 3) node tasks; we don’t have real node processors so we will need | |
| --- to set up a makeshift interface | |
| nodes.tasks = nodes.tasks or { } | |
| nodes.tasks.enableaction = function () end | |
| --- 4) commands namespace | |
| commands = commands or { } -- already present due to luaotfload-extrablibs | |
| --- 5) typesetters namespace | |
| --- | |
| --- With a current (as of 2013-09-08) Luaotfload this namespace | |
| --- already exists since we load typo-krn as part of the ongoing | |
| --- experiment with proper letterspacing support. At the moment | |
| --- it looks like Latex/Microtype prefer a simplified approach | |
| --- so the Luaotfload copy of typo-krn is likely to vanish in a | |
| --- future release. | |
| typesetters = typesetters or { } | |
| --- 6) the Context namespace; cannot be cleaned up without breaking | |
| --- things; srsly there needs to be a non-Context equivalent for | |
| --- this | |
| context = context or { } | |
| setmetatable (context, { | |
| --- this is quite primitive and considerably less functional than | |
| --- the real deal as defined in cldf-ini.lua, but we already get | |
| --- quite far with this reduced version | |
| __index = function (t, k) | |
| if k == "sprint" then | |
| return function (...) texsprint (...) end | |
| elseif type (k) == "string" then | |
| local command = [[\]] .. k | |
| return function (...) | |
| local res = { command } | |
| for i = 1, select ("#", ...) do | |
| --- just simple grouped arguments | |
| res [#res + 1] = "{" | |
| res [#res + 1] = select (i, ...) | |
| res [#res + 1] = "}" | |
| end | |
| texsprint (tableconcat (res)) | |
| end | |
| else | |
| return context | |
| end | |
| end, | |
| __call = function (t, fmt, first, ...) | |
| if t == nil or fmt == nil then | |
| return | |
| end | |
| local tf = type (fmt) | |
| if tf == "string" then | |
| if first then | |
| texsprint (-1, stringformat (fmt, first, ...)) | |
| else | |
| texsprint (-1, fmt) | |
| end | |
| elseif tf == "function" then | |
| texsprint (-1, fmt (first, ...)) | |
| elseif first then --- and so on, | |
| texsprint (-1, tostring (fmt), first, ...) | |
| else | |
| texsprint (-1, tostring (fmt)) | |
| end | |
| end, | |
| }) | |
| --- 7) catcodes namespace | |
| catcodes = catcodes or { } | |
| catcodes.numbers = catcodes.numbers or { } | |
| catcodes.numbers.ctxcatcodes = -1 | |
| --- 8) whatsit prototype; expected to be present in the nodepool | |
| local n_textdir = node.new (node.id "whatsit", nodes.whatsitcodes.dir) | |
| nodes.pool = nodes.pool or { } | |
| nodes.pool.textdir = function (dir) | |
| local n = copynode (n_textdir) | |
| n.dir = dir | |
| return n | |
| end | |
| --- 9) node identifiers | |
| nodes.nodecodes = table.mirrored (nodes.nodecodes) --> convenience | |
| ---------------------------------------------------------------------- | |
| --- import | |
| ----------------------------------------------------------------------- | |
| require "char-def" --> characters.data (unicode) | |
| require "char-ini" --> characters.* | |
| --- the next three used to share “typo-dir.lua” before it was split | |
| require "typo-dir" --> typesetters.directions | |
| require "typo-dha" --> typesetters.directions | |
| require "math-dir" --> typesetters.directions | |
| ----------------------------------------------------------------------- | |
| --- wrappers | |
| ----------------------------------------------------------------------- | |
| --- we use the *packagedata* namespace which should become canonical | |
| --- anyways; also we keep a copy of typesetters.directions in a | |
| --- subtable | |
| packagedata = packagedata or { } | |
| local directions = typesetters.directions | |
| local typo_dir = { directions = directions } | |
| packagedata.typo_dir = typo_dir | |
| local directionprocessor = directions.process | |
| local mathdirectionprocessor = directions.processmath | |
| local processorid = "typesetters.directions" | |
| --- emulate node tasks capability; we override the original definitions | |
| --- of set() and setmath() with surrogates that work with Luatexbase | |
| --- callback handlers | |
| directions.set = nil | |
| directions.setmath = nil | |
| --- we need to track which callbacks the node processor is hooked | |
| --- into since we lack the combined version Context has | |
| local registered_as = { } --- procname -> callbacks | |
| --- (node_t -> node_t) -> string -> string list -> bool | |
| local add_processor = function (processor, name, ...) | |
| for i=1, select ("#", ...) do | |
| local callback = select (i, ...) | |
| --- *IMPORTANT* the processor must be inserted at the top, | |
| --- i.e. with a priority higher than any other callback! | |
| luatexbase.add_to_callback (callback, processor, name, 1) | |
| end | |
| registered_as [name] = { ... } | |
| return true | |
| end | |
| --- string -> bool | |
| local remove_processor = function (name) | |
| local callbacks = registered_as [name] | |
| if callbacks then | |
| for i=1, #callbacks do | |
| luatexbase.remove_from_callback (callbacks [i], name) | |
| end | |
| return true | |
| end | |
| return false | |
| end | |
| --- we use the same callbacks as a node processor in Context | |
| --- unit -> bool | |
| local enabledirectionprocessor = function (math) | |
| local processor | |
| if math == true then | |
| processor = function (hd) | |
| --- different signature from the normal one | |
| return mathdirectionprocessor (hd) | |
| end | |
| else | |
| processor = function (hd) | |
| return directionprocessor ("directions", a_directions, hd) | |
| end | |
| end | |
| return add_processor (processor, | |
| processorid, | |
| "pre_linebreak_filter", | |
| "hpack_filter") | |
| end | |
| typo_dir.enable = enabledirectionprocessor | |
| --- unit -> bool | |
| local disabledirectionprocessor = function ( ) | |
| return remove_processor (processorid) | |
| end | |
| typo_dir.disable = disabledirectionprocessor | |
| local active = false --- activation state of direction processor | |
| typo_dir.set = function (n) | |
| if not n or n == 0 then | |
| n = unsetvalue | |
| end | |
| if not active then | |
| info ("Installing Context direction handler (%d).", n) | |
| enabledirectionprocessor () | |
| active = true | |
| end | |
| texsetattribute (a_directions, n) | |
| end | |
| local active = false --- activation state of math direction processor | |
| typo_dir.setmath = function (n) | |
| if not active and n and n > 0 then | |
| info ("Installing Context math direction handler (%d).", n) | |
| enabledirectionprocessor (true) | |
| active = true | |
| end | |
| end | |
| typo_dir.getbidimode = directions.getbidimode | |
| typo_dir.getbidimode = function (specification) | |
| context (directions.tomode (specification)) | |
| end | |
| ----------------------------------------------------------------------- | |
| --- clean | |
| ----------------------------------------------------------------------- | |
| attributes.private = nil | |
| attributes = nil | |
| interfaces.variables = nil | |
| interfaces = nil | |
| nodes.tasks = nil | |
| collectgarbage "collect" | |
| \documentclass {article} | |
| \usepackage {luaotfload} | |
| \RequireLuaModule {import-typo-dir} | |
| %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
| %% makeshift interface | |
| %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
| \def \typodircommand #1{\directlua {packagedata.typo_dir.#1}} | |
| %% this expects an attribute id | |
| \def \setdirection [#1]{\typodircommand {set (#1)}} | |
| \def \typodirsetmode [#1][#2][#3]{% scope, method, fences | |
| \def \currenttypodirbidimode {\typodircommand {getbidimode { | |
| scope = [[#1]], | |
| method = [[#2]], | |
| fences = [[#3]], | |
| }}}% | |
| \setdirection [\number \currenttypodirbidimode]% | |
| } | |
| \let \unexpanded \protect | |
| \let \normalUchar \luatexUchar | |
| %% below definitions are taken unmodified from typo-dir.mkiv | |
| \unexpanded \edef \bidilre {\normalUchar"202A} | |
| \unexpanded \edef \bidirle {\normalUchar"202B} | |
| \unexpanded \edef \bidipop {\normalUchar"202C} | |
| \unexpanded \edef \bidilro {\normalUchar"202D} | |
| \unexpanded \edef \bidirlo {\normalUchar"202E} | |
| %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
| %% latexifying the demo section of typo-dir.mkiv | |
| %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
| \font \mainfont = "file:lmroman10-regular.otf:mode=node;+tlig;+liga;+dlig" at 12 pt | |
| \font \Arabic = "file:amiri-regular.ttf:mode=node;language=dflt;script=arab;+init;+medi;+fina;+isol;+liga;+dlig;+rlig;+clig;+mark;+mkmk;+kern;+curs" at 20pt | |
| \mainfont | |
| \def \LATIN {LATIN} | |
| \def\ARAB {محمد} | |
| \def \biditest #1#2#3{% | |
| \leavevmode \hbox {\hbox {\tt #2}\quad | |
| \hbox {#1#3}\quad} | |
| \hbox {\tt \detokenize {#3}}} | |
| \let \textdir = \luatextextdir | |
| \def \runbiditests { | |
| \biditest \Arabic {LATIN BARA} {\textdir TLT \relax \LATIN\ \ARAB}\par | |
| \biditest \Arabic {BARA LATIN} {\textdir TRT \relax \LATIN\ \ARAB}\par | |
| \biditest \Arabic {LATIN ARAB} {\textdir TLT \bidilro \LATIN\ \ARAB}\par % right -> left | |
| \biditest \Arabic {LATIN ARAB} {\textdir TRT \bidilro \LATIN\ \ARAB}\par % right -> left | |
| \biditest \Arabic {BARA NITAL} {\textdir TLT \bidirlo \LATIN\ \ARAB}\par % left -> right | |
| \biditest \Arabic {BARA NITAL} {\textdir TRT \bidirlo \LATIN\ \ARAB}\par % left -> right | |
| } | |
| %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
| %% run the demo with the same parameters | |
| %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
| \begin{document} | |
| \typodirsetmode [off][default][yes] | |
| \runbiditests | |
| \vskip2\baselineskip | |
| \typodirsetmode [global][default][yes] | |
| \runbiditests | |
| \vskip2\baselineskip | |
| \typodirsetmode [local][default][yes] | |
| \runbiditests | |
| \end{document} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment