summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/tex/luatex/gregoriotex/gregoriotex.lua
diff options
context:
space:
mode:
Diffstat (limited to 'Master/texmf-dist/tex/luatex/gregoriotex/gregoriotex.lua')
-rw-r--r--Master/texmf-dist/tex/luatex/gregoriotex/gregoriotex.lua938
1 files changed, 683 insertions, 255 deletions
diff --git a/Master/texmf-dist/tex/luatex/gregoriotex/gregoriotex.lua b/Master/texmf-dist/tex/luatex/gregoriotex/gregoriotex.lua
index 6f15499f3ac..e87bbc553e0 100644
--- a/Master/texmf-dist/tex/luatex/gregoriotex/gregoriotex.lua
+++ b/Master/texmf-dist/tex/luatex/gregoriotex/gregoriotex.lua
@@ -1,6 +1,6 @@
--GregorioTeX Lua file.
--
---Copyright (C) 2008-2016 The Gregorio Project (see CONTRIBUTORS.md)
+--Copyright (C) 2008-2017 The Gregorio Project (see CONTRIBUTORS.md)
--
--This file is part of Gregorio.
--
@@ -24,19 +24,21 @@ local hpack, traverse, traverse_id, has_attribute, count, remove, insert_after,
gregoriotex = gregoriotex or {}
local gregoriotex = gregoriotex
-local internalversion = '4.1.5' -- GREGORIO_VERSION (comment used by VersionManager.py)
+local internalversion = '5.0.1' -- GREGORIO_VERSION (comment used by VersionManager.py)
local err, warn, info, log = luatexbase.provides_module({
name = "gregoriotex",
- version = '4.1.5', -- GREGORIO_VERSION
+ version = '5.0.1', -- GREGORIO_VERSION
greinternalversion = internalversion,
- date = "2016/08/18", -- GREGORIO_DATE_LTX
+ date = "2017/04/16", -- GREGORIO_DATE_LTX
description = "GregorioTeX module.",
author = "The Gregorio Project (see CONTRIBUTORS.md)",
- copyright = "2008-2016 - The Gregorio Project",
+ copyright = "2008-2017 - The Gregorio Project",
license = "GPLv3+",
})
+local real_gregorio_exe = nil
+
gregoriotex.module = { err = err, warn = warn, info = info, log = log }
local format = string.format
@@ -49,7 +51,7 @@ local whatsit = node.id('whatsit')
local hyphen = tex.defaulthyphenchar or 45
-local dash_attr = luatexbase.attributes['gre@attr@dash']
+local dash_attr = luatexbase.attributes['gre@attr@dash']
local potentialdashvalue = 1
local nopotentialdashvalue = 2
@@ -62,17 +64,28 @@ local glyph_top_attr = luatexbase.attributes['gre@attr@glyph@top']
local glyph_bottom_attr = luatexbase.attributes['gre@attr@glyph@bottom']
local prev_line_id = nil
+local syllable_id_attr = luatexbase.attributes['gre@attr@syllable@id']
+
local cur_score_id = nil
local score_inclusion = {}
local line_heights = nil
local new_line_heights = nil
local score_heights = nil
local new_score_heights = nil
-local var_brace_positions = nil
-local new_var_brace_positions = nil
-local pos_saves = nil
-local new_pos_saves = nil
+local saved_positions = nil
+local saved_lengths = nil
+local new_saved_lengths = nil
+local saved_newline_before_euouae = nil
+local new_saved_newline_before_euouae = nil
+local last_syllables = nil
+local new_last_syllables = nil
+local score_last_syllables = nil
+local new_score_last_syllables = nil
+local state_hashes = nil
+local new_state_hashes = nil
local auxname = nil
+local snippet_filename = nil
+local snippet_logname = nil
local space_below_staff = 5
local space_above_staff = 13
@@ -90,6 +103,13 @@ local number_to_letter = {
}
local capture_header_macro = {}
+local hashed_spaces = {}
+local space_hash = ''
+
+local per_line_dims = {}
+local per_line_counts = {}
+local saved_dims = {}
+local saved_counts = {}
local catcode_at_letter = luatexbase.catcodetables['gre@atletter']
@@ -98,9 +118,41 @@ local create_marker = luatexbase.new_user_whatsit('marker', 'gregoriotex')
local marker_whatsit_id = luatexbase.get_user_whatsit_id('marker', 'gregoriotex')
local translation_mark = 1
local abovelinestext_mark = 2
-
log("marker whatsit id is %d", marker_whatsit_id)
+local function gregorio_exe()
+ if real_gregorio_exe == nil then
+ local exe_version
+
+ -- first look for one with the exact version
+ real_gregorio_exe = 'gregorio-5_0_1' -- FILENAME_VERSION
+ exe_version = io.popen(real_gregorio_exe..' --version', 'r')
+ if exe_version then
+ exe_version = exe_version:read("*line")
+ end
+ if not exe_version then
+ -- look for suffix-less executable
+ real_gregorio_exe = 'gregorio'
+ exe_version = io.popen(real_gregorio_exe..' --version', 'r')
+ exe_version = exe_version:read("*line")
+ if not exe_version or string.match(exe_version,"%d+%.%d+%.")
+ ~= string.match(internalversion,"%d+%.%d+%.") then
+ real_gregorio_exe = nil
+ err("Unable to find gregorio executable.\n"..
+ "shell-escape mode may not be activated. Try\n\n"..
+ "%s --shell-escape %s.tex\n\n"..
+ "See the documentation of Gregorio or your TeX\n"..
+ "distribution to automatize it.",
+ tex.formatname, tex.jobname)
+ end
+ end
+
+ log("will use %s", real_gregorio_exe)
+ end
+
+ return real_gregorio_exe
+end
+
local function mark(value)
local marker = create_marker()
marker.type = 100
@@ -134,69 +186,130 @@ local function keys_changed(tab1, tab2)
return false
end
-local function heights_changed()
+local function saved_computations_changed(tab1, tab2)
+ local score_ids = {}
+ local id,_
+ for id,_ in pairs(tab1) do
+ score_ids[id] = true
+ end
+ for id,_ in pairs(tab2) do
+ score_ids[id] = true
+ end
+ for id,_ in pairs(score_ids) do
+ local inner1 = tab1[id]
+ local inner2 = tab2[id]
+ if inner1 == nil or inner2 == nil then return true end
+ local keys = {}
+ local index
+ for index,_ in pairs(inner1) do
+ keys[index] = true
+ end
+ for index,_ in pairs(inner2) do
+ keys[index] = true
+ end
+ for index,_ in pairs(keys) do
+ if inner1[index] ~= inner2[index] then return true end
+ end
+ end
+ return false
+end
+
+local function entries_changed(tab1, tab2)
+ local k, v
+ for k, v in pairs(tab1) do
+ if tab2[k] ~= v then return true end
+ end
+ return false
+end
+
+local function is_greaux_write_needed()
local id, tab
+ if entries_changed(state_hashes, new_state_hashes) or
+ entries_changed(new_state_hashes, state_hashes) then
+ return true
+ end
for id, tab in pairs(new_line_heights) do
if keys_changed(tab, line_heights[id]) then return true end
end
for id, tab in pairs(line_heights) do
if keys_changed(tab, new_line_heights[id]) then return true end
end
- for id, tab in pairs(new_var_brace_positions) do
- if keys_changed(tab, var_brace_positions[id]) then return true end
+ for id, tab in pairs(new_last_syllables) do
+ if keys_changed(tab, last_syllables[id]) then return true end
end
- for id, tab in pairs(var_brace_positions) do
- if keys_changed(tab, new_var_brace_positions[id]) then return true end
+ for id, tab in pairs(last_syllables) do
+ if keys_changed(tab, new_last_syllables[id]) then return true end
end
- for id, tab in pairs(new_pos_saves) do
- if keys_changed(tab, pos_saves[id]) then return true end
+ if saved_computations_changed(saved_lengths, new_saved_lengths) then
+ return true
end
- for id, tab in pairs(pos_saves) do
- if keys_changed(tab, new_pos_saves[id]) then return true end
+ if saved_computations_changed(saved_newline_before_euouae, new_saved_newline_before_euouae) then
+ return true
end
return false
end
local function write_greaux()
- if heights_changed() then
+ if is_greaux_write_needed() then
-- only write this if heights change; since table ordering is not
-- predictable, this ensures a steady state if the heights are unchanged.
local aux = io.open(auxname, 'w')
if aux then
log("Writing %s", auxname)
+ local id, tab, id2, line, value
aux:write('return {\n ["line_heights"]={\n')
- local id, tab, id2, line
for id, tab in pairs(new_line_heights) do
aux:write(string.format(' ["%s"]={\n', id))
for id2, line in pairs(tab) do
- aux:write(string.format(' [%d]={%d,%d,%d,%d},\n', id2, line[1],
- line[2], line[3], line[4]))
+ if id2 == 'last' then
+ aux:write(string.format(' ["%s"]=%d,\n', id2, line))
+ else
+ aux:write(string.format(' [%d]={%d,%d,%d,%d,%d},\n', id2, line[1],
+ line[2], line[3], line[4], line[5]))
+ end
end
aux:write(' },\n')
end
- aux:write(' },\n ["var_brace_positions"]={\n')
- for id, tab in pairs(new_var_brace_positions) do
+ aux:write(' },\n ["last_syllables"]={\n')
+ for id, tab in pairs(new_last_syllables) do
aux:write(string.format(' ["%s"]={\n', id))
- for id2, line in pairs(tab) do
- if line[1] ~= nil and line[2] ~= nil then
- aux:write(string.format(' [%d]={%d,%d},\n', id2, line[1],
- line[2]))
+ for id2, value in pairs(tab) do
+ if id2 == 'state' then
+ aux:write(string.format(' state="%s",\n', value))
+ else
+ aux:write(string.format(' [%d]=%d,\n', id2, value))
end
end
aux:write(' },\n')
end
- aux:write(' },\n ["pos_saves"]={\n')
- for id, tab in pairs(new_pos_saves) do
+ aux:write(' },\n ["saved_lengths"]={\n')
+ for id, tab in pairs(new_saved_lengths) do
aux:write(string.format(' ["%s"]={\n', id))
- for id2, line in pairs(tab) do
- if line[1] ~= nil and line[2] ~= nil and line[3] ~= nil and
- line[4] ~= nil then
- aux:write(string.format(' [%d]={%d,%d,%d,%d},\n', id2, line[1],
- line[2], line[3], line[4]))
+ for id2, value in pairs(tab) do
+ if value ~= nil then
+ aux:write(string.format(' [%d]=%d,\n', id2, value))
end
end
aux:write(' },\n')
end
+ aux:write(' },\n ["saved_newline_before_euouae"]={\n')
+ for id, tab in pairs(new_saved_newline_before_euouae) do
+ aux:write(string.format(' ["%s"]={\n', id))
+ for id2, value in pairs(tab) do
+ if value ~= nil then
+ if value then
+ aux:write(string.format(' [%d]=true,\n', id2))
+ else
+ aux:write(string.format(' [%d]=false,\n', id2))
+ end
+ end
+ end
+ aux:write(' },\n')
+ end
+ aux:write(' },\n ["state_hashes"]={\n')
+ for id, value in pairs(new_state_hashes) do
+ aux:write(string.format(' ["%s"]="%s",\n', id, value))
+ end
aux:write(' },\n}\n')
aux:close()
else
@@ -221,8 +334,12 @@ local function init(arg, enable_height_computation)
end
if outputdir and lfs.isdir(outputdir) then
auxname = outputdir..'/'..tex.jobname..'.gaux'
+ snippet_filename = outputdir..'/'..tex.jobname..'.gsnippet'
+ snippet_logname = outputdir..'/'..tex.jobname..'.gsniplog'
else
auxname = tex.jobname..'.gaux'
+ snippet_filename = tex.jobname..'.gsnippet'
+ snippet_logname = tex.jobname..'.gsniplog'
end
-- to get latexmk to realize the aux file is a dependency
@@ -231,16 +348,22 @@ local function init(arg, enable_height_computation)
log("Reading %s", auxname)
local score_info = dofile(auxname)
line_heights = score_info.line_heights or {}
- var_brace_positions = score_info.var_brace_positions or {}
- pos_saves = score_info.pos_saves or {}
+ last_syllables = score_info.last_syllables or {}
+ state_hashes = score_info.state_hashes or {}
+ saved_lengths = score_info.saved_lengths or {}
+ saved_newline_before_euouae = score_info.saved_newline_before_euouae or {}
else
line_heights = {}
- var_brace_positions = {}
- pos_saves = {}
+ last_syllables = {}
+ state_hashes = {}
+ saved_lengths = {}
+ saved_newline_before_euouae = {}
end
if enable_height_computation then
new_line_heights = {}
+ new_last_syllables = {}
+ new_state_hashes = {}
local mcb_version = luatexbase.get_module_version and
luatexbase.get_module_version('luatexbase-mcb') or 9999
@@ -262,8 +385,9 @@ local function init(arg, enable_height_computation)
'line heights. Remove or undefine \\greskipheightcomputation to '..
'resume height computation.')
end
- new_var_brace_positions = {}
- new_pos_saves = {}
+ saved_positions = {}
+ new_saved_lengths = {}
+ new_saved_newline_before_euouae = {}
end
-- node factory
@@ -357,15 +481,17 @@ end
local glue_sign_name = {[0] = 'normal', [1] = 'stretching', [2] = 'shrinking'}
-local function debugmessage(type, message)
+local function debugmessage(type, ...)
if (debug_types_activated[type] or debug_types_activated['all']) then
- texio.write_nl('GregorioTeX debug: ('..type..'): '..message)
+ texio.write_nl('GregorioTeX debug: ('..type..'): '..format(...))
end
end
+gregoriotex.module.debugmessage = debugmessage
+
-- in each function we check if we really are inside a score,
-- which we can see with the dash_attr being set or not
-local function process (h, groupcode, glyphes)
+local function post_linebreak(h, groupcode, glyphes)
-- TODO: to be changed according to the font
local lastseennode = nil
local adddash = false
@@ -378,6 +504,7 @@ local function process (h, groupcode, glyphes)
local line_has_translation = false
local line_has_abovelinestext = false
local linenum = 0
+ local syl_id = nil
-- we explore the lines
for line in traverse(h) do
if line.id == glue then
@@ -394,7 +521,7 @@ local function process (h, groupcode, glyphes)
h, line = remove(h, line)
else
linenum = linenum + 1
- debugmessage('linesglues', format('line %d: %s factor %d%%', linenum, glue_sign_name[line.glue_sign], line.glue_set*100))
+ debugmessage('linesglues', 'line %d: %s factor %d%%', linenum, glue_sign_name[line.glue_sign], line.glue_set*100)
centerstartnode = nil
line_id = nil
line_top = nil
@@ -402,6 +529,7 @@ local function process (h, groupcode, glyphes)
line_has_translation = false
line_has_abovelinestext = false
for n in traverse_id(hlist, line.head) do
+ syl_id = has_attribute(n, syllable_id_attr) or syl_id
if has_attribute(n, center_attr, startcenter) then
centerstartnode = n
elseif has_attribute(n, center_attr, endcenter) then
@@ -466,11 +594,15 @@ local function process (h, groupcode, glyphes)
addash=false
end
if line_id then
- new_score_heights[prev_line_id] = { line_top, line_bottom,
+ new_score_heights[prev_line_id] = { linenum, line_top, line_bottom,
line_has_translation and 1 or 0,
line_has_abovelinestext and 1 or 0 }
+ new_score_heights['last'] = prev_line_id
prev_line_id = line_id
end
+ if new_score_last_syllables and syl_id then
+ new_score_last_syllables[syl_id] = syl_id
+ end
end
-- we reinitialize the shift value, because it may change according to the line
currentshift=0
@@ -488,8 +620,75 @@ local function disable_hyphenation()
return false
end
-local function atScoreBeginning (score_id, top_height, bottom_height,
- has_translation, has_above_lines_text, top_height_adj, bottom_height_adj)
+local get_font_by_id = font.getfont --- cached, indexes fonts.hashes.identifiers
+local font_id = font.id
+
+-- an "unsafe" version of get_font_by_id that can see all fonts
+-- LuaTeX can see, which is needed when we need the font size of
+-- the user-selected current font
+local function unsafe_get_font_by_id(id)
+ return get_font_by_id(id) or font.fonts[id]
+end
+
+-- get_font_by_name(name) -- Look up a font identifier in the
+-- ``score_fonts`` table. Returns the id of the font if found, -1
+-- otherwise.
+local function get_font_by_name(name)
+ local id = font_id(name)
+ return id >= 0 and get_font_by_id(id)
+end
+
+-- get_score_font_id(name) -- Look up a font identifier in the
+-- ``score_fonts`` table. Returns the id of the font if found, -1
+-- otherwise.
+local function get_score_font_id(name)
+ local sfnt = score_fonts[name]
+ if sfnt then
+ return font_id(sfnt)
+ end
+ return -1
+end
+
+local resource_dummy = { unicodes = { } }
+
+-- get_font_resources(number) -- Retrieve the resource table
+-- associated with a font id. Always returns a Lua table value whose
+-- ``unicodes`` field is indexable.
+local function get_font_resources(id)
+ local fnt = get_font_by_id(id)
+ if fnt then
+ return fnt.resources or resource_dummy
+ end
+ return resource_dummy
+end
+
+-- get_score_font_resources(string) -- Retrieve the resource table
+-- belonging to a font in the ``score_font`` table. Always returns
+-- a table whose ``unicodes`` field is indexable.
+local function get_score_font_resources(name)
+ return get_font_resources(get_score_font_id(name))
+end
+
+local function get_score_font_unicode_pairs(name)
+ local unicodes = get_score_font_resources(name).unicodes
+ if not font_indexed[name] then
+ -- The unicodes table may be lazy-loaded, so iterating it may not
+ -- return everything. Attempting to retrieve the code point of a
+ -- glyph that has not already been loaded will trigger the __index
+ -- method in the metatable (implemented by the fontloader) to load
+ -- the table until the glyph is found. When iterating the
+ -- unicodes, we want the whole table to be filled, so we try to
+ -- access a non-existing glyph in order to force load the entire
+ -- table.
+ local ignored = unicodes['_this_is_hopefully_a_nonexistent_glyph_']
+ font_indexed[name] = true
+ end
+ return pairs(unicodes)
+end
+
+local function at_score_beginning(score_id, top_height, bottom_height,
+ has_translation, has_above_lines_text, top_height_adj, bottom_height_adj,
+ score_font_name)
local inclusion = score_inclusion[score_id] or 1
score_inclusion[score_id] = inclusion + 1
score_id = score_id..'.'..inclusion
@@ -507,14 +706,33 @@ local function atScoreBeginning (score_id, top_height, bottom_height,
score_heights = nil
new_score_heights = nil
end
+ local text_font = unsafe_get_font_by_id(font.current())
+ local score_font = unsafe_get_font_by_id(font.id('gre@font@music'))
+ local state = md5.sumhexa(string.format('%s|%d|%s|%d|%s', text_font.name,
+ text_font.size, score_font.name, score_font.size, space_hash))
+ score_last_syllables = last_syllables[score_id]
+ if score_last_syllables and state_hashes[score_id] ~= state then
+ score_last_syllables = nil
+ end
+ if new_state_hashes then
+ new_state_hashes[score_id] = state
+ end
+ if new_last_syllables then
+ new_score_last_syllables = {}
+ new_last_syllables[score_id] = new_score_last_syllables
+ end
- luatexbase.add_to_callback('post_linebreak_filter', process, 'gregoriotex.callback', 1)
+ luatexbase.add_to_callback('post_linebreak_filter', post_linebreak, 'gregoriotex.post_linebreak', 1)
luatexbase.add_to_callback("hyphenate", disable_hyphenation, "gregoriotex.disable_hyphenation", 1)
end
-local function atScoreEnd ()
- luatexbase.remove_from_callback('post_linebreak_filter', 'gregoriotex.callback')
+local function at_score_end()
+ luatexbase.remove_from_callback('post_linebreak_filter', 'gregoriotex.post_linebreak')
luatexbase.remove_from_callback("hyphenate", "gregoriotex.disable_hyphenation")
+ per_line_dims = {}
+ per_line_counts = {}
+ saved_dims = {}
+ saved_counts = {}
end
local function clean_old_gtex_files(file_withdir)
@@ -545,19 +763,44 @@ local function clean_old_gtex_files(file_withdir)
end
end
-local function compile_gabc(gabc_file, gtex_file)
+local function compile_gabc(gabc_file, gtex_file, glog_file, allow_deprecated)
info("compiling the score %s...", gabc_file)
local extra_args = ''
if tex.count['gre@generate@pointandclick'] == 1 then
- extra_args = ' -p'
+ extra_args = extra_args..' -p'
+ end
+ if not allow_deprecated then
+ extra_args = extra_args..' -D'
end
- res = os.execute(string.format("gregorio %s -o %s %s", extra_args, gtex_file, gabc_file))
+ local cmd = string.format('%s %s -W -o %s -l %s "%s"', gregorio_exe(),
+ extra_args, gtex_file, glog_file, gabc_file)
+ res = os.execute(cmd)
if res == nil then
- err("\nSomething went wrong when executing\n 'gregorio -o %s %s'.\n"
- .."shell-escape mode may not be activated. Try\n\n%s --shell-escape %s.tex\n\nSee the documentation of gregorio or your TeX\ndistribution to automatize it.", gtex_file, gabc_file, tex.formatname, tex.jobname)
+ err("\nSomething went wrong when executing\n '%s'.\n"
+ .."shell-escape mode may not be activated. Try\n\n"
+ .."%s --shell-escape %s.tex\n\n"
+ .."See the documentation of Gregorio or your TeX\n"
+ .."distribution to automatize it.",
+ cmd, tex.formatname, tex.jobname)
elseif res ~= 0 then
- err("\nAn error occured when compiling the score file\n'%s' with gregorio.\nPlease check your score file.", gabc_file)
+ local glog = io.open(glog_file, 'a+')
+ if glog == nil then
+ err("\n Unable to open %s", glog_file)
+ else
+ local size = glog:seek('end')
+ if size > 0 then
+ glog:seek('set')
+ local line
+ for line in glog:lines() do
+ warn(line)
+ end
+ end
+ glog:close()
+ end
+ err("\nAn error occured when compiling the score file\n"
+ .."'%s' with %s.\nPlease check your score file.", gabc_file,
+ gregorio_exe())
else
-- open the gtex file for writing so that LuaTeX records output to it
-- when the -recorder option is used
@@ -567,24 +810,49 @@ local function compile_gabc(gabc_file, gtex_file)
else
gtex:close()
end
+ local glog = io.open(glog_file, 'a+')
+ if glog == nil then
+ err("\n Unable to open %s", glog_file)
+ else
+ local size = glog:seek('end')
+ if size > 0 then
+ glog:seek('set')
+ local line
+ for line in glog:lines() do
+ warn(line)
+ end
+ warn("*** end of warnings for %s ***", gabc_file)
+ end
+ glog:close()
+ end
end
end
-local function include_score(input_file, force_gabccompile)
- local file_root
- if string.match(input_file:sub(-5), '%.gtex') then
- file_root = input_file:sub(1,-6)
- elseif string.match(input_file:sub(-4), '%.tex') then
- file_root = input_file:sub(1,-5)
- elseif string.match(input_file:sub(-5), '%.gabc') then
- file_root = input_file:sub(1,-6)
- elseif not file_root then
- file_root = input_file
+local function include_score(input_file, force_gabccompile, allow_deprecated)
+ if string.match(input_file, "[#%%]") then
+ err("GABC filename contains invalid character(s): # %%\n"
+ .."Rename the file and retry: %s", input_file)
end
- local gtex_file = file_root.."-"..internalversion:gsub("%.", "_")..".gtex"
- local gabc_file = file_root..".gabc"
+ local has_extention = false
+ local file_dir,input_name
+ local extensions = {['gabc']=true, ['gtex']=true, ['tex']=true}
+ if extensions[string.match(input_file, "([^%.\\/]*)$")] then
+ has_extention = true
+ end
+ if has_extention then
+ file_dir,input_name = string.match(input_file, "(.-)([^\\/]-)%.?[^%.\\/]*$")
+ else
+ file_dir,input_name = string.match(input_file, "(.-)([^\\/]*)$")
+ end
+
+ local cleaned_filename = input_name:gsub("[%s%+%&%*%?$@:;!\"\'`]", "-")
+ local gabc_file = string.format("%s%s.gabc", file_dir, input_name)
+ local gtex_file = string.format("%s%s-%s.gtex", file_dir, cleaned_filename,
+ internalversion:gsub("%.", "_"))
+ local glog_file = string.format("%s%s-%s.glog", file_dir, cleaned_filename,
+ internalversion:gsub("%.", "_"))
if not lfs.isfile(gtex_file) then
- clean_old_gtex_files(file_root)
+ clean_old_gtex_files(file_dir..cleaned_filename)
log("The file %s does not exist. Searching for a gabc file", gtex_file)
if lfs.isfile(gabc_file) then
local gabc = io.open(gabc_file, 'r')
@@ -594,7 +862,7 @@ local function include_score(input_file, force_gabccompile)
else
gabc:close()
end
- compile_gabc(gabc_file, gtex_file)
+ compile_gabc(gabc_file, gtex_file, glog_file, allow_deprecated)
tex.print(string.format([[\input %s\relax]], gtex_file))
return
else
@@ -615,103 +883,65 @@ local function include_score(input_file, force_gabccompile)
end
if gtex_timestamp < gabc_timestamp then
log("%s has been modified and %s needs to be updated. Recompiling the gabc file.", gabc_file, gtex_file)
- compile_gabc(gabc_file, gtex_file)
+ compile_gabc(gabc_file, gtex_file, glog_file, allow_deprecated)
elseif force_gabccompile then
- compile_gabc(gabc_file, gtex_file)
+ compile_gabc(gabc_file, gtex_file, glog_file, allow_deprecated)
end
tex.print(string.format([[\input %s\relax]], gtex_file))
return
end
-local function direct_gabc(gabc, header)
- tmpname = os.tmpname()
- local f = io.open(tmpname, 'w')
+local function direct_gabc(gabc, header, allow_deprecated)
+ info('Processing gabc snippet...')
+ local deprecated
+ if allow_deprecated then
+ deprecated = ''
+ else
+ deprecated = '-D '
+ end
+ local f = io.open(snippet_filename, 'w')
-- trims spaces on both ends (trim6 from http://lua-users.org/wiki/StringTrim)
gabc = gabc:match('^()%s*$') and '' or gabc:match('^%s*(.*%S)')
f:write('name:direct-gabc;\n'..(header or '')..'\n%%\n'..gabc:gsub('\\par ', '\n'))
f:close()
- local p = io.popen('gregorio -S '..tmpname, 'r')
+ local cmd = string.format('%s -W %s-S -l %s %s', gregorio_exe(), deprecated,
+ snippet_logname, snippet_filename)
+ local p = io.popen(cmd, 'r')
if p == nil then
- err("\nSomething went wrong when executing\n gregorio -S "..tmpname..".\n"
- .."shell-escape mode may not be activated. Try\n\n%s --shell-escape %s.tex\n\nSee the documentation of gregorio or your TeX\ndistribution to automatize it.", tex.formatname, tex.jobname)
- end
- tex.print(p:read("*a"):explode('\n'))
- p:close()
- os.remove(tmpname)
-end
-
-local function get_gregorioversion()
- return internalversion
-end
-
-local get_font_by_id = font.getfont --- cached, indexes fonts.hashes.identifiers
-local font_id = font.id
-
--- an "unsafe" version of get_font_by_id that can see all fonts
--- LuaTeX can see, which is needed when we need the font size of
--- the user-selected current font
-local function unsafe_get_font_by_id(id)
- return get_font_by_id(id) or font.fonts[id]
-end
-
--- get_font_by_name(name) -- Look up a font identifier in the
--- ``score_fonts`` table. Returns the id of the font if found, -1
--- otherwise.
-local function get_font_by_name(name)
- local id = font_id(name)
- return id >= 0 and get_font_by_id(id)
-end
-
--- get_score_font_id(name) -- Look up a font identifier in the
--- ``score_fonts`` table. Returns the id of the font if found, -1
--- otherwise.
-local function get_score_font_id(name)
- local sfnt = score_fonts[name]
- if sfnt then
- return font_id(sfnt)
+ err("\nSomething went wrong when executing\n %s\n"
+ .."shell-escape mode may not be activated. Try\n\n"
+ .."%s --shell-escape %s.tex\n\n"
+ .."See the documentation of Gregorio or your TeX\n"
+ .."distribution to automatize it.", cmd, tex.formatname, tex.jobname)
+ else
+ tex.print(p:read("*a"):explode('\n'))
+ p:close()
end
- return -1
-end
-
-local resource_dummy = { unicodes = { } }
-
--- get_font_resources(number) -- Retrieve the resource table
--- associated with a font id. Always returns a Lua table value whose
--- ``unicodes`` field is indexable.
-local function get_font_resources(id)
- local fnt = get_font_by_id(id)
- if fnt then
- return fnt.resources or resource_dummy
+ local glog = io.open(snippet_logname, 'a+')
+ if glog == nil then
+ err("\n Unable to open %s", snippet_logname)
+ else
+ local size = glog:seek('end')
+ if size > 0 then
+ glog:seek('set')
+ local line
+ for line in glog:lines() do
+ warn(line)
+ end
+ warn("*** end of warnings/errors processing snippet ***")
+ end
+ glog:close()
end
- return resource_dummy
-end
-
--- get_score_font_resources(string) -- Retrieve the resource table
--- belonging to a font in the ``score_font`` table. Always returns
--- a table whose ``unicodes`` field is indexable.
-local function get_score_font_resources(name)
- return get_font_resources(get_score_font_id(name))
+ os.remove(snippet_filename)
+ os.remove(snippet_logname)
end
-local function get_score_font_unicode_pairs(name)
- local unicodes = get_score_font_resources(name).unicodes
- if not font_indexed[name] then
- -- The unicodes table may be lazy-loaded, so iterating it may not
- -- return everything. Attempting to retrieve the code point of a
- -- glyph that has not already been loaded will trigger the __index
- -- method in the metatable (implemented by the fontloader) to load
- -- the table until the glyph is found. When iterating the
- -- unicodes, we want the whole table to be filled, so we try to
- -- access a non-existing glyph in order to force load the entire
- -- table.
- local ignored = unicodes['_this_is_hopefully_a_nonexistent_glyph_']
- font_indexed[name] = true
- end
- return pairs(unicodes)
+local function get_gregoriotexluaversion()
+ return internalversion
end
-local function check_font_version()
- local gregoriofont = get_font_by_name('gre@font@music')
+local function check_one_font_version(name)
+ local gregoriofont = get_font_by_name(name)
if gregoriofont then
local fontversion = gregoriofont.shared.rawdata.metadata.version
if fontversion and string.match(fontversion, "%d+%.%d+%.%d+") ~= string.match(internalversion, "%d+%.%d+%.%d+") then
@@ -721,12 +951,18 @@ local function check_font_version()
end
end
+local function check_font_version()
+ check_one_font_version('gre@font@music')
+ check_one_font_version('gre@font@music@hollow')
+ check_one_font_version('gre@font@music@hole')
+end
+
local function map_font(name, prefix)
log("Mapping font %s", name)
local glyph, unicode
for glyph, unicode in get_score_font_unicode_pairs(name) do
if unicode >= 0 and not string.match(glyph, '%.') then
- log("Setting \\Gre%s%s to \\char%d", prefix, glyph, unicode)
+ debugmessage("mapfont", "Setting \\Gre%s%s to \\char%d", prefix, glyph, unicode)
tex.sprint(catcode_at_letter, string.format(
[[\xdef\Gre%s%s{\char%d}]], prefix, glyph, unicode))
end
@@ -741,13 +977,18 @@ local function init_variant_font(font_name, for_score, gre_factor)
font_table[font_name] = font_csname
log("Registering variant font %s as %s.", font_name, font_csname)
if for_score then
+ local _, name, factor
+ _, _, name, factor = string.find(font_name, '^([^@]*)@(%d*)$')
+ name = name or font_name
+ factor = factor or '100000'
+ local size = gre_factor * tonumber(factor)
tex.print(catcode_at_letter, string.format(
- [[\global\font\%s = {name:%s} at 10 sp\relax ]],
- font_csname, font_name))
+ [[\global\font\%s = {name:%s} at %s sp\relax ]],
+ font_csname, name, size))
-- loaded_font_sizes will only be given a value if the font is for_score
- loaded_font_sizes[font_name] = {size = '10', gre_factor = gre_factor}
+ loaded_font_sizes[font_name] = {size = size, gre_factor = gre_factor}
if font_factors[font_name] == nil then
- font_factors[font_name] = '100000'
+ font_factors[font_name] = factor
end
else
-- is there a nice way to make this string readable?
@@ -762,14 +1003,14 @@ local function init_variant_font(font_name, for_score, gre_factor)
end
local function set_score_glyph(csname, font_csname, char)
- log([[Setting \%s to \%s\char%d]], csname, font_csname, char)
+ debugmessage('changeglyph', [[Setting \%s to \%s\char%d]], csname, font_csname, char)
tex.print(catcode_at_letter, string.format(
[[\edef\%s{{\noexpand\%s\char%d}}]], csname, font_csname, char))
end
local function set_common_score_glyph(csname, font_csname, char)
-- font_csname is ignored
- log([[Setting \%s to \char%d]], csname, char)
+ debugmessage('changeglyph', [[Setting \%s to \char%d]], csname, char)
tex.print(catcode_at_letter, string.format(
[[\edef\%s{{\char%d}}]], csname, char))
end
@@ -804,32 +1045,46 @@ local function def_glyph(csname, font_name, glyph, font_table, setter)
setter(csname, font_csname, char)
end
-local function change_single_score_glyph(glyph_name, font_name, replacement)
- if font_name == '*' then def_glyph('GreCP'..glyph_name, 'greciliae', replacement, score_fonts, set_common_score_glyph)
+local function general_font_for(cavum)
+ if cavum == 'Hollow' then
+ return 'greciliae-hollow'
+ elseif cavum == 'Hole' then
+ return 'greciliae-hole'
+ else
+ return 'greciliae'
+ end
+end
+
+local function change_single_score_glyph(glyph_name, cavum, font_name, replacement)
+ if font_name == '*' then
+ def_glyph('Gre'..cavum..'CP'..glyph_name, general_font_for(cavum),
+ replacement, score_fonts, set_common_score_glyph)
else
- def_glyph('GreCP'..glyph_name, font_name, replacement, score_fonts,
- set_score_glyph)
+ def_glyph('Gre'..cavum..'CP'..glyph_name, font_name, replacement,
+ score_fonts, set_score_glyph)
end
end
-local function change_score_glyph(glyph_name, font_name, replacement)
+local function change_score_glyph(glyph_name, font_name, replacement, cavum)
+ cavum = cavum or ''
if string.match(glyph_name, '%*') then
glyph_name = '^'..glyph_name:gsub('%*', '.*')..'$'
if not string.match(replacement, '^%.') then
err('If a wildcard is supplied for glyph name, replacement must start with a dot.')
end
+ local general_font = general_font_for(cavum)
local other_font
if font_name == '*' then
- other_font = get_score_font_resources('greciliae').unicodes
+ other_font = get_score_font_resources(general_font).unicodes
else
other_font = get_score_font_resources(font_name).unicodes
end
local name, char
- for name, char in get_score_font_unicode_pairs('greciliae') do
+ for name, char in get_score_font_unicode_pairs(general_font) do
if not string.match(name, '%.') and char >= 0 and string.match(name, glyph_name) then
local matched_replacement = name..replacement
if other_font[matched_replacement] ~= nil and other_font[matched_replacement] >= 0 then
- change_single_score_glyph(name, font_name, matched_replacement)
+ change_single_score_glyph(name, cavum, font_name, matched_replacement)
end
end
end
@@ -837,25 +1092,27 @@ local function change_score_glyph(glyph_name, font_name, replacement)
if string.match(replacement, '^%.') then
replacement = glyph_name..replacement
end
- change_single_score_glyph(glyph_name, font_name, replacement)
+ change_single_score_glyph(glyph_name, cavum, font_name, replacement)
end
end
-local function reset_score_glyph(glyph_name)
+local function reset_score_glyph(glyph_name, cavum)
+ cavum = cavum or ''
+ local general_font = general_font_for(cavum)
if string.match(glyph_name, '%*') then
glyph_name = '^'..glyph_name:gsub('%*', '.*')..'$'
local name, char
- for name, char in get_score_font_unicode_pairs('greciliae') do
+ for name, char in get_score_font_unicode_pairs(general_font) do
if not string.match(name, '%.') and char >= 0 and string.match(name, glyph_name) then
- set_common_score_glyph('GreCP'..name, nil, char)
+ set_common_score_glyph('Gre'..cavum..'CP'..name, nil, char)
end
end
else
- local char = get_score_font_resources("greciliae").unicodes[glyph_name]
+ local char = get_score_font_resources(general_font).unicodes[glyph_name]
if char == nil then
err('\nGlyph %s was not found.', glyph_name)
end
- set_common_score_glyph('GreCP'..glyph_name, nil, char)
+ set_common_score_glyph('Gre'..cavum..'CP'..glyph_name, nil, char)
end
end
@@ -863,12 +1120,17 @@ local function set_font_factor(font_name, font_factor)
font_factors[font_name] = font_factor
end
-local function scale_score_fonts(size, gre_factor)
+local function scale_score_fonts(gre_factor)
for font_name, font_csname in pairs(score_fonts) do
if loaded_font_sizes[font_name] and font_factors[font_name] and loaded_font_sizes[font_name].size ~= gre_factor * font_factors[font_name] then
+ local _, name
+ _, _, name, _ = string.find(font_name, '^([^@]*)@(%d*)$')
+ name = name or font_name
+ local size = gre_factor * font_factors[font_name]
+ log("%s : %s : rescaling %s to %s", font_name, font_csname, name, size)
tex.print(catcode_at_letter, string.format(
[[\global\font\%s = {name:%s} at %s sp\relax ]],
- font_csname, font_name, gre_factor * font_factors[font_name]))
+ font_csname, name, size))
loaded_font_sizes[font_name] = {size = size, gre_factor = gre_factor}
end
end
@@ -883,78 +1145,209 @@ local function font_size()
tex.print(string.format('%.2f', (unsafe_get_font_by_id(font.current()).size / 65536.0)))
end
-local function adjust_line_height(inside_discretionary)
- if score_heights then
- local heights = score_heights[tex.getattribute(glyph_id_attr)]
- if heights then
+local function adjust_line_height_internal(heights, inside_discretionary, for_next_line)
+ local backup_dims = saved_dims
+ local backup_counts = saved_counts
+ -- restore saved dims
+ local name, value
+ for name, value in pairs(saved_dims) do
+ tex.sprint(catcode_at_letter, string.format(
+ [[\grechangedim{%s}{%s}{%s}]], name, value[1], value[2]))
+ end
+ for name, value in pairs(saved_counts) do
+ tex.sprint(catcode_at_letter, string.format(
+ [[\grechangecount{%s}{%s}]], name, value))
+ end
+ -- clear saved dims
+ saved_dims = {}
+ saved_counts = {}
+ -- apply per-line dims
+ local line_dims = per_line_dims[heights[1]]
+ if line_dims ~= nil then
+ for name, value in pairs(line_dims) do
+ tex.sprint(catcode_at_letter, string.format(
+ [[\gre@changedimforline{%s}{%s}{%s}]], name, value[1], value[2]))
+ end
+ end
+ local line_counts = per_line_counts[heights[1]]
+ if line_counts ~= nil then
+ for name, value in pairs(line_counts) do
+ tex.sprint(catcode_at_letter, string.format(
+ [[\gre@changecountforline{%s}{%s}]], name, value))
+ end
+ end
+ -- recalculate spaces
+ tex.sprint(catcode_at_letter, string.format(
+ [[\gre@calculate@additionalspaces{%d}{%d}{%d}{%d}]],
+ heights[2], heights[3], heights[4], heights[5]))
+ if inside_discretionary == 0 then
+ tex.sprint(catcode_at_letter, [[\gre@updateleftbox ]])
+ end
+ if for_next_line then
+ -- IS THIS GOOD ENOUGH???
+ -- restore saved dims (from current line)
+ local name, value
+ for name, value in pairs(saved_dims) do
+ tex.sprint(catcode_at_letter, string.format(
+ [[\grechangedim{%s}{%s}{%s}]], name, value[1], value[2]))
+ end
+ for name, value in pairs(saved_counts) do
tex.sprint(catcode_at_letter, string.format(
- [[\gre@calculate@additionalspaces{%d}{%d}{%d}{%d}]],
- heights[1], heights[2], heights[3], heights[4]))
- if inside_discretionary == 0 then
- tex.sprint(catcode_at_letter, [[\gre@updateleftbox ]])
+ [[\grechangecount{%s}{%s}]], name, value))
+ end
+ -- put previous saved dims back
+ saved_dims = backup_dims
+ saved_counts = backup_counts
+ end
+end
+
+local function adjust_line_height(inside_discretionary, for_next_line)
+ if score_heights then
+ local heights = nil
+ if for_next_line then
+ local last = score_heights['last']
+ if last then
+ local target_id = tex.getattribute(glyph_id_attr) + 1
+ while target_id <= last do
+ heights = score_heights[target_id]
+ if heights then break end
+ target_id = target_id + 1
+ end
end
+ else
+ heights = score_heights[tex.getattribute(glyph_id_attr)]
+ end
+ if heights then
+ adjust_line_height_internal(heights, inside_discretionary, for_next_line)
end
end
end
-local function var_brace_note_pos(brace, start_end)
- tex.print(catcode_at_letter, string.format([[\luatexlatelua{gregoriotex.late_brace_note_pos('%s', %d, %d, \number\gre@lastxpos)}]], cur_score_id, brace, start_end))
+local function save_dim(name, value, modifier)
+ saved_dims[name] = { value, modifier }
end
-local function late_brace_note_pos(score_id, brace, start_end, pos)
- if new_var_brace_positions[score_id] == nil then
- new_var_brace_positions[score_id] = {}
- end
- if new_var_brace_positions[score_id][brace] == nil then
- new_var_brace_positions[score_id][brace] = {}
+local function save_count(name, value)
+ saved_counts[name] = value
+end
+
+local function change_next_score_line_dim(line_expr, name, value, modifier)
+ local linenum_str
+ for linenum_str in string.gmatch(line_expr, "%s*([^,]+)%s*") do
+ local linenum = tonumber(linenum_str)
+ local line_dims = per_line_dims[linenum]
+ if line_dims == nil then
+ line_dims = {}
+ per_line_dims[linenum] = line_dims
+ end
+ line_dims[name] = { value, modifier }
end
- new_var_brace_positions[score_id][brace][start_end] = pos
end
-local function var_brace_len(brace)
- if var_brace_positions[cur_score_id] ~= nil then
- if var_brace_positions[cur_score_id][brace] ~= nil then
- local posend = var_brace_positions[cur_score_id][brace][2]
- local posstart = var_brace_positions[cur_score_id][brace][1]
- if posend > posstart then
- tex.print(string.format('%dsp', posend - posstart))
- else
- warn('Dynamically sized braces spanning multiple lines unsupported, using length 2mm.')
- tex.print('2mm')
- end
- return
+local function change_next_score_line_count(line_expr, name, value)
+ local linenum_str
+ for linenum_str in string.gmatch(line_expr, "([^,]+)") do
+ local linenum = tonumber(linenum_str)
+ local line_counts = per_line_counts[linenum]
+ if line_counts == nil then
+ line_counts = {}
+ per_line_counts[linenum] = line_counts
end
+ line_counts[name] = value
end
- tex.print('2mm')
end
-local function save_pos(index, which)
- tex.print(catcode_at_letter, string.format([[\gre@savepos\luatexlatelua{gregoriotex.late_save_pos('%s', %d, %d, \number\gre@lastxpos, \number\gre@lastypos)}]], cur_score_id, index, which))
+local function prep_save_position(index, fn)
+ if saved_positions[cur_score_id] == nil then
+ saved_positions[cur_score_id] = {}
+ end
+ saved_positions[cur_score_id][index] = { fn = fn }
+end
+
+local function save_position(index, which)
+ tex.print(catcode_at_letter, string.format([[\luatexlatelua{gregoriotex.late_save_position('%s', %d, %d, \number\gre@lastxpos, \number\gre@lastypos)}]], cur_score_id, index, which))
end
-local function late_save_pos(score_id, index, which, xpos, ypos)
- if new_pos_saves[score_id] == nil then
- new_pos_saves[score_id] = {}
+local function late_save_position(score_id, index, which, xpos, ypos)
+ info('saving %s, %d [%d] (%d,%d)', score_id, index, which, xpos, ypos)
+ local pos = saved_positions[score_id][index]
+ if pos == nil then
+ err('Attempting to use unprepared position save slot %d', index)
+ return
end
- if new_pos_saves[score_id][index] == nil then
- new_pos_saves[score_id][index] = {}
+ --[[
+ if pos.fn == nil then
+ err('Attempting to reuse position save slot %d', index)
+ return
+ end
+ --]]
+ pos['x'..which] = xpos
+ pos['y'..which] = ypos
+ if pos.x1 ~= nil and pos.y1 ~= nil and pos.x2 ~= nil and pos.y2 ~= nil then
+ pos.fn(score_id, index, pos)
+ --pos.fn = nil
end
- new_pos_saves[score_id][index][(2 * which) - 1] = xpos
- new_pos_saves[score_id][index][2 * which] = ypos
+end
+
+local function compute_saved_length(score_id, index, pos)
+ if new_saved_lengths[score_id] == nil then
+ new_saved_lengths[score_id] = {}
+ end
+ new_saved_lengths[score_id][index] = pos.x2 - pos.x1
+ info('computed length for %s, %d: %d', score_id, index,
+ new_saved_lengths[score_id][index])
+end
+
+local function save_length(index, which)
+ if which == 1 then
+ prep_save_position(index, compute_saved_length)
+ end
+ save_position(index, which)
+end
+
+local function compute_saved_newline_before_euouae(score_id, index, pos)
+ if new_saved_newline_before_euouae[score_id] == nil then
+ new_saved_newline_before_euouae[score_id] = {}
+ end
+ new_saved_newline_before_euouae[score_id][index] = pos.y2 ~= pos.y1
+ info('computed euouae for %s, %d: %s', score_id, index,
+ new_saved_newline_before_euouae[score_id][index])
+end
+
+local function save_euouae(index, which)
+ if which == 1 then
+ prep_save_position(index, compute_saved_newline_before_euouae)
+ end
+ tex.sprint(catcode_at_letter, [[\gre@savepos]])
+ save_position(index, which)
+end
+
+local function var_brace_len(brace)
+ if saved_lengths[cur_score_id] ~= nil then
+ local length = saved_lengths[cur_score_id][brace]
+ if saved_lengths[cur_score_id][brace] ~= nil then
+ if length > 0 then
+ tex.print(string.format('%dsp', length))
+ return
+ else
+ warn('Dynamically sized signs spanning multiple lines unsupported, using length 2mm.')
+ end
+ end
+ end
+ tex.print('2mm')
end
-- this function is meant to be used from \ifcase; prints 0 for true and 1 for false
local function is_ypos_different(index)
- if pos_saves[cur_score_id] ~= nil then
- local saved_pos = pos_saves[cur_score_id][index]
- if saved_pos == nil or saved_pos[2] == saved_pos[4] then
- tex.sprint([[\number1\relax ]])
- else
+ if saved_newline_before_euouae[cur_score_id] ~= nil then
+ local newline_before_euouae =
+ saved_newline_before_euouae[cur_score_id][index]
+ if newline_before_euouae then
tex.sprint([[\number0\relax ]])
+ return
end
- else
- tex.sprint([[\number1\relax ]])
end
+ tex.sprint([[\number1\relax ]])
end
local function width_to_bp(width, value_if_star)
@@ -1031,39 +1424,74 @@ local function mode_part(part)
end
end
-gregoriotex.number_to_letter = number_to_letter
-gregoriotex.init = init
-gregoriotex.include_score = include_score
-gregoriotex.atScoreEnd = atScoreEnd
-gregoriotex.atScoreBeginning = atScoreBeginning
-gregoriotex.check_font_version = check_font_version
-gregoriotex.get_gregorioversion = get_gregorioversion
-gregoriotex.map_font = map_font
-gregoriotex.init_variant_font = init_variant_font
-gregoriotex.change_score_glyph = change_score_glyph
-gregoriotex.reset_score_glyph = reset_score_glyph
-gregoriotex.scale_score_fonts = scale_score_fonts
-gregoriotex.set_font_factor = set_font_factor
-gregoriotex.def_symbol = def_symbol
-gregoriotex.font_size = font_size
-gregoriotex.direct_gabc = direct_gabc
-gregoriotex.adjust_line_height = adjust_line_height
-gregoriotex.var_brace_len = var_brace_len
-gregoriotex.var_brace_note_pos = var_brace_note_pos
-gregoriotex.late_brace_note_pos = late_brace_note_pos
-gregoriotex.mark_translation = mark_translation
-gregoriotex.mark_abovelinestext = mark_abovelinestext
-gregoriotex.width_to_bp = width_to_bp
-gregoriotex.hypotenuse = hypotenuse
-gregoriotex.rotation = rotation
-gregoriotex.scale_space = scale_space
-gregoriotex.set_header_capture = set_header_capture
-gregoriotex.capture_header = capture_header
-gregoriotex.save_pos = save_pos
-gregoriotex.late_save_pos = late_save_pos
-gregoriotex.is_ypos_different = is_ypos_different
-gregoriotex.mode_part = mode_part
-gregoriotex.set_debug_string = set_debug_string
+-- this function is meant to be used from \ifcase; prints 0 for true and 1 for false
+local function is_last_syllable_on_line()
+ if score_last_syllables then
+ if score_last_syllables[tex.getattribute(syllable_id_attr)] then
+ tex.print(0)
+ else
+ tex.print(1)
+ end
+ else
+ -- if the last syllable is not computed, treat all syllables as the
+ -- last on a line
+ tex.print(0)
+ end
+end
+
+local function hash_spaces(name, value)
+ hashed_spaces[name] = value
+ local k, _
+ local keys = {}
+ for k,_ in pairs(hashed_spaces) do
+ table.insert(keys, k)
+ end
+ table.sort(keys)
+ local mash = ''
+ for _,k in ipairs(keys) do
+ mash = string.format('%s%s:%s|', mash, k, hashed_spaces[k])
+ end
+ space_hash = md5.sumhexa(mash)
+end
+
+gregoriotex.number_to_letter = number_to_letter
+gregoriotex.init = init
+gregoriotex.include_score = include_score
+gregoriotex.at_score_end = at_score_end
+gregoriotex.at_score_beginning = at_score_beginning
+gregoriotex.check_font_version = check_font_version
+gregoriotex.get_gregoriotexluaversion = get_gregoriotexluaversion
+gregoriotex.map_font = map_font
+gregoriotex.init_variant_font = init_variant_font
+gregoriotex.change_score_glyph = change_score_glyph
+gregoriotex.reset_score_glyph = reset_score_glyph
+gregoriotex.scale_score_fonts = scale_score_fonts
+gregoriotex.set_font_factor = set_font_factor
+gregoriotex.def_symbol = def_symbol
+gregoriotex.font_size = font_size
+gregoriotex.direct_gabc = direct_gabc
+gregoriotex.adjust_line_height = adjust_line_height
+gregoriotex.var_brace_len = var_brace_len
+gregoriotex.save_length = save_length
+gregoriotex.mark_translation = mark_translation
+gregoriotex.mark_abovelinestext = mark_abovelinestext
+gregoriotex.width_to_bp = width_to_bp
+gregoriotex.hypotenuse = hypotenuse
+gregoriotex.rotation = rotation
+gregoriotex.scale_space = scale_space
+gregoriotex.set_header_capture = set_header_capture
+gregoriotex.capture_header = capture_header
+gregoriotex.is_ypos_different = is_ypos_different
+gregoriotex.save_euouae = save_euouae
+gregoriotex.mode_part = mode_part
+gregoriotex.set_debug_string = set_debug_string
+gregoriotex.late_save_position = late_save_position
+gregoriotex.is_last_syllable_on_line = is_last_syllable_on_line
+gregoriotex.hash_spaces = hash_spaces
+gregoriotex.save_dim = save_dim
+gregoriotex.save_count = save_count
+gregoriotex.change_next_score_line_dim = change_next_score_line_dim
+gregoriotex.change_next_score_line_count = change_next_score_line_count
dofile(kpse.find_file('gregoriotex-nabc.lua', 'lua'))
dofile(kpse.find_file('gregoriotex-signs.lua', 'lua'))