diff options
-rw-r--r-- | luaotfload-auxiliary.lua | 6 | ||||
-rw-r--r-- | luaotfload-database.lua | 266 | ||||
-rw-r--r-- | luaotfload-override.lua | 11 | ||||
-rwxr-xr-x | luaotfload-tool.lua | 87 | ||||
-rw-r--r-- | luaotfload-tool.rst | 20 | ||||
-rw-r--r-- | luaotfload.dtx | 40 |
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: |