summaryrefslogtreecommitdiff
path: root/biblio/citation-style-language/citeproc-node-citation.lua
diff options
context:
space:
mode:
Diffstat (limited to 'biblio/citation-style-language/citeproc-node-citation.lua')
-rw-r--r--biblio/citation-style-language/citeproc-node-citation.lua171
1 files changed, 124 insertions, 47 deletions
diff --git a/biblio/citation-style-language/citeproc-node-citation.lua b/biblio/citation-style-language/citeproc-node-citation.lua
index 6c7f082746..aca01a7c93 100644
--- a/biblio/citation-style-language/citeproc-node-citation.lua
+++ b/biblio/citation-style-language/citeproc-node-citation.lua
@@ -1,6 +1,6 @@
--
--- Copyright (c) 2021-2022 Zeping Lee
+-- Copyright (c) 2021-2023 Zeping Lee
-- Released under the MIT license.
-- Repository: https://github.com/zepinglee/citeproc-lua
--
@@ -20,11 +20,13 @@ local Micro = require("citeproc-output").Micro
local Formatted = require("citeproc-output").Formatted
local PlainText = require("citeproc-output").PlainText
local InlineElement = require("citeproc-output").InlineElement
+local CiteInline = require("citeproc-output").CiteInline
local DisamStringFormat = require("citeproc-output").DisamStringFormat
local SortStringFormat = require("citeproc-output").SortStringFormat
local util = require("citeproc-util")
+---@class Citation: Element
local Citation = Element:derive("citation", {
givenname_disambiguation_rule = "by-cite",
-- https://github.com/citation-style-language/schema/issues/338
@@ -37,6 +39,8 @@ function Citation:from_node(node, style)
local o = self:new()
o.children = {}
+ o.layout = nil
+ o.layouts_by_language = {}
o:process_children_nodes(node)
@@ -45,7 +49,13 @@ function Citation:from_node(node, style)
for _, child in ipairs(o.children) do
local element_name = child.element_name
if element_name == "layout" then
- o.layout = child
+ if child.locale then
+ for _, lang in ipairs(util.split(util.strip(child.locale))) do
+ o.layouts_by_language[lang] = child
+ end
+ else
+ o.layout = child
+ end
elseif element_name == "sort" then
o.sort = child
end
@@ -121,6 +131,16 @@ local function remove_name_formatting(ir)
end
end
+---@class CitationItem
+---@field id string | number
+---@field prefix string?
+---@field suffix string?
+
+---comment
+---@param citation_items CitationItem[]
+---@param engine CiteProc
+---@param properties table
+---@return string
function Citation:build_cluster(citation_items, engine, properties)
properties = properties or {}
local output_format = engine.output_format
@@ -173,7 +193,6 @@ function Citation:build_cluster(citation_items, engine, properties)
-- util.debug(irs)
- local citation_delimiter = self.layout.delimiter
local citation_stream = {}
local context = Context:new()
@@ -190,9 +209,9 @@ function Citation:build_cluster(citation_items, engine, properties)
local cite_prefix = citation_items[i].prefix
local cite_suffix = citation_items[i].suffix
if not ir.collapse_suppressed then
- local ir_inlines = ir:flatten(output_format)
- if #ir_inlines > 0 then
- -- Make sure ir_inlines has outputs contents.
+ local cite_inlines = ir:flatten(output_format)
+ if #cite_inlines > 0 then
+ -- Make sure cite_inlines has outputs contents.
-- collapse_AuthorCollapseNoDateSorted.txt
if previous_ir then
if previous_ir.own_delimiter then
@@ -202,8 +221,8 @@ function Citation:build_cluster(citation_items, engine, properties)
if cite_prefix then
left_most_str = cite_prefix[1]:get_left_most_string()
end
- if citation_delimiter and not (cite_prefix and util.startswith(left_most_str, ",")) then
- table.insert(citation_stream, PlainText:new(citation_delimiter))
+ if previous_ir.cite_delimiter and not (cite_prefix and util.startswith(left_most_str, ",")) then
+ table.insert(citation_stream, PlainText:new(previous_ir.cite_delimiter))
end
end
end
@@ -212,8 +231,12 @@ function Citation:build_cluster(citation_items, engine, properties)
table.insert(citation_stream, Micro:new(cite_prefix))
end
- -- util.debug(ir)
- util.extend(citation_stream, ir_inlines)
+ -- util.debug(ir.cite_item.id)
+ -- util.debug(cite_inlines)
+ -- if context.engine.opt.citation_link then
+ cite_inlines = {CiteInline:new(cite_inlines, ir.cite_item)}
+ -- end
+ util.extend(citation_stream, cite_inlines)
previous_ir = ir
if cite_suffix then
@@ -223,6 +246,8 @@ function Citation:build_cluster(citation_items, engine, properties)
end
end
+ -- util.debug(citation_stream)
+
local has_printed_form = true
if #citation_items == 0 then
-- bugreports_AuthorOnlyFail.txt
@@ -232,19 +257,19 @@ function Citation:build_cluster(citation_items, engine, properties)
-- date_DateNoDateNoTest.txt
has_printed_form = false
citation_stream = {PlainText:new("[CSL STYLE ERROR: reference with no printed form.]")}
- elseif #citation_stream == 1 and citation_stream[1].value == "[NO_PRINTED_FORM]" then
+ elseif #citation_stream == 1 and citation_stream[1]._type == "CiteInline" and
+ #citation_stream[1].inlines == 1 and citation_stream[1].inlines[1].value == "[NO_PRINTED_FORM]" then
has_printed_form = false
end
local author_only_mode = (properties.mode == "author-only" or
(#citation_items >= 1 and citation_items[1]["author-only"]))
if has_printed_form and context.area.layout.affixes and not author_only_mode then
- local affixes = context.area.layout.affixes
- if affixes.prefix then
- table.insert(citation_stream, 1, PlainText:new(affixes.prefix))
+ if irs[1].cite_prefix then
+ table.insert(citation_stream, 1, PlainText:new(irs[1].cite_prefix))
end
- if affixes.suffix then
- table.insert(citation_stream, PlainText:new(affixes.suffix))
+ if irs[#irs].cite_suffix then
+ table.insert(citation_stream, PlainText:new(irs[#irs].cite_suffix))
end
end
@@ -314,24 +339,53 @@ function Citation:sorted_citation_items(items, engine)
return items
end
+
+---@class CiteIr: IrNode
+---@field cite_item CitationItem
+---@field reference table
+---@field ir_index any
+---@field is_ambiguous boolean
+---@field disam_level integer
+---@field cite_delimiter string?
+---@field cite_prefix string?
+---@field cite_suffix string?
+
+---@param cite_item CitationItem
+---@param output_format OutputFormat
+---@param engine CiteProc
+---@param properties table
+---@return CiteIr
function Citation:build_fully_disambiguated_ir(cite_item, output_format, engine, properties)
local cite_ir = self:build_ambiguous_ir(cite_item, output_format, engine)
-- util.debug(cite_ir)
+ -- if cite_item.id == "ITEM-3" then
+ -- util.debug(cite_item.id)
+ -- util.debug(cite_ir)
+ -- end
cite_ir = self:apply_disambiguate_add_givenname(cite_ir, engine)
cite_ir = self:apply_disambiguate_add_names(cite_ir, engine)
cite_ir = self:apply_disambiguate_conditionals(cite_ir, engine)
cite_ir = self:apply_disambiguate_add_year_suffix(cite_ir, engine)
+ -- if cite_item.id == "ITEM-3" then
+ -- util.debug(cite_item.id)
+ -- util.debug(cite_ir)
+ -- end
return cite_ir
end
+---comment
+---@param cite_item CitationItem
+---@param output_format OutputFormat
+---@param engine CiteProc
+---@return CiteIr
function Citation:build_ambiguous_ir(cite_item, output_format, engine)
local state = IrState:new(engine.style)
local context = Context:new()
context.engine = engine
context.style = engine.style
context.area = self
- context.locale = engine:get_locale(engine.lang)
+ -- context.locale = engine:get_locale(engine.lang)
context.name_inheritance = self.name_inheritance
context.format = output_format
context.id = cite_item.id
@@ -339,9 +393,12 @@ function Citation:build_ambiguous_ir(cite_item, output_format, engine)
-- context.reference = self:get_item(cite_item.id)
context.reference = engine.registry.registry[cite_item.id]
+ local active_layout, context_lang = util.get_layout_by_language(self, engine, context.reference)
+ context.locale = engine:get_locale(context_lang)
+
local ir
if context.reference then
- ir = self:build_ir(engine, state, context)
+ ir = self:build_ir(engine, state, context, active_layout)
else
ir = Rendered:new({Formatted:new({PlainText:new(cite_item.id)}, {["font-weight"] = "bold"})}, self)
end
@@ -353,6 +410,12 @@ function Citation:build_ambiguous_ir(cite_item, output_format, engine)
ir.is_ambiguous = false
ir.disam_level = 0
+ ir.cite_delimiter = active_layout.delimiter
+ if active_layout.affixes then
+ ir.cite_prefix = active_layout.affixes.prefix
+ ir.cite_suffix = active_layout.affixes.suffix
+ end
+
-- Formattings like font-style are ignored for disambiguation.
local disam_format = DisamStringFormat:new()
local inlines = ir:flatten(disam_format)
@@ -374,11 +437,11 @@ function Citation:build_ambiguous_ir(cite_item, output_format, engine)
return ir
end
-function Citation:build_ir(engine, state, context)
- if not self.layout then
+function Citation:build_ir(engine, state, context, active_layout)
+ if not active_layout then
util.error("Missing citation layout.")
end
- return self.layout:build_ir(engine, state, context)
+ return active_layout:build_ir(engine, state, context)
end
function Citation:apply_disambiguate_add_givenname(cite_ir, engine)
@@ -875,14 +938,25 @@ function Citation:check_ambiguity(cite_ir, engine)
return false
end
-function Citation:get_same_output_irs(cite_ir, engine)
- local ambiguous_same_output_irs = {}
- for _, ir_ in pairs(engine.cite_irs_by_output[cite_ir.disam_str]) do
- if ir_.disam_str == cite_ir.disam_str then
- table.insert(ambiguous_same_output_irs, ir_)
+function Citation:get_ambiguous_cite_irs(cite_ir, engine)
+ local res = {}
+ for _, ir in pairs(engine.cite_irs_by_output[cite_ir.disam_str]) do
+ if ir.cite_item.id ~= cite_ir.cite_item.id then
+ table.insert(res, ir)
end
end
- return ambiguous_same_output_irs
+ return res
+end
+
+function Citation:get_ambiguous_same_output_cite_irs(cite_ir, engine)
+ -- This includes the cite_ir itself.
+ local res = {}
+ for _, ir in pairs(engine.cite_irs_by_output[cite_ir.disam_str]) do
+ if ir.disam_str == cite_ir.disam_str then
+ table.insert(res, ir)
+ end
+ end
+ return res
end
function Citation:apply_disambiguate_add_year_suffix(cite_ir, engine)
@@ -890,60 +964,63 @@ function Citation:apply_disambiguate_add_year_suffix(cite_ir, engine)
return cite_ir
end
- local same_output_irs = self:get_same_output_irs(cite_ir, engine)
+ local ambiguous_same_output_irs = self:get_ambiguous_same_output_cite_irs(cite_ir, engine)
- table.sort(same_output_irs, function (a, b)
+ table.sort(ambiguous_same_output_irs, function (a, b)
-- return a.ir_index < b.ir_index
return a.reference["citation-number"] < b.reference["citation-number"]
end)
- local year_suffix_number = 0
- -- util.debug(cite_ir)
-
local disam_format = DisamStringFormat:new()
- for _, ir_ in ipairs(same_output_irs) do
+ for _, ir_ in ipairs(ambiguous_same_output_irs) do
ir_.reference.year_suffix_number = nil
end
- for _, ir_ in ipairs(same_output_irs) do
- -- print(ir_.cite_item.id)
- -- print(ir_.reference)
+ -- TODO: clear year-suffix after updateItems
+ local year_suffix_number = 0
+ for _, ir_ in ipairs(ambiguous_same_output_irs) do
if not ir_.reference.year_suffix_number then
year_suffix_number = year_suffix_number + 1
ir_.reference.year_suffix_number = year_suffix_number
ir_.reference["year-suffix"] = self:render_year_suffix(year_suffix_number)
end
+ -- util.debug(string.format('%s: %s "%s"', ir_.cite_item.id, tostring(ir_.reference.year_suffix_number), ir_.reference["year-suffix"]))
if not ir_.year_suffix_irs then
ir_.year_suffix_irs = ir_:collect_year_suffix_irs()
if #ir_.year_suffix_irs == 0 then
- -- By default, the year-suffix is appended the first year rendered through cs:date
+ -- The style does not have a "year-suffix" variable.
+ -- Then the year-suffix is appended the first year rendered through cs:date
local year_ir = ir_:find_first_year_ir()
-- util.debug(year_ir)
if year_ir then
local year_suffix_ir = YearSuffix:new({}, self)
table.insert(year_ir.children, year_suffix_ir)
table.insert(ir_.year_suffix_irs, year_suffix_ir)
+ else
+ util.warning("No date variable for year-suffix")
end
end
end
+ -- Render all the year-suffix irs.
for _, year_suffix_ir in ipairs(ir_.year_suffix_irs) do
- year_suffix_ir.inlines = {PlainText:new(ir_.reference["year-suffix"])}
+ -- util.debug(ir_.reference["year-suffix"])
+ year_suffix_ir.inlines = { PlainText:new(ir_.reference["year-suffix"]) }
year_suffix_ir.year_suffix_number = ir_.reference.year_suffix_number
year_suffix_ir.group_var = "important"
end
- local inlines = ir_:flatten(disam_format)
- local disam_str = disam_format:output(inlines, nil)
- -- util.debug("update: " .. ir_.cite_item.id .. ": " .. disam_str)
- ir_.disam_str = disam_str
- if not engine.cite_irs_by_output[disam_str] then
- engine.cite_irs_by_output[disam_str] = {}
- end
- engine.cite_irs_by_output[disam_str][ir_.ir_index] = ir_
-
+ -- DisamStringFormat doesn't render YearSuffix and this can be skipped.
+ -- local inlines = ir_:flatten(disam_format)
+ -- local disam_str = disam_format:output(inlines, nil)
+ -- util.debug(string.format('update %s: "%s" to "%s"', ir_.cite_item.id, ir_.disam_str, disam_str))
+ -- ir_.disam_str = disam_str
+ -- if not engine.cite_irs_by_output[disam_str] then
+ -- engine.cite_irs_by_output[disam_str] = {}
+ -- end
+ -- engine.cite_irs_by_output[disam_str][ir_.ir_index] = ir_
end
cite_ir.is_ambiguous = false