Skip to content

Commit 18c436e

Browse files
OmikhleiaDidier Willis
authored andcommitted
feat(packages): Partial support for name-parts formatting
1 parent 64eaba4 commit 18c436e

1 file changed

Lines changed: 91 additions & 25 deletions

File tree

packages/bibtex/csl/engine.lua

Lines changed: 91 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -831,6 +831,28 @@ function CslEngine:_name_et_al (options)
831831
return t
832832
end
833833

834+
local function initialize (options, entry)
835+
if SU.boolean(options.initialize, true) and options['initialize-with'] then
836+
-- FIXME TODO Quick and dirty:
837+
-- Major styles abbreviate the given name with ". " as initialize-with
838+
-- and don't set initialize-with-hyphen to false.
839+
-- So here we just use the short name already derived by our BibTeX parser.
840+
-- ... But this is not general, obviously.
841+
return entry['given-short'] .. options['initialize-with']:gsub("%s*$", "")
842+
end
843+
return entry.given
844+
end
845+
846+
function CslEngine:_format_a_name (options, name)
847+
if not options then
848+
return name
849+
end
850+
return self:_render_formatting(
851+
self:_render_textCase(name, options),
852+
options
853+
)
854+
end
855+
834856
function CslEngine:_a_name (options, content, entry)
835857
if entry.literal then -- pass through literal names
836858
return entry.literal
@@ -875,36 +897,71 @@ function CslEngine:_a_name (options, content, entry)
875897
return table.concat(name, " ")
876898
end
877899

878-
local form = options.form
879-
local nameAsSortOrder = options["name-as-sort-order"] or "first"
880-
881-
-- TODO FIXME: content can consists in name-part elements for formatting, text-case, affixes
882-
-- Chigaco style does not seem to use them, so we keep it "simple" for now.
900+
-- Name-parts for formatting:
901+
-- If set to “given”, formatting and text-case attributes on cs:name-part affect
902+
-- the “given” and “dropping-particle” name-parts.
903+
-- FIXME TODO Affixes surround the “given” name-part, enclosing any demoted name
904+
-- particles for inverted names.
905+
-- If set to “family”, formatting and text-case attributes affect the “family” and
906+
-- “non-dropping-particle” name-parts.
907+
-- FIXME TODO Affixes surround the “family” name-part, enclosing any preceding name
908+
-- particles, as well as the “suffix” name-part for non-inverted names.
909+
-- N.B. Very few styles use affixes, hence the FIXME TODO, not implemented yet.
910+
if not options["__name-parts"] then
911+
-- First the options from the cs:name node
912+
local formattingAndCaseOptions = {
913+
["text-case"] = options["text-case"],
914+
["font-style"] = options["font-style"],
915+
["font-variant"] = options["font-variant"],
916+
["font-weight"] = options["font-weight"],
917+
["text-decoration"] = options["text-decoration"],
918+
["vertical-align"] = options["vertical-align"],
919+
}
920+
local namePartOptions = {
921+
given = formattingAndCaseOptions,
922+
family = formattingAndCaseOptions,
923+
}
924+
for _, namep in ipairs(content) do
925+
-- Override with the options for the cs:name-part explicit nodes, if any
926+
if namep.command == "cs:name-part" then
927+
namePartOptions[namep.options.name] = pl.tablex.merge(
928+
namePartOptions[namep.options.name],
929+
namep.options,
930+
true
931+
)
932+
end
933+
end
934+
options["__name-parts"] = namePartOptions -- memoize
935+
end
936+
local namepartOptions = options["__name-parts"]
883937

938+
local form = options.form
884939
if form == "short" then
885940
-- Order is: [NDP] Family, e.g. van Gogh
886941
if entry["non-dropping-particle"] then
887942
return table.concat({
888-
entry["non-dropping-particle"],
889-
entry.family,
943+
self:_format_a_name(namepartOptions.family, entry["non-dropping-particle"]),
944+
self:_format_a_name(namepartOptions.family, entry.family),
890945
}, " ")
891946
end
892-
return entry.family
947+
return self:_format_a_name(namepartOptions.family, entry.family)
893948
end
894949

895-
if nameAsSortOrder ~= "all" and not self.firstName then
950+
local nameAsSortOrder = options["name-as-sort-order"]
951+
local familyFirst = nameAsSortOrder == "all" or (nameAsSortOrder == "first" and self.firstName) or false
952+
if not familyFirst then
896953
-- Order is: [Given] [DP] [NDP] Family [Suffix] e.g. Vincent van Gogh III
897954
local t = {}
898955
if entry.given then
899-
table.insert(t, entry.given)
956+
table.insert(t, self:_format_a_name(namepartOptions.given, initialize(options, entry)))
900957
end
901958
if entry["dropping-particle"] then
902-
table.insert(t, entry["dropping-particle"])
959+
table.insert(t, self:_format_a_name(namepartOptions.given, entry["dropping-particle"]))
903960
end
904961
if entry["non-dropping-particle"] then
905-
table.insert(t, entry["non-dropping-particle"])
962+
table.insert(t, self:_format_a_name(namepartOptions.family, entry["non-dropping-particle"]))
906963
end
907-
table.insert(t, entry.family)
964+
table.insert(t, self:_format_a_name(namepartOptions.family, entry.family))
908965
if entry.suffix then
909966
table.insert(t, entry.suffix)
910967
end
@@ -916,41 +973,41 @@ function CslEngine:_a_name (options, content, entry)
916973
-- Order is: Family, [Given] [DP] [NDP], [Suffix] e.g. Gogh, Vincent van, III
917974
local mid = {}
918975
if entry.given then
919-
table.insert(mid, entry.given)
976+
table.insert(mid, self:_format_a_name(namepartOptions.given, initialize(options, entry)))
920977
end
921978
if entry["dropping-particle"] then
922-
table.insert(mid, entry["dropping-particle"])
979+
table.insert(mid, self:_format_a_name(namepartOptions.given, entry["dropping-particle"]))
923980
end
924981
if entry["non-dropping-particle"] then
925-
table.insert(mid, entry["non-dropping-particle"])
982+
table.insert(mid, self:_format_a_name(namepartOptions.family, entry["non-dropping-particle"]))
926983
end
927984
local midname = table.concat(mid, " ")
928985
if #midname > 0 then
929986
return table.concat({
930-
entry.family,
987+
self:_format_a_name(namepartOptions.family, entry.family),
931988
midname,
932989
entry.suffix, -- may be nil
933990
}, sep)
934991
end
935992
return table.concat({
936-
entry.family,
993+
self:_format_a_name(namepartOptions.family, entry.family),
937994
entry.suffix, -- may be nil
938995
}, sep)
939996
end
940997

941998
-- Order is: [NDP] Family, [Given] [DP], [Suffix] e.g. van Gogh, Vincent, III
942999
local beg = {}
9431000
if entry["non-dropping-particle"] then
944-
table.insert(beg, entry["non-dropping-particle"])
1001+
table.insert(beg, self:_format_a_name(namepartOptions.family, entry["non-dropping-particle"]))
9451002
end
946-
table.insert(beg, entry.family)
1003+
table.insert(beg, self:_format_a_name(namepartOptions.family, entry.family))
9471004
local begname = table.concat(beg, " ")
9481005
local mid = {}
9491006
if entry.given then
950-
table.insert(mid, entry.given)
1007+
table.insert(mid, self:_format_a_name(namepartOptions.given, initialize(options, entry)))
9511008
end
9521009
if entry["dropping-particle"] then
953-
table.insert(mid, entry["dropping-particle"])
1010+
table.insert(mid, self:_format_a_name(namepartOptions.given, entry["dropping-particle"]))
9541011
end
9551012
local midname = table.concat(mid, " ")
9561013
if #midname > 0 then
@@ -1068,7 +1125,11 @@ function CslEngine:_names_with_resolved_opts (options, substitute_node, entry)
10681125
sep_delim = #l > 2 and name_delimiter or " "
10691126
end
10701127
local last = table.remove(l)
1071-
joined = table.concat(l, name_delimiter) .. sep_delim .. and_word .. " " .. last
1128+
if and_word then
1129+
joined = table.concat(l, name_delimiter) .. sep_delim .. and_word .. " " .. last
1130+
else
1131+
joined = table.concat(l, name_delimiter) .. sep_delim .. last
1132+
end
10721133
end
10731134
if label then
10741135
joined = is_label_first and (label .. joined) or (joined .. label)
@@ -1120,8 +1181,13 @@ function CslEngine:_names (options, content, entry)
11201181
name_node.options.form = name_node.options.form or inherited_opts["name-form"]
11211182
local et_al_min = tonumber(name_node.options["et-al-min"]) or 4 -- No default in the spec, using Chicago's
11221183
local et_al_use_first = tonumber(name_node.options["et-al-use-first"]) or 1
1123-
local and_opt = name_node.options["and"] or "text"
1124-
local and_word = and_opt == "symbol" and "&" or self:_render_term("and") -- text by default
1184+
local and_opt = name_node.options["and"]
1185+
local and_word
1186+
if and_opt == "symbol"then
1187+
and_word = "&"
1188+
elseif and_opt == "text" then
1189+
and_word = self:_render_term("and")
1190+
end
11251191
local name_delimiter = name_node.options.delimiter or inherited_opts["names-delimiter"] or ", "
11261192
-- local delimiter_precedes_et_al = name_node.options["delimiter-precedes-et-al"] -- FIXME NOT IMPLEMENTED
11271193
local delimiter_precedes_last = name_node.options["delimiter-precedes-last"]

0 commit comments

Comments
 (0)