diff --git a/csl/core/engine.lua b/csl/core/engine.lua index 2a76e71fa..e78bd6fcc 100644 --- a/csl/core/engine.lua +++ b/csl/core/engine.lua @@ -748,28 +748,101 @@ function CslEngine:_name_et_al (options) end function CslEngine:_a_name (options, content, entry) - local form = options.form - local nameAsSortOrder = options["name-as-sort-order"] + if not entry.family then + -- There's one element in a name we can't do without. + SU.error("Name without family: what do you expect me to do with it?") + end + local demoteNonDroppingParticle = options["demote-non-dropping-particle"] or "never" + if self.sorting then - -- Ovveride form and name-as-sort-order in sorting mode - form = "long" - nameAsSortOrder = "all" + -- Implicitely we are in long form, name-as-sort-order all, and no formatting. + if demoteNonDroppingParticle == "never" then + -- Order is: [NDP] Family [Given] [Suffix] e.g. van Gogh Vincent III + local name = {} + if entry["non-dropping-particle"] then table.insert(name, entry["non-dropping-particle"]) end + table.insert(name, entry.family) + if entry.given then table.insert(name, entry.given) end + if entry.suffix then table.insert(name, entry.suffix) end + return table.concat(name, " ") + end + -- Order is: Family [Given] [DP] [Suffix] e.g. Gogh Vincent van III + local name = { entry.family } + if entry.given then table.insert(name, entry.given) end + if entry["dropping-particle"] then table.insert(name, entry["dropping-particle"]) end + if entry["non-dropping-particle"] then table.insert(name, entry["non-dropping-particle"]) end + if entry.suffix then table.insert(name, entry.suffix) end + return table.concat(name, " ") end + local form = options.form + local nameAsSortOrder = options["name-as-sort-order"] or "first" + -- TODO FIXME: content can consists in name-part elements for formatting, text-case, affixes - -- Chigaco style does not seem to use them, so we keep it simple for now. - -- TODO FIXME: demote-non-dropping-particle option not implemented, and name particle not implemented at all! + -- Chigaco style does not seem to use them, so we keep it "simple" for now. if form == "short" then + -- Order is: [NDP] Family, e.g. van Gogh + if entry["non-dropping-particle"] then + return table.concat({ + entry["non-dropping-particle"], + entry.family + }, " ") + end return entry.family end + if nameAsSortOrder ~= "all" and not self.firstName then - -- Order is: Given Family - return entry.given and (entry.given .. " " .. entry.family) or entry.family + -- Order is: [Given] [DP] [NDP] Family [Suffix] e.g. Vincent van Gogh III + local t = {} + if entry.given then table.insert(t, entry.given) end + if entry["dropping-particle"] then table.insert(t, entry["dropping-particle"]) end + if entry["non-dropping-particle"] then table.insert(t, entry["non-dropping-particle"]) end + table.insert(t, entry.family) + if entry.suffix then table.insert(t, entry.suffix) end + return table.concat(t, " ") end - -- Order is: Family, Given + local sep = options["sort-separator"] or (self.punctuation[","] .. " ") - return entry.given and (entry.family .. sep .. entry.given) or entry.family + if demoteNonDroppingParticle == "display-and-sort" then + -- Order is: Family, [Given] [DP] [NDP], [Suffix] e.g. Gogh, Vincent van, III + local mid = {} + if entry.given then table.insert(mid, entry.given) end + if entry["dropping-particle"] then table.insert(mid, entry["dropping-particle"]) end + if entry["non-dropping-particle"] then table.insert(mid, entry["non-dropping-particle"]) end + local midname = table.concat(mid, " ") + if #midname > 0 then + return table.concat({ + entry.family, + midname, + entry.suffix -- may be nil + }, sep) + end + return table.concat({ + entry.family, + entry.suffix -- may be nil + }, sep) + end + + -- Order is: [NDP] Family, [Given] [DP], [Suffix] e.g. van Gogh, Vincent, III + local beg = {} + if entry["non-dropping-particle"] then table.insert(beg, entry["non-dropping-particle"]) end + table.insert(beg, entry.family) + local begname = table.concat(beg, " ") + local mid = {} + if entry.given then table.insert(mid, entry.given) end + if entry["dropping-particle"] then table.insert(mid, entry["dropping-particle"]) end + local midname = table.concat(mid, " ") + if #midname > 0 then + return table.concat({ + begname, + midname, + entry.suffix -- may be nil + }, sep) + end + return table.concat({ + begname, + entry.suffix -- may be nil + }, sep) end local function hasField (list, field) @@ -840,8 +913,12 @@ function CslEngine:_names_with_resolved_opts (options, substitute_node, entry) elseif #l == 1 then joined = l[1] else + -- TODO THINGS TO SUPPORT THAT MIGHT REQUIRE A REFACTOR + -- They are needed in Chicago style, but let's keep it simple for now. + -- delimiter-precedes-last ("contextual" by default) + -- Chicago has "always", let's hard-code it for now. local last = table.remove(l) - joined = table.concat(l, name_delimiter) .. " " .. and_word .. " " .. last + joined = table.concat(l, name_delimiter) .. name_delimiter .. and_word .. " " .. last end if label then joined = is_label_first and (label .. joined) or (joined .. label) @@ -895,7 +972,7 @@ function CslEngine:_names (options, content, entry) local et_al_use_first = tonumber(name_node.options["et-al-use-first"]) or 1 local and_opt = name_node.options["and"] or "text" local and_word = and_opt == "symbol" and "&" or self:_render_term("and") -- text by default - local name_delimiter = name_node.options.delimiter or inherited_opts["names-delimiter"] + local name_delimiter = name_node.options.delimiter or inherited_opts["names-delimiter"] or ", " -- local delimiter_precedes_et_al = name_node.options["delimiter-precedes-et-al"] -- TODO NOT IMPLEMENTED if name_delimiter and not self.cache[name_delimiter] then diff --git a/packages/bibtex/support/nbibtex.lua b/packages/bibtex/support/nbibtex.lua index ad00a67eb..e4a7642f3 100644 --- a/packages/bibtex/support/nbibtex.lua +++ b/packages/bibtex/support/nbibtex.lua @@ -1,6 +1,9 @@ -- The following functions borrowed from Norman Ramsey's nbibtex, -- with permission. -- Thanks, Norman, for these functions! +-- NOTE: Modified in 2024 for CSL compatibility: +-- - nbsp instead of "~" for non-breaking space +-- - added CSL compatibility fields (given, non-dropping-particle, family, suffix) -- The initial implementation was using "~", but we now sanitized the -- input earlier at parsing to replace those from the input with @@ -266,11 +269,21 @@ do end end set_name(first_start, first_lim, "ff", "f") - set_name(first_start, first_lim, "given", "f") -- HACK OMIKHLEIA FIXME + set_name(first_start, first_lim, "given", "given-short") -- CSL compatibility + set_name(von_start, von_lim, "vv", "v") + -- BibLaTex doesn't distinguish between dropping-particle and non-dropping-particle... + -- So we assume it is non-dropping-particle. + -- Note: citeproc-lua assumes a non-dropping-particle too, without comment (checking its code) + -- I'd like to be more convinced, or the BibLaTeX folks to evolve towards something more + -- explicit. We are in 2024, folks, there has been time to think about it... + set_name(von_start, von_lim, "non-dropping-particle", "non-dropping-particle-short") -- CSL compatibility + set_name(von_lim, last_lim, "ll", "l") - set_name(von_lim, last_lim, "family", "l") -- HACK OMIKHLEIA FIXME + set_name(von_lim, last_lim, "family", "family-short") -- CSL compatibility + set_name(last_lim, jr_lim, "jj", "j") + set_name(last_lim, jr_lim, "suffix", "suffix-short") -- CSL compatibility return name end end