summaryrefslogtreecommitdiff
path: root/biblio/citation-style-language/citeproc-node-text.lua
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2022-01-22 03:01:16 +0000
committerNorbert Preining <norbert@preining.info>2022-01-22 03:01:16 +0000
commit26bfc07f2b7829213356de43cf5b81c3ba99e338 (patch)
treeefb3037df2c42c45c904ad131334e8fc626cea19 /biblio/citation-style-language/citeproc-node-text.lua
parent5d5f239204f5c0d1f7573c9ebc64b5ad1ae75b49 (diff)
CTAN sync 202201220301
Diffstat (limited to 'biblio/citation-style-language/citeproc-node-text.lua')
-rw-r--r--biblio/citation-style-language/citeproc-node-text.lua217
1 files changed, 217 insertions, 0 deletions
diff --git a/biblio/citation-style-language/citeproc-node-text.lua b/biblio/citation-style-language/citeproc-node-text.lua
new file mode 100644
index 0000000000..55dd13e295
--- /dev/null
+++ b/biblio/citation-style-language/citeproc-node-text.lua
@@ -0,0 +1,217 @@
+local text = {}
+
+local element = require("citeproc-element")
+local richtext = require("citeproc-richtext")
+local util = require("citeproc-util")
+
+
+local Text = element.Element:new()
+
+function Text:render (item, context)
+ self:debug_info(context)
+ context = self:process_context(context)
+
+ local res = nil
+
+ local variable = nil
+ local variable_name = self:get_attribute("variable")
+ if variable_name then
+ local form = self:get_attribute("form")
+ if form == "short" then
+ variable = self:get_variable(item, variable_name .. "-" .. form, context)
+ end
+ if not variable then
+ variable = self:get_variable(item, variable_name, context)
+ end
+ if variable then
+ res = variable
+ if type(res) == "number" then
+ res = tostring(res)
+ end
+ if variable_name == "page" or variable_name == "locator" then
+ res = util.lstrip(res)
+ res = self:_format_page(res, context)
+ end
+ end
+
+ table.insert(context.variable_attempt, res ~= nil)
+ end
+
+ local macro_name = self:get_attribute("macro")
+ if macro_name then
+ local macro = self:get_macro(macro_name)
+ res = macro:render(item, context)
+ end
+
+ local term_name = self:get_attribute("term")
+ if term_name then
+ local form = self:get_attribute("form")
+
+ local term = self:get_term(term_name, form)
+ if term then
+ res = term:render(context)
+ end
+ end
+
+ local value = self:get_attribute("value")
+ if value then
+ res = value
+ res = self:escape(res)
+ end
+
+ if type(res) == "string" and res ~= "" then
+ res = richtext.new(res)
+ end
+
+ res = self:strip_periods(res, context)
+ res = self:case(res, context)
+ res = self:format(res, context)
+ res = self:quote(res, context)
+ res = self:wrap(res, context)
+ res = self:display(res, context)
+
+ if variable_name == "citation-number" then
+ res = self:_process_citation_number(variable, res, context)
+ end
+
+ return res
+end
+
+
+function Text:_process_citation_number(citation_number, res, context)
+ if context.mode == "citation" and not context.sorting and context.options["collapse"] == "citation-number" then
+ context.build.item_citation_numbers[context.item.id] = citation_number
+ if type(res) == "string" then
+ res = richtext.new(res)
+ end
+ table.insert(context.build.item_citation_number_text, res)
+ end
+ return res
+end
+
+
+function Text:_format_page (page, context)
+ local res = nil
+
+ local page_range_delimiter = self:get_term("page-range-delimiter"):render(context) or util.unicode["en dash"]
+ local page_range_format = context.options["page-range-format"]
+ if page_range_format == "chicago" then
+ if self:get_style():get_version() >= "1.1" then
+ page_range_format = "chicago-16"
+ else
+ page_range_format = "chicago-15"
+ end
+ end
+
+ local last_position = 1
+ local page_parts = {}
+ local punct_list = {}
+ for part, punct, pos in string.gmatch(page, "(.-)%s*([,&])%s*()") do
+ table.insert(page_parts, part)
+ table.insert(punct_list, punct)
+ last_position = pos
+ end
+ table.insert(page_parts, string.sub(page, last_position))
+
+ res = ""
+ for i, part in ipairs(page_parts) do
+ res = res .. self:_format_range(part, page_range_format, page_range_delimiter)
+ local punct = punct_list[i]
+ if punct then
+ if punct == "&" then
+ res = res .. " " .. punct .. " "
+ else
+ res = res .. punct .. " "
+ end
+ end
+ end
+ res = self:escape(res)
+ return res
+end
+
+function Text:_format_range (str, format, range_delimiter)
+ local start, delimiter, stop = string.match(str, "(%w+)%s*(%-+)%s*(%S*)")
+ if not stop or stop == "" then
+ return string.gsub(str, "\\%-", "-")
+ end
+
+
+ local start_prefix, start_num = string.match(start, "(.-)(%d*)$")
+ local stop_prefix, stop_num = string.match(stop, "(.-)(%d*)$")
+
+ if start_prefix ~= stop_prefix then
+ -- Not valid range: "n11564-1568" -> "n11564-1568"
+ -- 110-N6
+ -- N110-P5
+ return start .. delimiter .. stop
+ end
+
+ if format == "chicago-16" then
+ stop = self:_format_range_chicago_16(start_num, stop_num)
+ elseif format == "chicago-15" then
+ stop = self:_format_range_chicago_15(start_num, stop_num)
+ elseif format == "expanded" then
+ stop = stop_prefix .. self:_format_range_expanded(start_num, stop_num)
+ elseif format == "minimal" then
+ stop = self:_format_range_minimal(start_num, stop_num)
+ elseif format == "minimal-two" then
+ stop = self:_format_range_minimal(start_num, stop_num, 2)
+ end
+
+ return start .. range_delimiter .. stop
+end
+
+function Text:_format_range_chicago_16(start, stop)
+ if #start < 3 or string.sub(start, -2) == "00" then
+ return self:_format_range_expanded(start, stop)
+ elseif string.sub(start, -2, -2) == "0" then
+ return self:_format_range_minimal(start, stop)
+ else
+ return self:_format_range_minimal(start, stop, 2)
+ end
+ return stop
+end
+
+function Text:_format_range_chicago_15(start, stop)
+ if #start < 3 or string.sub(start, -2) == "00" then
+ return self:_format_range_expanded(start, stop)
+ else
+ local changed_digits = self:_format_range_minimal(start, stop)
+ if string.sub(start, -2, -2) == "0" then
+ return changed_digits
+ elseif #start == 4 and #changed_digits == 3 then
+ return self:_format_range_expanded(start, stop)
+ else
+ return self:_format_range_minimal(start, stop, 2)
+ end
+ end
+ return stop
+end
+
+function Text:_format_range_expanded(start, stop)
+ -- Expand "1234–56" -> "1234–1256"
+ if #start <= #stop then
+ return stop
+ end
+ return string.sub(start, 1, #start - #stop) .. stop
+end
+
+function Text:_format_range_minimal(start, stop, threshold)
+ threshold = threshold or 1
+ if #start < #stop then
+ return stop
+ end
+ local offset = #start - #stop
+ for i = 1, #stop - threshold do
+ local j = i + offset
+ if string.sub(stop, i, i) ~= string.sub(start, j, j) then
+ return string.sub(stop, i)
+ end
+ end
+ return string.sub(stop, -threshold)
+end
+
+
+text.Text = Text
+
+return text