Skip to content

Instantly share code, notes, and snippets.

@phi-gamma
Last active December 22, 2015 14:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save phi-gamma/6488187 to your computer and use it in GitHub Desktop.
Save phi-gamma/6488187 to your computer and use it in GitHub Desktop.
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