summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--luaotfload-auxiliary.lua6
-rw-r--r--luaotfload-database.lua266
-rw-r--r--luaotfload-override.lua11
-rwxr-xr-xluaotfload-tool.lua87
-rw-r--r--luaotfload-tool.rst20
-rw-r--r--luaotfload.dtx40
6 files changed, 335 insertions, 95 deletions
diff --git a/luaotfload-auxiliary.lua b/luaotfload-auxiliary.lua
index be380e3..999bc22 100644
--- a/luaotfload-auxiliary.lua
+++ b/luaotfload-auxiliary.lua
@@ -64,10 +64,8 @@ local add_fontdata_fallbacks = function (fontdata)
fontdata.units = fontdata.units_per_em
else --- otf
- metadata = fontdata.shared.rawdata.metadata
- fontdata.name = fontdata.name
- or fontdata.fullname
- or fontdata.psname
+ metadata = fontdata.shared.rawdata.metadata
+ fontdata.name = metadata.origname or fontdata.name
fontdata.units = fontdata.units_per_em
fontdata.size = fontdata.size or fontparameters.size
local resources = fontdata.resources
diff --git a/luaotfload-database.lua b/luaotfload-database.lua
index 224fa61..60a7977 100644
--- a/luaotfload-database.lua
+++ b/luaotfload-database.lua
@@ -239,7 +239,7 @@ end
local crude_file_lookup
local crude_file_lookup_verbose
local find_closest
-local flush_cache
+local flush_lookup_cache
local font_fullinfo
local load_names
local load_lookups
@@ -259,8 +259,8 @@ local fonts_reloaded = false
--- limit output when approximate font matching (luaotfload-tool -F)
local fuzzy_limit = 1 --- display closest only
---- unit -> dbobj
-load_names = function ( )
+--- bool? -> dbobj
+load_names = function (dry_run)
local starttime = os.gettimeofday()
local foundname, data = load_lua_file(names.path.path)
@@ -273,8 +273,11 @@ load_names = function ( )
report("both", 0, "db",
[[Font names database not found, generating new one.
This can take several minutes; please be patient.]])
- data = update_names(fontnames_init(false))
- save_names(data)
+ data = update_names(fontnames_init(false), nil, dry_run)
+ local success = save_names(data)
+ if not success then
+ report("both", 0, "db", "Database creation unsuccessful.")
+ end
end
fonts_loaded = true
return data
@@ -443,7 +446,10 @@ resolve_cached = function (_, _, specification)
--- TODO this should trigger a save only once the
--- document is compiled (finish_pdffile callback?)
report("both", 5, "cache", "saving updated cache")
- save_lookups()
+ local success = save_lookups()
+ if not success then --- sad, but not critical
+ report("both", 0, "cache", "could not write to cache")
+ end
return filename, subfont, true
end
@@ -675,9 +681,12 @@ end --- resolve()
reload_db = function (why, caller, ...)
report("both", 1, "db", "reload initiated; reason: “%s”", why)
names.data = update_names()
- save_names()
- fonts_reloaded = true
- return caller(...)
+ local success = save_names()
+ if success then
+ fonts_reloaded = true
+ return caller(...)
+ end
+ report("both", 0, "db", "Database update unsuccessful.")
end
--- string -> string -> int
@@ -859,7 +868,9 @@ end
--- we return true if the fond is new or re-indexed
--- string -> dbobj -> dbobj -> bool
local load_font = function (fullname, fontnames, newfontnames)
- if not fullname then return false end
+ if not fullname then
+ return false
+ end
local newmappings = newfontnames.mappings
local newstatus = newfontnames.status
@@ -1061,15 +1072,20 @@ for key, value in next, font_extensions do
font_extensions_set[value] = true
end
---- string -> dbobj -> dbobj -> bool -> (int * int)
-local scan_dir = function (dirname, fontnames, newfontnames)
- --[[
- This function scans a directory and populates the list of fonts
+--[[doc--
+
+ scan_dir() scans a directory and populates the list of fonts
with all the fonts it finds.
- - dirname is the name of the directory to scan
- - names is the font database to fill -> no such term!!!
- - texmf used to be a boolean saying if we are scanning a texmf directory
- ]]
+
+ · dirname : name of the directory to scan
+ · fontnames : current font db object
+ · newnames : font db object to fill
+ · dry_run : don’t touch anything
+
+--doc]]--
+
+--- string -> dbobj -> dbobj -> bool -> (int * int)
+local scan_dir = function (dirname, fontnames, newfontnames, dry_run)
local n_scanned, n_new = 0, 0 --- total of fonts collected
report("both", 2, "db", "scanning directory %s", dirname)
for _,i in next, font_extensions do
@@ -1083,9 +1099,16 @@ local scan_dir = function (dirname, fontnames, newfontnames)
for j=1, n_found do
local fullname = found[j]
fullname = path_normalize(fullname)
- report("both", 4, "db", "loading font “%s”", fullname)
- local new = load_font(fullname, fontnames, newfontnames)
- if new then n_new = n_new + 1 end
+ local new
+ if dry_run == true then
+ report("both", 1, "db", "would have been loading “%s”", fullname)
+ else
+ report("both", 4, "db", "loading font “%s”", fullname)
+ local new = load_font(fullname, fontnames, newfontnames)
+ if new == true then
+ n_new = n_new + 1
+ end
+ end
end
end
end
@@ -1093,7 +1116,8 @@ local scan_dir = function (dirname, fontnames, newfontnames)
return n_scanned, n_new
end
-local function scan_texmf_fonts(fontnames, newfontnames)
+--- dbobj -> dbobj -> bool? -> (int * int)
+local scan_texmf_fonts = function (fontnames, newfontnames, dry_run)
local n_scanned, n_new = 0, 0
--[[
This function scans all fonts in the texmf tree, through kpathsea
@@ -1109,7 +1133,7 @@ local function scan_texmf_fonts(fontnames, newfontnames)
if not stringis_empty(fontdirs) then
for _,d in next, filesplitpath(fontdirs) do
report("info", 4, "db", "Entering directory %s", d)
- local found, new = scan_dir(d, fontnames, newfontnames)
+ local found, new = scan_dir(d, fontnames, newfontnames, dry_run)
n_scanned = n_scanned + found
n_new = n_new + new
end
@@ -1343,6 +1367,7 @@ do --- closure for read_fonts_conf()
end --- read_fonts_conf closure
--- TODO stuff those paths into some writable table
+--- unit -> string list
local function get_os_dirs()
if os.name == 'macosx' then
return {
@@ -1365,7 +1390,8 @@ local function get_os_dirs()
return {}
end
-local function scan_os_fonts(fontnames, newfontnames)
+--- dbobj -> dbobj -> bool? -> (int * int)
+local scan_os_fonts = function (fontnames, newfontnames, dry_run)
local n_scanned, n_new = 0, 0
--[[
This function scans the OS fonts through
@@ -1375,23 +1401,27 @@ local function scan_os_fonts(fontnames, newfontnames)
]]
report("info", 2, "db", "Scanning OS fonts...")
report("info", 3, "db", "Searching in static system directories...")
- for _,d in next, get_os_dirs() do
- local found, new = scan_dir(d, fontnames, newfontnames)
+ for _, d in next, get_os_dirs() do
+ local found, new = scan_dir(d, fontnames, newfontnames, dry_run)
n_scanned = n_scanned + found
n_new = n_new + new
end
return n_scanned, n_new
end
-flush_cache = function ()
+--- unit -> (bool, lookup_cache)
+flush_lookup_cache = function ()
if not names.lookups then names.lookups = load_lookups() end
names.lookups = { }
collectgarbage"collect"
return true, names.lookups
end
---- dbobj -> bool -> dbobj
-update_names = function (fontnames, force)
+--- force: dictate rebuild from scratch
+--- dry_dun: don’t write to the db, just scan dirs
+
+--- dbobj? -> bool? -> bool? -> dbobj
+update_names = function (fontnames, force, dry_run)
if config.luaotfload.update_live == false then
report("info", 2, "db",
"skipping database update")
@@ -1412,7 +1442,7 @@ update_names = function (fontnames, force)
fontnames = fontnames_init(false)
else
if not fontnames then
- fontnames = load_names()
+ fontnames = load_names(dry_run)
end
if fontnames.version ~= names.version then
report("both", 1, "db", "No font names database or old "
@@ -1424,11 +1454,11 @@ update_names = function (fontnames, force)
read_blacklist()
local scanned, new
- scanned, new = scan_texmf_fonts(fontnames, newfontnames)
+ scanned, new = scan_texmf_fonts(fontnames, newfontnames, dry_run)
n_scanned = n_scanned + scanned
n_new = n_new + new
- scanned, new = scan_os_fonts(fontnames, newfontnames)
+ scanned, new = scan_os_fonts(fontnames, newfontnames, dry_run)
n_scanned = n_scanned + scanned
n_new = n_new + new
@@ -1457,7 +1487,7 @@ end
--- file. As we update it after every single addition this saves us
--- quite some time.
---- unit -> string
+--- unit -> bool
save_lookups = function ( )
---- this is boilerplate and should be refactored into something
---- usable by both the db and the cache writers
@@ -1471,19 +1501,19 @@ save_lookups = function ( )
os.remove(lucname)
caches.compile(lookups, luaname, lucname)
report("both", 3, "cache", "Lookup cache saved")
- return names.path.lookup_path
+ return true
end
end
end
report("info", 0, "cache", "Could not write lookup cache")
- return nil
+ return false
end
--- save_names() is usually called without the argument
---- dbobj -> unit
+--- dbobj? -> bool
save_names = function (fontnames)
if not fontnames then fontnames = names.data end
- local path = ensure_names_path()
+ local path = ensure_names_path()
if fileiswritable(path) then
local luaname, lucname = make_name(names.path.path)
if luaname then
@@ -1492,38 +1522,170 @@ save_names = function (fontnames)
if lucname and type(caches.compile) == "function" then
os.remove(lucname)
caches.compile(fontnames, luaname, lucname)
- report("info", 0, "db", "Font names database saved")
- return names.path.path
+ report("info", 1, "db", "Font names database saved")
+ return true
end
end
end
report("both", 0, "db", "Failed to save names database")
- return nil
+ return false
end
-scan_external_dir = function (dir)
- local old_names, new_names
- if fonts_loaded then
- old_names = names.data
- else
- old_names = load_names()
+--[[doc--
+
+ Below set of functions is modeled after mtx-cache.
+
+--doc]]--
+
+--- string -> string -> string list -> string list -> string list -> unit
+local print_cache = function (category, path, luanames, lucnames, rest)
+ local report_indeed = function (...)
+ report("info", 0, "cache", ...)
end
- new_names = tablecopy(old_names)
- local n_scanned, n_new = scan_dir(dir, old_names, new_names)
- names.data = new_names
- return n_scanned, n_new
+ report_indeed("Luaotfload cache: %s", category)
+ report_indeed("location: %s", path)
+ report_indeed("[raw] %4i", #luanames)
+ report_indeed("[compiled] %4i", #lucnames)
+ report_indeed("[other] %4i", #rest)
+ report_indeed("[total] %4i", #luanames + #lucnames + #rest)
+end
+
+--- string -> string -> string list -> bool -> bool
+local purge_from_cache = function (category, path, list, all)
+ report("info", 2, "cache", "Luaotfload cache: %s %s",
+ (all and "erase" or "purge"), category)
+ report("info", 2, "cache", "location: %s",path)
+ local n = 0
+ for i=1,#list do
+ local filename = list[i]
+ if string.find(filename,"luatex%-cache") then -- safeguard
+ if all then
+ report("info", 5, "cache", "removing %s", filename)
+ os.remove(filename)
+ n = n + 1
+ else
+ local suffix = file.suffix(filename)
+ if suffix == "lua" then
+ local checkname = file.replacesuffix(
+ filename, "lua", "luc")
+ if lfs.isfile(checkname) then
+ report("info", 5, "cache", "removing %s", filename)
+ os.remove(filename)
+ n = n + 1
+ end
+ end
+ end
+ end
+ end
+ report("info", 2, "cache", "removed lua files : %i", n)
+ return true
+end
+--- string -> string list -> int -> string list -> string list -> string list ->
+--- (string list * string list * string list * string list)
+local collect_cache collect_cache = function (path, all, n, luanames,
+ lucnames, rest)
+ if not all then
+ local all = dirglob(path .. "/**/*")
+ local luanames, lucnames, rest = { }, { }, { }
+ return collect_cache(nil, all, 1, luanames, lucnames, rest)
+ end
+
+ local filename = all[n]
+ if filename then
+ local suffix = file.suffix(filename)
+ if suffix == "lua" then
+ luanames[#luanames+1] = filename
+ elseif suffix == "luc" then
+ lucnames[#lucnames+1] = filename
+ else
+ rest[#rest+1] = filename
+ end
+ return collect_cache(nil, all, n+1, luanames, lucnames, rest)
+ end
+ return luanames, lucnames, rest, all
end
+--- unit -> unit
+local purge_cache = function ( )
+ local writable_path = caches.getwritablepath()
+ local luanames, lucnames, rest = collect_cache(writable_path)
+ if logs.get_loglevel() > 1 then
+ print_cache("writable path", writable_path, luanames, lucnames, rest)
+ end
+ local success = purge_from_cache("writable path", writable_path, luanames, false)
+ return success
+end
+
+--- unit -> unit
+local erase_cache = function ( )
+ local writable_path = caches.getwritablepath()
+ local luanames, lucnames, rest, all = collect_cache(writable_path)
+ if logs.get_loglevel() > 1 then
+ print_cache("writable path", writable_path, luanames, lucnames, rest)
+ end
+ local success = purge_from_cache("writable path", writable_path, all, true)
+ return success
+end
+
+local separator = function ( )
+ report("info", 0, string.rep("-", 67))
+end
+
+--- unit -> unit
+local show_cache = function ( )
+ local readable_paths = caches.getreadablepaths()
+ local writable_path = caches.getwritablepath()
+ local luanames, lucnames, rest = collect_cache(writable_path)
+
+ separator()
+ print_cache("writable path", writable_path, luanames, lucnames, rest)
+ texiowrite_nl""
+ for i=1,#readable_paths do
+ local readable_path = readable_paths[i]
+ if readable_path ~= writable_path then
+ local luanames, lucnames = collect_cache(readable_path)
+ print_cache("readable path",
+ readable_path,luanames,lucnames,rest)
+ end
+ end
+ separator()
+ return true
+end
+
+--- is this used anywhere? we decided to comment it for the
+--- time being.
+--- https://github.com/lualatex/luaotfload/pull/61
+--scan_external_dir = function (dir)
+-- local old_names, new_names
+-- if fonts_loaded then
+-- old_names = names.data
+-- else
+-- old_names = load_names()
+-- end
+-- new_names = tablecopy(old_names)
+-- local n_scanned, n_new = scan_dir(dir, old_names, new_names)
+-- names.data = new_names
+-- return n_scanned, n_new
+--end
+
+-----------------------------------------------------------------------
--- export functionality to the namespace “fonts.names”
-names.flush_cache = flush_cache
+-----------------------------------------------------------------------
+
+names.flush_lookup_cache = flush_lookup_cache
names.save_lookups = save_lookups
names.load = load_names
names.save = save_names
-names.scan = scan_external_dir
+-----.scan = scan_external_dir
names.update = update_names
names.crude_file_lookup = crude_file_lookup
names.crude_file_lookup_verbose = crude_file_lookup_verbose
+--- font cache
+names.purge_cache = purge_cache
+names.erase_cache = erase_cache
+names.show_cache = show_cache
+
--- replace the resolver from luatex-fonts
if config.luaotfload.resolver == "cached" then
report("both", 2, "cache", "caching of name: lookups active")
diff --git a/luaotfload-override.lua b/luaotfload-override.lua
index f143009..99a6611 100644
--- a/luaotfload-override.lua
+++ b/luaotfload-override.lua
@@ -30,14 +30,25 @@ We recreate the verbosity levels previously implemented in font-nms:
local loglevel = 1 --- default
local logout = "log"
+--- int -> bool
local set_loglevel = function (n)
if type(n) == "number" then
loglevel = n
end
+ return true
end
+logs.setloglevel = set_loglevel
logs.set_loglevel = set_loglevel
logs.set_log_level = set_loglevel --- accomodating lazy typists
+--- unit -> int
+local get_loglevel = function ( )
+ return loglevel
+end
+logs.getloglevel = get_loglevel
+logs.get_loglevel = get_loglevel
+logs.get_log_level = get_loglevel
+
local set_logout = function (s)
if s == "stdout" then
logout = "term"
diff --git a/luaotfload-tool.lua b/luaotfload-tool.lua
index b16fe49..0ee53eb 100755
--- a/luaotfload-tool.lua
+++ b/luaotfload-tool.lua
@@ -169,7 +169,8 @@ This tool is part of the luaotfload package. Valid options are:
-u --update update the database
-f --force force re-indexing all fonts
- -c --flush-cache empty cache of font requests
+ -l --flush-lookups empty lookup cache of font requests
+ -D --dry-run skip loading of fonts, just scan
--find="font name" query the database for a font name
-F --fuzzy look for approximate matches if --find fails
@@ -185,6 +186,12 @@ The font database will be saved to
%s
%s
+-------------------------------------------------------------------------------
+ FONT CACHE
+
+ --cache=<directive> operate on font cache, where <directive> is
+ “show”, “purge”, or “erase”
+
]],
mkluatexfontdb = [[
@@ -260,7 +267,8 @@ set.
--]]--
local action_sequence = {
- "loglevel", "help", "version", "flush", "generate", "list", "query"
+ "loglevel", "help", "version", "cache",
+ "flush", "generate", "list", "query",
}
local action_pending = table.tohash(action_sequence, false)
@@ -273,6 +281,7 @@ actions.loglevel = function (job)
logs.set_loglevel(job.log_level)
logs.names_report("info", 3, "util",
"setting log level", "%d", job.log_level)
+ logs.names_report("log", 0, "util", "lua=%s", _VERSION)
return true, true
end
@@ -288,28 +297,47 @@ end
actions.generate = function (job)
local fontnames, savedname
- fontnames = names.update(fontnames, job.force_reload)
+ fontnames = names.update(fontnames, job.force_reload, job.dry_run)
logs.names_report("info", 2, "db",
"Fonts in the database: %i", #fontnames.mappings)
- savedname = names.save(fontnames)
- if savedname then --- FIXME have names.save return bool
+ local success = names.save(fontnames)
+ if success then
return true, true
end
return false, false
end
actions.flush = function (job)
- local success, lookups = names.flush_cache()
+ local success, lookups = names.flush_lookup_cache()
if success then
- local savedname = names.save_lookups()
- logs.names_report("info", 2, "cache", "Cache emptied")
- if savedname then
+ local success = names.save_lookups()
+ if success then
+ logs.names_report("info", 2, "cache", "Lookup cache emptied")
return true, true
end
end
return false, false
end
+local cache_directives = {
+ ["purge"] = names.purge_cache,
+ ["erase"] = names.erase_cache,
+ ["show"] = names.show_cache,
+}
+
+actions.cache = function (job)
+ local directive = cache_directives[job.cache]
+ if not directive or type(directive) ~= "function" then
+ logs.names_report("info", 2, "cache",
+ "Invalid font cache directive %s.", job.cache)
+ return false, false
+ end
+ if directive() then
+ return true, true
+ end
+ return false, false
+end
+
actions.query = function (job)
local query = job.query
@@ -520,24 +548,26 @@ local process_cmdline = function ( ) -- unit -> jobspec
}
local long_options = {
- alias = 1,
- ["flush-cache"] = "c",
- fields = 1,
- find = 1,
- force = "f",
- fuzzy = "F",
- help = "h",
- info = "i",
- limit = 1,
- list = 1,
- log = 1,
- quiet = "q",
- update = "u",
- verbose = 1 ,
- version = "V",
+ alias = 1,
+ cache = 1,
+ ["dry-run"] = "D",
+ ["flush-lookups"] = "l",
+ fields = 1,
+ find = 1,
+ force = "f",
+ fuzzy = "F",
+ help = "h",
+ info = "i",
+ limit = 1,
+ list = 1,
+ log = 1,
+ quiet = "q",
+ update = "u",
+ verbose = 1 ,
+ version = "V",
}
- local short_options = "cfFiquvVh"
+ local short_options = "DfFilquvVh"
local options, _, optarg =
alt_getopt.get_ordered_opts (arg, short_options, long_options)
@@ -586,13 +616,18 @@ local process_cmdline = function ( ) -- unit -> jobspec
result.show_info = true
elseif v == "alias" then
config.luaotfload.self = optarg[n]
- elseif v == "c" then
+ elseif v == "l" then
action_pending["flush"] = true
elseif v == "list" then
action_pending["list"] = true
result.criterion = optarg[n]
elseif v == "fields" then
result.asked_fields = optarg[n]
+ elseif v == "cache" then
+ action_pending["cache"] = true
+ result.cache = optarg[n]
+ elseif v == "D" then
+ result.dry_run = true
end
end
diff --git a/luaotfload-tool.rst b/luaotfload-tool.rst
index 6fc6138..9ea267b 100644
--- a/luaotfload-tool.rst
+++ b/luaotfload-tool.rst
@@ -17,11 +17,13 @@ SYNOPSIS
**luaotfload** [ -cfFiquvVh ]
-**luaotfload** --update [ --force ] [ --quiet ] [ --verbose ]
+**luaotfload** --update [ --force ] [ --quiet ] [ --verbose ] [ --dry-run ]
**luaotfload** --find=FONTNAME [ --fuzzy ] [ --info ]
-**luaotfload** --flush-cache
+**luaotfload** --flush-lookups
+
+**luaotfload** --cache=DIRECTIVE
**luaotfload** --list=CRITERION[:VALUE] [ --fields=F1,F2,...,Fn ]
@@ -53,6 +55,8 @@ update mode
--update, -u Update the database; indexes new fonts.
--force, -f Force rebuilding of the database; re-indexes
all fonts.
+--dry-run, -D Don’t load fonts, scan directories only.
+ (For debugging file system related issues.)
query mode
-----------------------------------------------------------------------
@@ -79,9 +83,17 @@ query mode
printed. The default is *fullname,version*.
(Only meaningful with ``--list``.)
-lookup cache
+font and lookup caches
-----------------------------------------------------------------------
---flush-cache Clear font name lookup cache (experimental).
+--flush-lookups Clear font name lookup cache (experimental).
+
+--cache=DIRECTIVE Cache control, where *DIRECTIVE* is one of the
+ following:
+
+ 1) ``purge`` -> delete Lua files from cache;
+ 2) ``erase`` -> delete Lua and Luc files from
+ cache;
+ 3) ``show`` -> print stats.
miscellaneous
-----------------------------------------------------------------------
diff --git a/luaotfload.dtx b/luaotfload.dtx
index b3a1304..7ccd6e8 100644
--- a/luaotfload.dtx
+++ b/luaotfload.dtx
@@ -146,14 +146,15 @@ and the derived files
\usepackage{hologo}
-\newcommand\TEX {\TeX\xspace}
-\newcommand\LUA {Lua\xspace}
-\newcommand\PDFTEX {pdf\TeX\xspace}
-\newcommand\LUATEX {Lua\TeX\xspace}
-\newcommand\XETEX {\XeTeX\xspace}
-\newcommand\LATEX {\LaTeX\xspace}
-\newcommand\CONTEXT {Con\TeX t\xspace}
-\newcommand\OpenType{\identifier{Open\kern-.25ex Type}\xspace}
+\newcommand\TEX {\TeX\xspace}
+\newcommand\LUA {Lua\xspace}
+\newcommand\PDFTEX {pdf\TeX\xspace}
+\newcommand\LUATEX {Lua\TeX\xspace}
+\newcommand\XETEX {\XeTeX\xspace}
+\newcommand\LATEX {\LaTeX\xspace}
+\newcommand\LUALATEX {Lua\LaTeX\xspace}
+\newcommand\CONTEXT {Con\TeX t\xspace}
+\newcommand\OpenType {\identifier{Open\kern-.25ex Type}\xspace}
\def\definehighlight[#1][#2]%
{\ifcsname #1\endcsname\else
@@ -258,7 +259,7 @@ and the derived files
% functionality like ligatures, old-style numbers, small capitals,
% etc., and support more complex writing systems like Arabic and
% Indic\footnote{%
-% Unfortunately, \identifier{luaotfload} doesn't support Indic
+% Unfortunately, \identifier{luaotfload} doesn‘t support many Indic
% scripts right now.
% Assistance in implementing the prerequisites is greatly
% appreciated.
@@ -282,6 +283,27 @@ and the derived files
% Additionally, it provides means for accessing fonts known to the operating
% system conveniently by indexing the metadata.
%
+%
+% \section{Thanks}
+%
+% \identifier{Luaotfload} is part of \LUALATEX, the community-driven
+% project to provide a foundation for using the \LATEX format with the
+% full capabilites of the \LUATEX engine.
+% As such, the distinction between end users, contributors, and project
+% maintainers is intentionally kept less strict, lest we unduly
+% personalize the common effort.
+%
+% Nevertheless, the current maintainers would like to express their
+% gratitude to Khaled Hosny, Akira Kakuto, Hironori Kitagawa and Dohyun
+% Kim.
+% Their contributions -- be it patches, advice, or systematic
+% testing -- made the switch from version 1.x to 2.2 possible.
+% Also, Hans Hagen, the author of the font loader, made porting the
+% code to \LATEX a breeze due to the extra effort he invested into
+% isolating it from the rest of \CONTEXT, not to mention his assistance
+% in the task and willingness to respond to our suggestions.
+%
+%
% \section{Loading Fonts}
%
% \identifier{luaotfload} supports an extended font request syntax: