texlive[71944] Master/texmf-dist: citation-style-language (1aug24)
commits+karl at tug.org
commits+karl at tug.org
Thu Aug 1 21:56:55 CEST 2024
Revision: 71944
https://tug.org/svn/texlive?view=revision&revision=71944
Author: karl
Date: 2024-08-01 21:56:55 +0200 (Thu, 01 Aug 2024)
Log Message:
-----------
citation-style-language (1aug24)
Modified Paths:
--------------
trunk/Master/texmf-dist/doc/latex/citation-style-language/CHANGELOG.md
trunk/Master/texmf-dist/doc/latex/citation-style-language/citation-style-language-doc.pdf
trunk/Master/texmf-dist/doc/latex/citation-style-language/citation-style-language-doc.tex
trunk/Master/texmf-dist/doc/man/man1/citeproc-lua.1
trunk/Master/texmf-dist/doc/man/man1/citeproc-lua.man1.pdf
trunk/Master/texmf-dist/scripts/citation-style-language/citeproc-bibtex-parser.lua
trunk/Master/texmf-dist/scripts/citation-style-language/citeproc-bibtex2csl.lua
trunk/Master/texmf-dist/scripts/citation-style-language/citeproc-cli.lua
trunk/Master/texmf-dist/scripts/citation-style-language/citeproc-context.lua
trunk/Master/texmf-dist/scripts/citation-style-language/citeproc-element.lua
trunk/Master/texmf-dist/scripts/citation-style-language/citeproc-engine.lua
trunk/Master/texmf-dist/scripts/citation-style-language/citeproc-latex-parser.lua
trunk/Master/texmf-dist/scripts/citation-style-language/citeproc-node-choose.lua
trunk/Master/texmf-dist/scripts/citation-style-language/citeproc-node-citation.lua
trunk/Master/texmf-dist/scripts/citation-style-language/citeproc-node-names.lua
trunk/Master/texmf-dist/scripts/citation-style-language/citeproc-node-number.lua
trunk/Master/texmf-dist/scripts/citation-style-language/citeproc-node-sort.lua
trunk/Master/texmf-dist/scripts/citation-style-language/citeproc-node-text.lua
trunk/Master/texmf-dist/scripts/citation-style-language/citeproc-output.lua
trunk/Master/texmf-dist/scripts/citation-style-language/citeproc-util.lua
trunk/Master/texmf-dist/scripts/citation-style-language/citeproc.lua
trunk/Master/texmf-dist/tex/latex/citation-style-language/citation-style-language-bib.sty
trunk/Master/texmf-dist/tex/latex/citation-style-language/citation-style-language-cite.sty
trunk/Master/texmf-dist/tex/latex/citation-style-language/citation-style-language-compatible.sty
trunk/Master/texmf-dist/tex/latex/citation-style-language/citation-style-language-init.sty
trunk/Master/texmf-dist/tex/latex/citation-style-language/citation-style-language.sty
trunk/Master/texmf-dist/tex/latex/citation-style-language/styles/apa.csl
trunk/Master/texmf-dist/tex/latex/citation-style-language/styles/ieee.csl
Added Paths:
-----------
trunk/Master/texmf-dist/scripts/citation-style-language/citeproc-manager.lua
Removed Paths:
-------------
trunk/Master/texmf-dist/scripts/citation-style-language/citeproc-latex-core.lua
trunk/Master/texmf-dist/scripts/citation-style-language/citeproc-latex.lua
Modified: trunk/Master/texmf-dist/doc/latex/citation-style-language/CHANGELOG.md
===================================================================
--- trunk/Master/texmf-dist/doc/latex/citation-style-language/CHANGELOG.md 2024-07-31 23:41:56 UTC (rev 71943)
+++ trunk/Master/texmf-dist/doc/latex/citation-style-language/CHANGELOG.md 2024-08-01 19:56:55 UTC (rev 71944)
@@ -7,6 +7,21 @@
## [Unreleased]
+## [0.6.0] - 2024-07-31
+
+- Add support for multiple bibliographies (`refsection` environment).
+- Add global `ref-section` option.
+
+### Fixed
+
+- Fix an error of empty locator in citation (([#70](https://github.com/zepinglee/citeproc-lua/discussions/70)))
+
+## [0.5.1] - 2024-07-10
+
+### Fixed
+
+- Fix a bug in font style flip-flopping with raw code ([#67](https://github.com/zepinglee/citeproc-lua/issues/67)).
+
## [0.5.0] - 2024-06-09
### Added
@@ -197,7 +212,9 @@
- Initial CTAN release.
-[Unreleased]: https://github.com/zepinglee/citeproc-lua/compare/v0.5.0...HEAD
+[Unreleased]: https://github.com/zepinglee/citeproc-lua/compare/v0.6.0...HEAD
+[0.6.0]: https://github.com/zepinglee/citeproc-lua/compare/v0.5.1...v0.6.0
+[0.5.1]: https://github.com/zepinglee/citeproc-lua/compare/v0.5.0...v0.5.1
[0.5.0]: https://github.com/zepinglee/citeproc-lua/compare/v0.4.9...v0.5.0
[0.4.9]: https://github.com/zepinglee/citeproc-lua/compare/v0.4.8...v0.4.9
[0.4.8]: https://github.com/zepinglee/citeproc-lua/compare/v0.4.7...v0.4.8
Modified: trunk/Master/texmf-dist/doc/latex/citation-style-language/citation-style-language-doc.pdf
===================================================================
(Binary files differ)
Modified: trunk/Master/texmf-dist/doc/latex/citation-style-language/citation-style-language-doc.tex
===================================================================
--- trunk/Master/texmf-dist/doc/latex/citation-style-language/citation-style-language-doc.tex 2024-07-31 23:41:56 UTC (rev 71943)
+++ trunk/Master/texmf-dist/doc/latex/citation-style-language/citation-style-language-doc.tex 2024-08-01 19:56:55 UTC (rev 71944)
@@ -51,7 +51,7 @@
}%
}
-\date{2024-06-09 v0.5.0}
+\date{2024-07-31 v0.6.0}
\maketitle
@@ -212,6 +212,24 @@
When \pkg{babel} package is loaded, the selected main language is implicitly set
as the \opt{locale} for \pkg{citation-style-language}.
+\DescribeOption{ref-section}
+This option automatically starts a new reference section at the given document
+heading such as a chapter or a section. This is equivalent to the
+\cs{newrefsection} command. The following choices are available:
+
+\begin{description}
+ \item[\opt{none}] Disable this feature (default).
+ \item[\opt{part}] Start a reference section at every \cs{part} command.
+ \item[\opt{chapter}] Start a reference section at every \cs{chapter} command.
+ \item[\opt{chapter+}] Start a reference section at every \cs{chapter} and
+ every higher level of sectioning, i.e. \cs{part}.
+ \item[\opt{section}] Start a reference section at every \cs{section} command.
+ \item[\opt{section+}] Start a reference section at every \cs{section} and
+ every higher level of sectioning, i.e. \cs{part} and \cs{chapter}.
+ \item[\opt{subsection}] Start a reference section at every \cs{subsection} command.
+ \item[\opt{subsection+}] Start a reference section at every \cs{subsection} and every higher level of sectioning, i.e. \cs{part}, \cs{chapter} and \cs{section}.
+\end{description}
+
\DescribeOption{bib-font}
Usually, the list of references is printed in the same font style and size as
the main text.
@@ -509,6 +527,68 @@
This option may be used multiple times.
+\subsection{Bibliography Sections}
+
+The \env{refsection} environment is used in the document body to mark a
+reference section.
+This environment is useful if you want separate, independent
+bibliographies and bibliography lists in each chapter, section, or any other
+part of a document.
+Within a reference section, all cited works are assigned labels which are local
+to the environment. Technically, reference sections are completely independent
+from document divisions such as \cs{chapter} and \cs{section} even though they
+will most likely be used per chapter or section.
+See the refsection package option in § 3.1.2.1 for a way to automate this.
+Also see § 3.14.3 for usage examples.
+
+\begin{function}{\begin{refsection}, \end{refsection}}
+ \begin{syntax}
+ \cs{begin}\{refsection\}
+ \cs{begin}\{refsection\}[style = \meta{style-id}, bib-resource = <datafile>, ...]
+ \end{syntax}
+\end{function}
+
+All citations given outside a \env{refsection} environment are assigned to
+the global section.
+If \cs{printbibliography} is used within a refsection, it will automatically
+select the current section.
+Note that \env{refsection} environments may not be nested.
+Beginning a new reference section automatically ends the active reference context (see § 3.8.10).
+The optional argument is a list of key-value configurations. That following options are available.
+
+
+\DescribeOption{style}
+The \opt{style} option specifies the CSL style used in this reference section.
+If this is not given, the global style will be used by default which is defined
+via package options or \cs{cslsetup}.
+
+\DescribeOption{bib-resource}
+The bibliographic data files are specified with this option.
+In case of multiple data files, remember to enclose the file with curly brackets
+so that the key-values are correctly parsed
+(e.g., \texttt{bib-resource = \{foo.json, bar.bib\}}).
+By default the global bib resources are used if no \opt{bib-resource} is given.
+
+\DescribeOption{locale}
+This option sets the locale used in this reference section.
+By default the global locale is used.
+
+
+\begin{function}{\newrefsection, \endrefsection}
+ \begin{syntax}
+ \cs{newrefsection}[style = \meta{style-id}, bib-resource = <datafile>, ...]
+ \cs{endrefsection}
+ \end{syntax}
+\end{function}
+
+The \cs{newrefsection} command is similar to the \env{refsection} environment
+except that it is a standalone command rather than an environment.
+It automatically ends the previous reference section (if any) and immediately
+starts a new one.
+The \cs{endrefsection} can terminate the current reference section and restore
+to the global section.
+
+
\subsection{Bibliography Headings}
\begin{function}{\defbibheading}
Modified: trunk/Master/texmf-dist/doc/man/man1/citeproc-lua.1
===================================================================
--- trunk/Master/texmf-dist/doc/man/man1/citeproc-lua.1 2024-07-31 23:41:56 UTC (rev 71943)
+++ trunk/Master/texmf-dist/doc/man/man1/citeproc-lua.1 2024-08-01 19:56:55 UTC (rev 71944)
@@ -1,4 +1,4 @@
-.TH citeproc-lua 1 "0.5.0"
+.TH citeproc-lua 1 "0.6.0"
.SH NAME
citeproc-lua \- make CSL citations and bibliography for LaTeX
.SH SYNOPSIS
Modified: trunk/Master/texmf-dist/doc/man/man1/citeproc-lua.man1.pdf
===================================================================
(Binary files differ)
Modified: trunk/Master/texmf-dist/scripts/citation-style-language/citeproc-bibtex-parser.lua
===================================================================
--- trunk/Master/texmf-dist/scripts/citation-style-language/citeproc-bibtex-parser.lua 2024-07-31 23:41:56 UTC (rev 71943)
+++ trunk/Master/texmf-dist/scripts/citation-style-language/citeproc-bibtex-parser.lua 2024-08-01 19:56:55 UTC (rev 71944)
@@ -117,7 +117,7 @@
if piece_str then
value = value .. piece_str
else
- util.warning(string.format('String name "%s" is undefined."', piece.name))
+ util.warning(string.format("String name '%s' is undefined.", piece.name))
end
end
end
@@ -311,7 +311,7 @@
function bibtex_parser.split_name_parts(str)
str = util.strip(str)
if string.match(str, ",$") then
- util.warning(string.format('Name "%s" has has a comma at the end.', str))
+ util.warning(string.format("Name '%s' has has a comma at the end.", str))
str = string.gsub(str, ",$", '')
end
@@ -339,7 +339,7 @@
elseif #parts == 3 then
name = bibtex_parser._split_last_jr_first_parts(parts)
elseif #parts > 3 then
- util.error(string.format('Too many commas in name "%s"', str))
+ util.error(string.format("Too many commas in name '%s'", str))
name = bibtex_parser._split_last_jr_first_parts(util.slice(parts, 1, 3))
end
@@ -407,7 +407,7 @@
key, value = string.match(part, '^"([a-zA-Z]+%-?i?)%s*=%s*(.-)%s*"%s*$')
end
if not key then
- util.error(string.format('Invalid extended name part "%s"', part))
+ util.error(string.format("Invalid extended name part '%s'", part))
end
if key == "given" then
Modified: trunk/Master/texmf-dist/scripts/citation-style-language/citeproc-bibtex2csl.lua
===================================================================
--- trunk/Master/texmf-dist/scripts/citation-style-language/citeproc-bibtex2csl.lua 2024-07-31 23:41:56 UTC (rev 71943)
+++ trunk/Master/texmf-dist/scripts/citation-style-language/citeproc-bibtex2csl.lua 2024-08-01 19:56:55 UTC (rev 71944)
@@ -374,6 +374,9 @@
function bibtex2csl._parse_edtf_date(str)
local date_range = util.split(str, "/")
+ if str == "" then
+ return nil
+ end
if #date_range == 1 then
date_range = util.split(str, util.unicode["en dash"])
end
Modified: trunk/Master/texmf-dist/scripts/citation-style-language/citeproc-cli.lua
===================================================================
--- trunk/Master/texmf-dist/scripts/citation-style-language/citeproc-cli.lua 2024-07-31 23:41:56 UTC (rev 71943)
+++ trunk/Master/texmf-dist/scripts/citation-style-language/citeproc-cli.lua 2024-08-01 19:56:55 UTC (rev 71944)
@@ -11,10 +11,10 @@
local lpeg = require("lpeg")
require("lualibs")
+local citeproc_manager = require("citeproc-manager")
local citeproc = require("citeproc")
local bibtex2csl -- = require("citeproc-bibtex-parser") -- load on demand
local util = require("citeproc-util")
-local core = require("citeproc-latex-core")
local latex_parser = require("citeproc-latex-parser")
@@ -82,116 +82,6 @@
end
-local balanced = lpeg.P{ "{" * lpeg.V(1)^0 * "}" + (1 - lpeg.S"{}") }
-
-
---- at param text string
---- at return string?
-local function get_command_argument(text, command)
- if string.match(text, command) then
- local grammar = (lpeg.P(command) * lpeg.S(" \t\r\n")^0 * lpeg.C(balanced) + 1)^0
- local argument = grammar:match(text)
- if not argument then
- return nil
- end
- argument = string.sub(argument, 2, -2)
- return argument
- end
- return nil
-end
-
-
-
----comment
---- at param aux_file any
---- at return string
---- at return string[]
---- at return Citation[]
---- at return table<string, string>
---- at return string[]
-local function read_aux_file(aux_file)
- local csl_style = nil
- local csl_data_files = {}
- local csl_citations = {}
- local csl_options = {}
- local csl_bibliographies = {}
-
- local file = io.open(aux_file)
- if not file then
- util.error(string.format("Couldn't open file %s", aux_file))
- return csl_style, csl_data_files, csl_citations, csl_options, csl_bibliographies
- end
- for line in file:lines() do
- -- TODO: Use lpeg-based method and detect multiple lines
- local style = get_command_argument(line, "\\csl at aux@style")
- if style then
- csl_style = style
- else
- local data = get_command_argument(line, "\\csl at aux@data")
- if data then
- for _, bib_file in ipairs(latex_parser.parse_seq(data)) do
- table.insert(csl_data_files, bib_file)
- end
- else
- local cite = get_command_argument(line, "\\csl at aux@cite")
- if cite then
- local citation = core.make_citation(cite)
- table.insert(csl_citations, citation)
- else
- local options = get_command_argument(line, "\\csl at aux@options")
- if options then
- options = latex_parser.parse_prop(options)
- for key, value in pairs(options) do
- csl_options[key] = value
- end
- else
- local bib = get_command_argument(line, "\\csl at aux@bibliography")
- if bib then
- table.insert(csl_bibliographies, bib)
- else
- local sub_aux_file = get_command_argument(line, "\\@input")
- if sub_aux_file and util.endswith(sub_aux_file, ".aux") then
- local style_name, data_files, citations, opts, bibs = read_aux_file(sub_aux_file)
- if style_name then
- csl_style = style_name
- end
- util.extend(csl_data_files, data_files)
- util.extend(csl_citations, citations)
- util.extend(csl_citations, citations)
- for key, value in pairs(opts) do
- csl_options[key] = value
- end
- util.extend(csl_bibliographies, bibs)
- end
- end
- end
- end
- end
- end
- end
- file:close()
-
- return csl_style, csl_data_files, csl_citations, csl_options, csl_bibliographies
-end
-
-
-local function get_undefined_info(core, citation)
- local res = ""
- for _, cite_item in ipairs(citation.citationItems) do
- if not core.item_dict[cite_item.id] then
- if res ~= "" then
- res = res .. ","
- end
- res = res .. cite_item.id
- end
- end
- if res ~= "" then
- res = string.format("\\cslsetup{undefined-cites={%s}}", res)
- end
- return res
-end
-
-
--- at param aux_file string
local function process_aux_file(aux_file)
if not util.endswith(aux_file, ".aux") then
@@ -204,73 +94,17 @@
util.info(banner)
util.info(string.format("The top-level auxiliary file: %s", aux_file))
- local style_name, bib_files, citations, csl_options, bibliographies = read_aux_file(aux_file)
+ local csl_citation_manager = citeproc_manager.CslCitationManager:new()
- if style_name and style_name ~= "" then
- util.info(string.format("The style file: %s.csl", style_name))
- else
- util.warning("Missing style name. Will use default APA style.")
- style_name = "apa"
+ local aux_content = util.read_file(aux_file)
+ if not aux_content then
+ return
end
- if #citations == 0 then
- util.error(string.format("No citation commands in file %s", aux_file))
- end
+ local bbl_str = csl_citation_manager:read_aux_file(aux_content)
- if #bib_files == 0 then
- util.warning("empty bibliography data files")
- else
- for i, bib_file in ipairs(bib_files) do
- util.info(string.format("Database file #%d: %s", i, bib_file))
- end
- end
-
- local lang = csl_options.locale
-
- local engine = core.init(style_name, bib_files, lang)
- if not engine then
- error("citeproc-lua: fails in initialize engine")
- end
- if csl_options.linking then
- engine:enable_linking()
- end
- local style_class = engine:get_style_class()
-
- if style_class == "in-text" then
- for _, citation in ipairs(citations) do
- citation.properties.noteIndex = 0
- end
- end
-
- local citation_strings = core.process_citations(engine, citations)
-
- -- util.debug(citation_strings)
-
- local output_string = string.format("\\cslsetup{class = %s}\n\n", style_class)
-
- for _, citation in ipairs(citations) do
- local citation_id = citation.citationID
- if citation_id ~= "@nocite" then
- local citation_str = citation_strings[citation_id]
- local undefined_entry_info = get_undefined_info(core, citation)
- output_string = output_string .. string.format("\\cslcitation{%s}{%s%s}\n",
- citation_id, undefined_entry_info, citation_str)
- end
- end
-
- output_string = output_string .. "\n"
- local categories_str = csl_options["categories"]
- if categories_str then
- core.set_categories(engine, categories_str)
- end
-
- for _, bib_filter_str in ipairs(bibliographies) do
- local result = core.make_bibliography(engine, bib_filter_str)
- output_string = output_string .. "\n\n\n" .. result
- end
-
local output_path = string.gsub(aux_file, "%.aux$", ".bbl")
- util.write_file(output_string, output_path)
+ util.write_file(bbl_str, output_path)
util.quiet_mode = false;
if util.num_errors > 1 then
Modified: trunk/Master/texmf-dist/scripts/citation-style-language/citeproc-context.lua
===================================================================
--- trunk/Master/texmf-dist/scripts/citation-style-language/citeproc-context.lua 2024-07-31 23:41:56 UTC (rev 71943)
+++ trunk/Master/texmf-dist/scripts/citation-style-language/citeproc-context.lua 2024-08-01 19:56:55 UTC (rev 71944)
@@ -297,7 +297,7 @@
function Context:get_macro(name)
local res = self.style.macros[name]
if not res then
- util.error(string.format('Undefined macro "%s"', name))
+ util.error(string.format("Undefined macro '%s'", name))
end
return res
end
@@ -363,7 +363,7 @@
function IrState:push_macro(macro_name)
for _, name in ipairs(macro_name) do
if name == macro_name then
- util.error(string.format('Recursive macro "%s".', macro_name))
+ util.error(string.format("Recursive macro '%s'.", macro_name))
end
table.insert(self.macro_stack, macro_name)
end
Modified: trunk/Master/texmf-dist/scripts/citation-style-language/citeproc-element.lua
===================================================================
--- trunk/Master/texmf-dist/scripts/citation-style-language/citeproc-element.lua 2024-07-31 23:41:56 UTC (rev 71943)
+++ trunk/Master/texmf-dist/scripts/citation-style-language/citeproc-element.lua 2024-08-01 19:56:55 UTC (rev 71944)
@@ -384,10 +384,20 @@
end
+--- at param number string Non-empty string
+--- at param variable string
+--- at param form string
+--- at param context Context
+--- at return string
function Element:format_number(number, variable, form, context)
number = util.strip(number)
if variable == "locator" then
- variable = context:get_variable("label")
+ local locator_variable = context:get_variable("label")
+ if not locator_variable or type(locator_variable) ~= "string" then
+ util.error("Invalid locator label")
+ locator_variable = "page"
+ end
+ variable = locator_variable
end
form = form or "numeric"
local number_part_list = self:split_number_parts_lpeg(number, context)
@@ -431,9 +441,11 @@
return res
end
----comment
---- at param number any
---- at param context any
+--- at alias NumberToken {type: string, value: string, delimiter_type: string}
+
+--- at param number string
+--- at param context Context
+--- at return NumberToken[]
function Element:parse_number_tokens(number, context)
local and_text = "and"
local and_symbol = "&"
@@ -465,10 +477,15 @@
value = token,
}
end
- local grammer = l.Ct(token_patt * (delimiter * token_patt)^0)
+ local grammer = l.Ct((token_patt * (delimiter * token_patt)^0)^-1)
local tokens = grammer:match(number)
-- util.debug(tokens)
+ if not tokens then
+ return {}
+ end
+ --- at cast tokens NumberToken[]
+
for i, token in ipairs(tokens) do
if token.type == "string" then
token.value = string.gsub(token.value, "\\%-", "-")
Modified: trunk/Master/texmf-dist/scripts/citation-style-language/citeproc-engine.lua
===================================================================
--- trunk/Master/texmf-dist/scripts/citation-style-language/citeproc-engine.lua 2024-07-31 23:41:56 UTC (rev 71943)
+++ trunk/Master/texmf-dist/scripts/citation-style-language/citeproc-engine.lua 2024-08-01 19:56:55 UTC (rev 71944)
@@ -103,6 +103,10 @@
--- at field cite_first_note_numbers table<ItemId, NoteIndex>
local CiteProc = {}
+--- at class CiteProcSys
+--- at field retrieveLocale fun(LanguageCode): string?
+--- at field retrieveItem fun(ItemId): ItemData?
+
---comment
--- at param sys table
--- at param style string
@@ -192,7 +196,7 @@
function CiteProc:check_valid_citation_element()
if not self.style.citation then
if self.style.info and self.style.info.independent_parent then
- util.error(string.format('This is a dependent style linked to "%s".', self.style.info.independent_parent))
+ util.error(string.format("This is a dependent style linked to '%s'.", self.style.info.independent_parent))
else
util.error('No <citation> in style.')
end
@@ -213,8 +217,10 @@
local loaded_ids = {}
for _, id in ipairs(ids) do
- table.insert(cite_items, {id = id})
- loaded_ids[id] = true
+ if not loaded_ids[id] then
+ table.insert(cite_items, {id = id})
+ loaded_ids[id] = true
+ end
end
for _, id in ipairs(self.registry.uncited_list) do
if not loaded_ids[id] then
@@ -737,6 +743,8 @@
return res
end
+--- at param bibsection any
+--- at return [{[string]: string | number | boolean}, string[]]
function CiteProc:makeBibliography(bibsection)
-- The bibsection works as a filter described in
-- <https://citeproc-js.readthedocs.io/en/latest/running.html#selective-output-with-makebibliography>.
@@ -981,7 +989,6 @@
local res = {}
local item = self.sys.retrieveItem(id)
if not item then
- util.warning(string.format("Didn't find a database entry for '%s'", id))
return nil
end
@@ -1139,7 +1146,7 @@
local locale_str = self.sys.retrieveLocale(lang)
if not locale_str then
- util.warning(string.format("Failed to retrieve locale \"%s\"", lang))
+ util.warning(string.format("Failed to retrieve locale '%s'", lang))
return nil
end
local locale_xml = dom.parse(locale_str)
Deleted: trunk/Master/texmf-dist/scripts/citation-style-language/citeproc-latex-core.lua
===================================================================
--- trunk/Master/texmf-dist/scripts/citation-style-language/citeproc-latex-core.lua 2024-07-31 23:41:56 UTC (rev 71943)
+++ trunk/Master/texmf-dist/scripts/citation-style-language/citeproc-latex-core.lua 2024-08-01 19:56:55 UTC (rev 71944)
@@ -1,525 +0,0 @@
---
--- Copyright (c) 2021-2024 Zeping Lee
--- Released under the MIT license.
--- Repository: https://github.com/zepinglee/citeproc-lua
---
-
-local core = {}
-
-require("lualibs")
-local json_decode = utilities.json.tolua
-
-local citeproc = require("citeproc")
-local bibtex_data = require("citeproc-bibtex-data")
-local bibtex_parser = require("citeproc-bibtex-parser")
-local latex_parser = require("citeproc-latex-parser")
-local yaml -- = require("citeproc-yaml") -- load on demand
-local bibtex2csl -- = require("citeproc-bibtex2csl") -- load on demand
-local unicode = require("citeproc-unicode")
-local util = citeproc.util
-
-
-core.locale_file_format = "csl-locales-%s.xml"
-core.uncited_ids = {}
-core.uncite_all_items = false
-
-core.item_list = {}
-core.item_dict = {}
-
---- at param file_name string
---- at param ftype "bib"?
---- at param file_info string
---- at return string? contents
-function core.read_file(file_name, ftype, file_info)
- if file_info then
- file_info = unicode.capitalize(file_info)
- else
- file_info = "File"
- end
- local path = kpse.find_file(file_name, ftype)
- if not path then
- if ftype and not util.endswith(file_name, ftype) then
- file_name = file_name .. ftype
- end
- util.error(string.format('%s "%s" not found', file_info, file_name))
- return nil
- end
- local file = io.open(path, "r")
- if not file then
- util.error(string.format('Cannot open %s "%s"', file_info, path))
- return nil
- end
- local contents = file:read("*a")
- contents = util.remove_bom(contents)
- file:close()
- return contents
-end
-
-
---- at param filename string
---- at return string file
---- at return string format
---- at return string? contents
-local function read_data_file(filename)
- local file = filename
- local format = "json"
- local contents = nil
-
- if util.endswith(filename, ".json") then
- format = "json"
- contents = core.read_file(filename, nil, "database file")
- elseif string.match(filename, "%.ya?ml$") then
- format = "yaml"
- contents = core.read_file(filename, nil, "database file")
- elseif util.endswith(filename, ".bib") then
- format = "bibtex"
- contents = core.read_file(filename, "bib", "database file")
- else
- file = filename .. ".json"
- local path = kpse.find_file(file)
- if path then
- format = "json"
- contents = core.read_file(file, nil, "database file")
- else
- path = kpse.find_file(filename .. ".yaml") or kpse.find_file(filename .. ".yml")
- if path then
- format = "yaml"
- file = filename .. string.match(path, "%.ya?ml$")
- contents = core.read_file(path, nil, "database file")
- else
- path = kpse.find_file(filename, "bib")
- if path then
- file = filename .. ".bib"
- format = "bibtex"
- contents = core.read_file(filename, "bib", "database file")
- else
- util.error(string.format('Cannot find database file "%s"', filename .. ".json"))
- return file, format, nil
- end
- end
- end
- end
- return file, format, contents
-end
-
-
-local function read_data_files(data_files)
- local item_list = {}
- local item_dict = {}
-
- --- Store BibTeX entries for later resolving crossref
- --- at type table<string, BibtexEntry>
- local bibtex_entries = {}
- --- at type table<string, string>
- local bibtex_strings = {}
- for name, macro in pairs(bibtex_data.macros) do
- bibtex_strings[name] = macro.value
- end
- --- at type BibtexEntry[]
- local entries_with_crossref = {}
-
- for _, data_file in ipairs(data_files) do
- -- local file_name, csl_items = read_data_file(data_file)
-
- local csl_items = {}
-
- local file, format, contents = read_data_file(data_file)
-
- if contents then
-
- if format == "json" then
- local ok, res = pcall(json_decode, contents)
- if ok and res then
- --- at cast res CslData
- csl_items = res
- else
- util.error(string.format('JSON decode error in file "%s".', file))
- end
-
- elseif format == "yaml" then
- yaml = yaml or require("citeproc-yaml")
- local ok, res = pcall(yaml.parse, contents)
- if ok and res then
- --- at cast res CslData
- csl_items = res
- else
- util.error(string.format('YAML decode error in file "%s".', file))
- end
-
- elseif format == "bibtex" then
- local bib_data, exceptions = bibtex_parser.parse(contents, bibtex_strings)
- if bib_data then
- bibtex2csl = bibtex2csl or require("citeproc-bibtex2csl")
- csl_items = bibtex2csl.convert_to_csl_data(bib_data, true, true, true, true)
- for _, entry in ipairs(bib_data.entries) do
- if not bibtex_entries[entry.key] then
- bibtex_entries[entry.key] = entry
- if entry.fields.crossref then
- table.insert(entries_with_crossref, entry)
- end
- end
- end
- for string_name, value in pairs(bib_data.strings) do
- bibtex_strings[string_name] = value
- end
- end
- end
-
- for _, item in ipairs(csl_items) do
- local id = item.id
- if item_dict[id] then
- util.warning(string.format('Duplicate entry key "%s" in "%s".', id, file))
- else
- item_dict[id] = item
- table.insert(item_list, item)
- end
- end
-
- end
- end
-
- bibtex_parser.resolve_crossrefs(entries_with_crossref, bibtex_entries)
-
- for _, entry in ipairs(entries_with_crossref) do
- local new_item = bibtex2csl.convert_to_csl_item(entry, true, true, true, true)
- item_dict[new_item.id] = new_item
- for i, item in ipairs(item_list) do
- if item.id == new_item.id then
- item_list[i] = new_item
- break
- end
- end
- end
-
- return item_list, item_dict
-end
-
-
-function core.make_citeproc_sys(data_files)
- core.item_list, core.item_dict = read_data_files(data_files)
- local citeproc_sys = {
- retrieveLocale = function (lang)
- local locale_file_format = core.locale_file_format or "locales-%s.xml"
- local filename = string.format(locale_file_format, lang)
- return core.read_file(filename)
- end,
- retrieveItem = function (id)
- local res = core.item_dict[id]
- return res
- end
- }
-
- return citeproc_sys
-end
-
----comment
---- at param style_name string
---- at param data_files string[]
---- at param lang string?
---- at return CiteProc?
-function core.init(style_name, data_files, lang)
- if style_name == "" or #data_files == 0 then
- return nil
- end
- local style = core.read_file(style_name .. ".csl", nil, "style")
- if not style then
- util.error(string.format('Failed to load style "%s.csl"', style_name))
- return nil
- end
-
- local force_lang = nil
- if lang and lang ~= "" then
- force_lang = true
- else
- lang = nil
- end
-
- local citeproc_sys = core.make_citeproc_sys(data_files)
- local engine = citeproc.new(citeproc_sys, style, lang, force_lang)
-
- if engine:is_dependent_style() then
- local default_locale = engine.style.default_locale;
- local parent_style_link = engine:get_independent_parent()
- if not parent_style_link then
- return nil
- end
- local parent_style_id = string.match(string.gsub(parent_style_link, "/+$", ""), "[^/]+$")
- util.info(string.format('Style "%s" is a dependent style linked to "%s".', style_name, parent_style_id))
- style = core.read_file(parent_style_id .. ".csl", nil, "style")
- if not style then
- util.error(string.format('Failed to load style "%s.csl"', parent_style_id))
- return nil
- end
- engine = citeproc.new(citeproc_sys, style, lang, force_lang)
- engine.style.default_locale = default_locale
- end
-
- return engine
-end
-
-local function parse_latex_seq(s)
- local t = {}
- for item in string.gmatch(s, "(%b{})") do
- item = string.sub(item, 2, -2)
- table.insert(t, item)
- end
- return t
-end
-
-local function parse_latex_prop(s)
- local t = {}
- for key, value in string.gmatch(s, "([%w%-]+)%s*=%s*(%b{})") do
- value = string.sub(value, 2, -2)
- if value == "true" then
- value = true
- elseif value == "false" then
- value = false
- end
- t[key] = value
- end
- return t
-end
-
-function core.make_citation(citation_info)
- -- `citation_info`: "citationID={ITEM-1 at 2},citationItems={{id={ITEM-1},label={page},locator={6}}},properties={noteIndex={3}}"
- -- util.debug(citation_info)
- local citation = parse_latex_prop(citation_info)
- -- assert(citation.citationID)
- -- assert(citation.citationItems)
- -- assert(citation.properties)
-
- citation.citationItems = parse_latex_seq(citation.citationItems)
-
- for i, item in ipairs(citation.citationItems) do
- local citation_item = parse_latex_prop(item)
- if citation_item.prefix then
- -- util.debug(citation_item.prefix)
- citation_item.prefix = latex_parser.latex_to_pseudo_html(citation_item.prefix, true, false)
- -- util.debug(citation_item.prefix)
- end
- if citation_item.suffix then
- citation_item.suffix = latex_parser.latex_to_pseudo_html(citation_item.suffix, true, false)
- end
- citation.citationItems[i] = citation_item
- end
-
- citation.properties = parse_latex_prop(citation.properties)
- local note_index = citation.properties.noteIndex
- if not note_index or note_index == "" then
- citation.properties.noteIndex = 0
- elseif type(note_index) == "string" and string.match(note_index, "^%d+$") then
- citation.properties.noteIndex = tonumber(note_index)
- else
- util.error(string.format('Invalid note index "%s".', note_index))
- end
-
- -- util.debug(citation)
- return citation
-end
-
-
---- at param engine CiteProc
---- at param citations CitationData[]
---- at return table<CitationId, string>
-function core.process_citations(engine, citations)
- local citations_pre = {}
-
- local citation_strings = {}
-
- core.update_cited_and_uncited_ids(engine, citations)
-
- for _, citation in ipairs(citations) do
- if citation.citationID ~= "@nocite" then
- -- local res = engine:processCitationCluster(citation, citations_pre, {})
- -- for _, tuple in ipairs(res[2]) do
- -- local citation_str = tuple[2]
- -- local citation_id = tuple[3]
- -- citation_strings[citation_id] = citation_str
- -- util.debug(citation_str)
- -- end
-
- local citation_str = engine:process_citation(citation)
- citation_strings[citation.citationID] = citation_str
-
- table.insert(citations_pre, {citation.citationID, citation.properties.noteIndex})
- end
- end
-
- return citation_strings
-end
-
-function core.update_cited_and_uncited_ids(engine, citations)
- local id_list = {}
- local id_map = {} -- Boolean map for checking if id in list
- local uncited_id_list = {}
- local uncited_id_map = {}
-
- for _, citation in ipairs(citations) do
- if citation.citationID == "@nocite" then
- for _, cite_item in ipairs(citation.citationItems) do
- if cite_item.id == "*" then
- if not core.uncite_all_items then
- for _, item in ipairs(core.item_list) do
- if not uncited_id_map[item.id] then
- table.insert(uncited_id_list, item.id)
- uncited_id_map[item.id] = true
- end
- end
- core.uncite_all_items = true
- end
- elseif not uncited_id_map[cite_item.id] then
- table.insert(uncited_id_list, cite_item.id)
- uncited_id_map[cite_item.id] = true
- end
- end
-
- else -- Real citation
- for _, cite_item in ipairs(citation.citationItems) do
- if not id_map[cite_item.id] then
- table.insert(id_list, cite_item.id)
- id_map[cite_item.id] = true
- end
- end
-
- end
- end
-
- engine:updateItems(id_list)
- engine:updateUncitedItems(uncited_id_list)
-
-end
-
-
----Convert to a filter object described in
---- <https://citeproc-js.readthedocs.io/en/latest/running.html#selective-output-with-makebibliography>
---- at param filter_str string e.g., "type={book},notcategory={csl},notcategory={tex}"
---- at return table
-function core.parser_filter(filter_str)
- local conditions = {}
- for i, condition in ipairs(latex_parser.parse_seq(filter_str)) do
- local negative
- local field, value = string.match(condition, "(%w+)%s*=%s*{([^}]+)}")
- if field then
- if string.match(field, "^not") then
- negative = true
- field = string.gsub(field, "^not", "")
- end
- if field == "category" then
- field = "categories"
- end
- if field == "keyword" or field == "type" or field == "categories" then
- table.insert(conditions, {
- field = field,
- value = value,
- negative = negative,
- })
- end
- end
- end
- -- util.debug(conditions)
- return {select = conditions}
-end
-
----comment
---- at param engine CiteProc
---- at param option_str string
---- at return unknown
-function core.make_bibliography(engine, option_str)
- local filter
- local options = {}
- if option_str and option_str ~= "" then
- options = latex_parser.parse_prop(option_str)
- filter = core.parser_filter(option_str)
- end
- local result = engine:makeBibliography(filter)
-
- local params = result[1]
- local bib_items = result[2]
-
- local res = ""
-
- --- at type table<string, any>
- local bib_options = {
- index = options.index or "1"
- }
-
- local bib_option_map = {
- ["second-field-align"] = "second-field-align",
- ["hanging-indent"] = "hangingindent",
- ["entry-spacing"] = "entryspacing",
- ["line-spacing"] = "linespacing",
- ["widest-label"] = "widest_label",
- }
- local bib_option_order = {
- "index",
- "second-field-align",
- "hanging-indent",
- "line-spacing",
- "entry-spacing",
- "widest-label",
- }
-
- for option, param in pairs(bib_option_map) do
- if params[param] then
- bib_options[option] = params[param]
- end
- end
-
- local bib_option_list = {}
- for _, option in ipairs(bib_option_order) do
- local value = bib_options[option]
- if value and value ~= "" then
- table.insert(bib_option_list, string.format("%s = %s", option, tostring(value)))
- end
- end
- local bib_options_str = table.concat(bib_option_list, ", ")
-
- -- util.debug(params.bibstart)
- -- if params.bibstart then
- -- res = res .. params.bibstart
- -- end
-
- local bibstart = string.format("\\begin{thebibliography}{%s}\n", bib_options_str)
- res = res .. bibstart
-
-
- for _, bib_item in ipairs(bib_items) do
- res = res .. "\n" .. bib_item
- end
-
- if params.bibend then
- res = res .. "\n" .. params.bibend
- end
- return res
-end
-
-
-function core.set_categories(engine, categories_str)
- -- util.debug(categories_str)
- local category_dict = latex_parser.parse_prop(categories_str)
- for category, keys in pairs(category_dict) do
- category_dict[category] = latex_parser.parse_seq(keys)
- end
- for category, keys in pairs(category_dict) do
- for _, key in ipairs(keys) do
- local item = engine.registry.registry[key]
- if item then
- if not item.categories then
- item.categories = {}
- end
- if not util.in_list(category, item.categories) then
- table.insert(item.categories, category)
- end
- else
- util.error(string.format("Invalid citation key '%s'.", key))
- end
- end
- end
- -- for id, item in pairs(csl.engine.registry.registry) do
- -- util.debug(id)
- -- util.debug(item.categories)
- -- end
-end
-
-
-return core
Modified: trunk/Master/texmf-dist/scripts/citation-style-language/citeproc-latex-parser.lua
===================================================================
--- trunk/Master/texmf-dist/scripts/citation-style-language/citeproc-latex-parser.lua 2024-07-31 23:41:56 UTC (rev 71943)
+++ trunk/Master/texmf-dist/scripts/citation-style-language/citeproc-latex-parser.lua 2024-08-01 19:56:55 UTC (rev 71944)
@@ -8,7 +8,7 @@
local bibtex_parser
local latex_data
-local markup
+local markup
local util
if kpse then
latex_data = require("citeproc-latex-data")
@@ -365,6 +365,7 @@
return inlines, i
end
+-- TODO: raise a warning for unrecognized LaTeX command like `\switchargs`
function latex_parser.convert_group_to_inlines(token, strict, case_protection, force_add_braces)
if case_protection then
local first_token = token.contents[1]
Deleted: trunk/Master/texmf-dist/scripts/citation-style-language/citeproc-latex.lua
===================================================================
--- trunk/Master/texmf-dist/scripts/citation-style-language/citeproc-latex.lua 2024-07-31 23:41:56 UTC (rev 71943)
+++ trunk/Master/texmf-dist/scripts/citation-style-language/citeproc-latex.lua 2024-08-01 19:56:55 UTC (rev 71944)
@@ -1,183 +0,0 @@
---
--- Copyright (c) 2021-2024 Zeping Lee
--- Released under the MIT license.
--- Repository: https://github.com/zepinglee/citeproc-lua
---
-
-local csl = {}
-
-local citeproc = require("citeproc")
-local util = citeproc.util
-require("lualibs")
-local core = require("citeproc-latex-core")
-local latex_parser = require("citeproc-latex-parser")
-
-
-csl.initialized = "false"
-csl.id_list = {}
-csl.id_map = {} -- Boolean map for checking if id in list
-csl.uncited_id_list = {}
-csl.uncited_id_map = {}
-csl.citations_pre = {}
-
-csl.preview_mode = false -- Whether to use citeproc:preview_citation
-
-
-function csl.init(style_name, bib_files, lang)
- if string.match(bib_files, "^%s*$") then
- bib_files = {}
- else
- bib_files = util.split(util.strip(bib_files), "%s*,%s*")
- end
-
- csl.engine = core.init(style_name, bib_files, lang)
-
- if csl.engine and csl.engine.style.citation then
- csl.initialized = "true"
- else
- return
- end
-
- -- csl.init is called via \AtBeginDocument and it's executed after
- -- loading .aux file. The csl.id_list are already registered.
- csl.engine:updateItems(csl.id_list)
-
- if core.uncite_all_items then
- for _, item in ipairs(core.item_list) do
- if not csl.uncited_id_map[item.id] then
- table.insert(csl.uncited_id_list, item.id)
- csl.uncited_id_map[item.id] = true
- end
- end
- end
- csl.engine:updateUncitedItems(csl.uncited_id_list)
- csl.style_class = csl.engine:get_style_class()
-end
-
-
-function csl.get_style_class()
- tex.sprint(csl.style_class)
-end
-
-
-function csl.register_citation_info(citation_info)
- local citation = core.make_citation(citation_info)
- if citation.citationID == "@nocite" then
- for _, cite_item in ipairs(citation.citationItems) do
- if cite_item.id == "*" then
- -- \nocite all items
- core.uncite_all_items = true
-
- elseif not csl.uncited_id_map[cite_item.id] then
- table.insert(csl.uncited_id_list, cite_item.id)
- csl.uncited_id_map[cite_item.id] = true
- end
- end
-
- else
- for _, cite_item in ipairs(citation.citationItems) do
- if not csl.id_map[cite_item.id] then
- table.insert(csl.id_list, cite_item.id)
- csl.id_map[cite_item.id] = true
- end
- end
- end
-end
-
-
-function csl.enable_linking()
- csl.engine:enable_linking()
-end
-
-
----comment
---- at param citation_info string
-function csl.cite(citation_info)
- -- "citationID={ITEM-UNAVAILABLE at 1},citationItems={{id={ITEM-UNAVAILABLE}}},properties={noteIndex={1}}"
- if not csl.engine then
- util.error("CSL engine is not initialized.")
- end
-
- -- util.debug(citation_info)
- local citation = core.make_citation(citation_info)
- -- util.debug(citation)
-
- local citation_str
- if csl.preview_mode then
- -- TODO: preview mode in first pass of \blockquote of csquotes
- -- citation_str = csl.engine:preview_citation(citation)
- citation_str = ""
- else
- citation_str = csl.engine:process_citation(citation)
- end
- -- util.debug(citation_str)
-
- -- tex.sprint(citation_str)
- -- tex.setcatcode(35, 12) -- #
- -- tex.setcatcode(37, 12) -- %
- -- token.set_macro("l__csl_citation_tl", citation_str)
- -- Don't use `token.set_macro`.
- -- See <https://github.com/zepinglee/citeproc-lua/issues/42>
- -- and <https://tex.stackexchange.com/questions/519954/backslashes-in-macros-defined-in-lua-code>.
- tex.sprint(string.format("\\expandafter\\def\\csname l__csl_citation_tl\\endcsname{%s}", citation_str))
-
- for _, cite_item in ipairs(citation.citationItems) do
- if not core.item_dict[cite_item.id] then
- tex.print(string.format("\\cslsetup{undefined-cites = {%s}}", cite_item.id))
- end
- end
-
- table.insert(csl.citations_pre, {citation.citationID, citation.properties.noteIndex})
-end
-
-
-function csl.nocite(ids_string)
- local uncited_ids = util.split(ids_string, "%s*,%s*")
- for _, uncited_id in ipairs(uncited_ids) do
- if uncited_id == "*" then
- if csl.engine then
- for id, _ in pairs(core.item_dict) do
- if not csl.uncited_id_map[id] then
- table.insert(csl.uncited_id_list, id)
- csl.uncited_id_map[id] = true
- end
- end
- csl.engine:updateUncitedItems(csl.uncited_id_list)
- else
- core.uncite_all_items = true
- end
- else
- if not csl.uncited_id_map[uncited_id] then
- table.insert(csl.uncited_id_list, uncited_id)
- csl.uncited_id_map[uncited_id] = true
- if csl.engine then
- csl.engine:updateUncitedItems(csl.uncited_id_list)
- end
- end
- end
- end
-end
-
-
-function csl.bibliography(filter_str)
- if not csl.engine then
- util.error("CSL engine is not initialized.")
- return
- end
-
- -- util.debug(filter)
- local result = core.make_bibliography(csl.engine, filter_str)
- -- util.debug(result)
-
- -- token.set_macro("g__csl_bibliography_tl", result)
-
- tex.print(util.split(result, "\n"))
-end
-
-
-function csl.set_categories(categories_str)
- core.set_categories(csl.engine, categories_str)
-end
-
-
-return csl
Added: trunk/Master/texmf-dist/scripts/citation-style-language/citeproc-manager.lua
===================================================================
--- trunk/Master/texmf-dist/scripts/citation-style-language/citeproc-manager.lua (rev 0)
+++ trunk/Master/texmf-dist/scripts/citation-style-language/citeproc-manager.lua 2024-08-01 19:56:55 UTC (rev 71944)
@@ -0,0 +1,916 @@
+--
+-- Copyright (c) 2021-2024 Zeping Lee
+-- Released under the MIT license.
+-- Repository: https://github.com/zepinglee/citeproc-lua
+--
+
+local citeproc_manager = {}
+
+require("lualibs")
+local json_decode = utilities.json.tolua
+
+local citeproc = require("citeproc")
+local bibtex_data = require("citeproc-bibtex-data")
+local bibtex_parser = require("citeproc-bibtex-parser")
+local latex_parser = require("citeproc-latex-parser")
+local util = citeproc.util
+local unicode = require("citeproc-unicode")
+
+
+--- at param file_name string
+--- at param ftype "bib" | nil
+--- at param file_info string
+--- at return string? contents
+local function read_file(file_name, ftype, file_info)
+ if file_info then
+ file_info = unicode.capitalize(file_info)
+ else
+ file_info = "File"
+ end
+ local path
+ if ftype then
+ path = kpse.find_file(file_name, ftype)
+ else
+ path = kpse.find_file(file_name)
+ end
+
+ if not path then
+ if ftype and not util.endswith(file_name, ftype) then
+ file_name = file_name .. ftype
+ end
+ util.error(string.format("%s '%s' not found", file_info, file_name))
+ return nil
+ end
+ local file = io.open(path, "r")
+ if not file then
+ util.error(string.format("Cannot open %s '%s'", file_info, path))
+ return nil
+ end
+ local contents = file:read("*a")
+ contents = util.remove_bom(contents)
+ file:close()
+ return contents
+end
+
+
+--- at param filename string
+--- at return string file
+--- at return string format
+--- at return string? contents
+local function read_data_file(filename)
+ local file = filename
+ local format = "json"
+ local contents = nil
+
+ if util.endswith(filename, ".json") then
+ format = "json"
+ contents = read_file(filename, nil, "database file")
+ elseif string.match(filename, "%.ya?ml$") then
+ format = "yaml"
+ contents = read_file(filename, nil, "database file")
+ elseif util.endswith(filename, ".bib") then
+ format = "bibtex"
+ contents = read_file(filename, "bib", "database file")
+ else
+ file = filename .. ".json"
+ local path = kpse.find_file(file)
+ if path then
+ format = "json"
+ contents = read_file(file, nil, "database file")
+ else
+ path = kpse.find_file(filename .. ".yaml") or kpse.find_file(filename .. ".yml")
+ if path then
+ format = "yaml"
+ file = filename .. string.match(path, "%.ya?ml$")
+ contents = read_file(path, nil, "database file")
+ else
+ path = kpse.find_file(filename, "bib")
+ if path then
+ file = filename .. ".bib"
+ format = "bibtex"
+ contents = read_file(filename, "bib", "database file")
+ else
+ util.error(string.format("Cannot find database file '%s'", filename .. ".json"))
+ return file, format, nil
+ end
+ end
+ end
+ end
+ return file, format, contents
+end
+
+
+--- at param data_files FilePath[]
+--- at return ItemData[]
+--- at return table<ItemId, ItemData>
+local function read_data_files(data_files)
+ local item_list = {}
+ local item_dict = {}
+
+ --- Store BibTeX entries for later resolving crossref
+ --- at type table<string, BibtexEntry>
+ local bibtex_entries = {}
+ --- at type table<string, string>
+ local bibtex_strings = {}
+ for name, macro in pairs(bibtex_data.macros) do
+ bibtex_strings[name] = macro.value
+ end
+ --- at type BibtexEntry[]
+ local entries_with_crossref = {}
+
+ for _, data_file in ipairs(data_files) do
+ -- local file_name, csl_items = read_data_file(data_file)
+
+ local csl_items = {}
+
+ local file, format, contents = read_data_file(data_file)
+
+ if contents then
+
+ if format == "json" then
+ local ok, res = pcall(json_decode, contents)
+ if ok and res then
+ --- at cast res CslData
+ csl_items = res
+ else
+ util.error(string.format("JSON decode error in file '%s'.", file))
+ end
+
+ elseif format == "yaml" then
+ yaml = yaml or require("citeproc-yaml")
+ local ok, res = pcall(yaml.parse, contents)
+ if ok and res then
+ --- at cast res CslData
+ csl_items = res
+ else
+ util.error(string.format("YAML decode error in file '%s'.", file))
+ end
+
+ elseif format == "bibtex" then
+ local bib_data, exceptions = bibtex_parser.parse(contents, bibtex_strings)
+ if bib_data then
+ bibtex2csl = bibtex2csl or require("citeproc-bibtex2csl")
+ csl_items = bibtex2csl.convert_to_csl_data(bib_data, true, true, true, true)
+ for _, entry in ipairs(bib_data.entries) do
+ if not bibtex_entries[entry.key] then
+ bibtex_entries[entry.key] = entry
+ if entry.fields.crossref then
+ table.insert(entries_with_crossref, entry)
+ end
+ end
+ end
+ for string_name, value in pairs(bib_data.strings) do
+ bibtex_strings[string_name] = value
+ end
+ end
+ end
+
+ for _, item in ipairs(csl_items) do
+ local id = item.id
+ if item_dict[id] then
+ util.warning(string.format("Duplicate entry key '%s' in '%s'.", id, file))
+ else
+ item_dict[id] = item
+ table.insert(item_list, item)
+ end
+ end
+
+ end
+ end
+
+ bibtex_parser.resolve_crossrefs(entries_with_crossref, bibtex_entries)
+
+ for _, entry in ipairs(entries_with_crossref) do
+ local new_item = bibtex2csl.convert_to_csl_item(entry, true, true, true, true)
+ item_dict[new_item.id] = new_item
+ for i, item in ipairs(item_list) do
+ if item.id == new_item.id then
+ item_list[i] = new_item
+ break
+ end
+ end
+ end
+
+ return item_list, item_dict
+end
+
+
+--- at param item_dict table<ItemId, ItemData>
+--- at return CiteProcSys
+local function make_citeproc_sys(item_dict)
+ local citeproc_sys = {
+ retrieveLocale = function (lang)
+ local locale_file_format = "csl-locales-%s.xml"
+ local filename = string.format(locale_file_format, lang)
+ return read_file(filename, nil, "locale file")
+ end,
+ retrieveItem = function (id)
+ local res = item_dict[id]
+ if not res and not luatexbase then
+ util.warning(string.format("Didn't find a database entry for '%s'", id))
+ end
+ return res
+ end
+ }
+ return citeproc_sys
+end
+
+
+--- at alias StyleId string
+--- at alias FilePath string
+--- at alias LanguageCode string
+
+--- at class RefSection
+--- at field initialized boolean
+--- at field style_id string?
+--- at field bib_resources FilePath[]
+--- at field lang LanguageCode?
+--- at field engine CiteProc?
+--- at field cited_ids ItemId[]
+--- at field uncited_ids ItemId[]
+--- at field items ItemData[]
+--- at field item_dict table<ItemId, ItemData>
+--- at field citations CitationData[]
+--- at field citations_pre table[]
+--- at field bibliography_configs string[]
+local RefSection = {}
+
+--- at return RefSection
+function RefSection:new()
+ --- at type RefSection
+ local ref_section = {
+ initialized = false,
+ style_id = nil,
+ bib_resources = {},
+ lang = nil,
+ engine = nil,
+ cited_ids = {},
+ uncited_ids = {},
+ items = {},
+ item_dict = {},
+ citations = {},
+ citations_pre = {},
+ bibliography_configs = {},
+ }
+ setmetatable(ref_section, self)
+ self.__index = self
+ return ref_section
+end
+
+function RefSection:make_citeproc_engine()
+ if not self.style_id or self.style_id == "" then
+ self.style_id = "apa"
+ end
+ local style = read_file(self.style_id .. ".csl", nil, "style")
+ if not style then
+ return
+ end
+
+ self.items, self.item_dict = read_data_files(self.bib_resources)
+ local citeproc_sys = make_citeproc_sys(self.item_dict)
+
+ local force_lang = false
+ if self.lang and self.lang ~= "" then
+ force_lang = true
+ else
+ self.lang = nil
+ end
+
+ self.engine = citeproc.new(citeproc_sys, style, self.lang, force_lang)
+ self:_check_dependent_style(citeproc_sys)
+
+ if self.engine and self.engine.style.citation then
+ self.initialized = true
+ end
+
+ self.engine:updateItems(self.cited_ids)
+
+ self:_update_uncited_items()
+
+end
+
+--- at param citeproc_sys CiteProcSys
+function RefSection:_check_dependent_style(citeproc_sys)
+ if self.engine:is_dependent_style() then
+ local default_locale = self.engine.style.default_locale;
+ local parent_style_link = self.engine:get_independent_parent()
+ if not parent_style_link then
+ return nil
+ end
+ local parent_style_id = string.match(string.gsub(parent_style_link, "/+$", ""), "[^/]+$")
+ util.info(string.format('Style "%s" is a dependent style linked to "%s".', self.style_id, parent_style_id))
+ local style = read_file(parent_style_id .. ".csl", nil, "style")
+ if not style then
+ util.error(string.format("Failed to load style '%s.csl'", parent_style_id))
+ return nil
+ end
+ local force_lang = false
+ if self.lang and self.lang ~= "" then
+ force_lang = true
+ else
+ self.lang = nil
+ end
+ self.engine = citeproc.new(citeproc_sys, style, self.lang, force_lang)
+ self.engine.style.default_locale = default_locale
+ end
+end
+
+function RefSection:_update_uncited_items()
+ local uncited_ids = {}
+ for _, id in ipairs(self.uncited_ids) do
+ if id == "*" then
+ for _, item in ipairs(self.items) do
+ table.insert(uncited_ids, item.id)
+ end
+ break
+ else
+ table.insert(uncited_ids, id)
+ end
+ end
+ if self.initialized then
+ self.engine:updateUncitedItems(uncited_ids)
+ end
+ self.uncited_ids = uncited_ids
+end
+
+
+--- at class CslCitationManager
+--- at field global_ref_section RefSection
+--- at field max_ref_section_index integer
+--- at field ref_section_index integer
+--- at field ref_sections table<integer, RefSection>
+--- at field ref_section RefSection
+--- at field hyperref_loaded boolean
+local CslCitationManager = {}
+
+--- at return CslCitationManager
+function CslCitationManager:new()
+ local ref_section = RefSection:new()
+ --- at type CslCitationManager
+ local o = {
+ -- global_style_id = "apa",
+ -- global_bib_resources = {},
+ -- global_lang = nil,
+ global_ref_section = ref_section,
+ max_ref_section_index = 0,
+ ref_section_index = 0,
+ ref_sections = {
+ [0] = ref_section,
+ },
+ ref_section = ref_section,
+
+ hyperref_loaded = false,
+ }
+
+ setmetatable(o, self)
+ self.__index = self
+ return o
+end
+
+--- The init method is called via \AtBeginDocument after loading .aux file.
+--- The ref_section.cited_ids are already registered.
+--- at param style_id StyleId
+--- at param bib_resources_str FilePathsString
+--- at param lang LanguageCode?
+function CslCitationManager:init(style_id, bib_resources_str, lang)
+ local global_ref_section = self.global_ref_section
+ global_ref_section.style_id = "apa"
+ if style_id and style_id ~= "" then
+ global_ref_section.style_id = style_id
+ end
+ global_ref_section.bib_resources = util.split(util.strip(bib_resources_str), "%s*,%s*")
+ if lang and lang ~= "" then
+ global_ref_section.lang = lang
+ end
+
+ global_ref_section:make_citeproc_engine()
+ if self.hyperref_loaded then
+ global_ref_section.engine:enable_linking()
+ end
+ self.ref_section_index = 0
+end
+
+
+function CslCitationManager:get_style_class()
+ if not self.ref_section then
+ return nil
+ end
+ if self.ref_section.engine then
+ return self.ref_section.engine:get_style_class()
+ else
+ return nil
+ end
+end
+
+--- at alias FilePathsString string
+
+--- at param style_id string?
+--- at param bib_resources_str FilePathsString?
+--- at param lang LanguageCode?
+function CslCitationManager:begin_ref_section(style_id, bib_resources_str, lang)
+ self.max_ref_section_index = self.max_ref_section_index + 1
+ self.ref_section_index = self.max_ref_section_index
+ self.ref_section = self.ref_sections[self.ref_section_index]
+ if not self.ref_section then
+ self.ref_section = RefSection:new()
+ self.ref_sections[self.ref_section_index] = self.ref_section
+ end
+
+ self.ref_section.style_id = style_id or self.global_ref_section.style_id
+ self.ref_section.bib_resources = self.global_ref_section.bib_resources
+ if bib_resources_str and bib_resources_str ~= "" then
+ self.ref_section.bib_resources = util.split(util.strip(bib_resources_str), "%s*,%s*")
+ end
+ self.ref_section.lang = self.global_ref_section.lang
+ if lang and lang ~= "" then
+ self.ref_section.lang = lang
+ end
+ -- self.ref_section.force_lang = force_lang or false
+
+ self.ref_section:make_citeproc_engine()
+
+ if self.hyperref_loaded then
+ self.ref_section.engine:enable_linking()
+ end
+
+end
+
+
+function CslCitationManager:end_ref_section()
+ self.ref_section_index = 0
+ self.ref_section = self.ref_sections[0]
+end
+
+
+---This method is called from the `\csl at aux@cite` command from `.aux` file.
+--- at param ref_section_index_str string
+--- at param citation_info string
+function CslCitationManager:register_citation_info(ref_section_index_str, citation_info)
+ local ref_section_index = tonumber(ref_section_index_str)
+ if not ref_section_index then
+ util.error(string.format("Invalid refsetion index '%s'", ref_section_index_str))
+ return
+ end
+ local ref_section = self.ref_sections[ref_section_index]
+ if not ref_section then
+ ref_section = RefSection:new()
+ self.ref_sections[ref_section_index] = ref_section
+ end
+
+ local citation = self:_make_citation(citation_info)
+
+ for _, cite_item in ipairs(citation.citationItems) do
+ if citation.citationID == "@nocite" then
+ table.insert(ref_section.uncited_ids, cite_item.id)
+ else
+ table.insert(ref_section.cited_ids, cite_item.id)
+ end
+ end
+end
+
+function CslCitationManager:enable_linking()
+ self.hyperref_loaded = true
+ if self.ref_section.engine then
+ self.ref_section.engine:enable_linking()
+ end
+end
+
+
+--- at param citation_info string
+function CslCitationManager:cite(citation_info)
+ if not self.ref_section then
+ util.error("Refsection is not initialized.")
+ return
+ end
+ local engine = self.ref_section.engine
+ if not engine then
+ util.error("CSL engine is not initialized.")
+ return
+ end
+
+ -- util.debug(citation_info)
+ local citation = self:_make_citation(citation_info)
+ -- util.debug(citation)
+
+ local citation_str
+ -- if preview_mode then
+ -- -- TODO: preview mode in first pass of \blockquote of csquotes
+ -- -- citation_str = engine:preview_citation(citation)
+ -- citation_str = ""
+ -- else
+ citation_str = engine:process_citation(citation)
+ -- end
+ -- util.debug(citation_str)
+
+ -- tex.sprint(citation_str)
+ -- tex.setcatcode(35, 12) -- #
+ -- tex.setcatcode(37, 12) -- %
+ -- token.set_macro("l__csl_citation_tl", citation_str)
+ -- Don't use `token.set_macro`.
+ -- See <https://github.com/zepinglee/citeproc-lua/issues/42>
+ -- and <https://tex.stackexchange.com/questions/519954/backslashes-in-macros-defined-in-lua-code>.
+ tex.sprint(string.format("\\expandafter\\def\\csname l__csl_citation_tl\\endcsname{%s}", citation_str))
+
+ table.insert(self.ref_section.citations_pre, {citation.citationID, citation.properties.noteIndex})
+end
+
+local function parse_latex_seq(s)
+ local t = {}
+ for item in string.gmatch(s, "(%b{})") do
+ item = string.sub(item, 2, -2)
+ table.insert(t, item)
+ end
+ return t
+end
+
+local function parse_latex_prop(s)
+ local t = {}
+ for key, value in string.gmatch(s, "([%w%-]+)%s*=%s*(%b{})") do
+ value = string.sub(value, 2, -2)
+ if value == "true" then
+ value = true
+ elseif value == "false" then
+ value = false
+ end
+ t[key] = value
+ end
+ return t
+end
+
+--- at param citation_info string
+--- at return CitationData
+function CslCitationManager:_make_citation(citation_info)
+ -- `citation_info`: "citationID={ITEM-1 at 2},citationItems={{id={ITEM-1},label={page},locator={6}}},properties={noteIndex={3}}"
+ -- util.debug(citation_info)
+ local citation = parse_latex_prop(citation_info)
+ -- assert(citation.citationID)
+ -- assert(citation.citationItems)
+ -- assert(citation.properties)
+
+ citation.citationItems = parse_latex_seq(citation.citationItems)
+
+ for i, item in ipairs(citation.citationItems) do
+ local citation_item = parse_latex_prop(item)
+ if citation_item.prefix then
+ -- util.debug(citation_item.prefix)
+ citation_item.prefix = latex_parser.latex_to_pseudo_html(citation_item.prefix, true, false)
+ -- util.debug(citation_item.prefix)
+ end
+ if citation_item.suffix then
+ citation_item.suffix = latex_parser.latex_to_pseudo_html(citation_item.suffix, true, false)
+ end
+ citation.citationItems[i] = citation_item
+ end
+
+ citation.properties = parse_latex_prop(citation.properties)
+ local note_index = citation.properties.noteIndex
+ if not note_index or note_index == "" then
+ citation.properties.noteIndex = 0
+ elseif type(note_index) == "string" and string.match(note_index, "^%d+$") then
+ citation.properties.noteIndex = tonumber(note_index)
+ else
+ util.error(string.format("Invalid note index '%s'.", note_index))
+ end
+
+ -- util.debug(citation)
+ return citation
+end
+
+--- at param ids_string string The list of item IDs separated by commas
+function CslCitationManager:nocite(ids_string)
+ local uncited_ids = util.split(util.strip(ids_string), "%s*,%s*")
+
+ local engine = self.ref_section.engine
+ if not engine then
+ for _, id in ipairs(uncited_ids) do
+ table.insert(self.ref_section.uncited_ids, id)
+ end
+ return
+ end
+
+ for _, id in ipairs(uncited_ids) do
+ if id == "*" then
+ for _, item in ipairs(self.ref_section.items) do
+ table.insert(self.ref_section.uncited_ids, item.id)
+ end
+ break
+ else
+ table.insert(self.ref_section.uncited_ids, id)
+ end
+ end
+ engine:updateUncitedItems(self.ref_section.uncited_ids)
+end
+
+
+--- at param filter_str string
+function CslCitationManager:bibliography(filter_str)
+ if not self.ref_section then
+ util.error("Refsection is not initialized.")
+ return
+ end
+ local bib_lines = self:make_bibliography(filter_str)
+ tex.print(util.split(table.concat(bib_lines, "\n"), "\n"))
+end
+
+--- at param filter_str string
+--- at return string[]
+function CslCitationManager:make_bibliography(filter_str)
+ local engine = self.ref_section.engine
+ if not engine then
+ util.error("CSL engine is not initialized.")
+ return {}
+ end
+ local filter
+ local options = {}
+ if filter_str and filter_str ~= "" then
+ options = latex_parser.parse_prop(filter_str)
+ filter = self:_parser_filter(filter_str)
+ -- util.debug(filter)
+ end
+ local result = engine:makeBibliography(filter)
+
+ local params = result[1]
+ local bib_items = result[2]
+
+ --- at type table<string, any>
+ local bib_options = {
+ index = options.index or "1"
+ }
+
+ local bib_option_map = {
+ ["second-field-align"] = "second-field-align",
+ ["hanging-indent"] = "hangingindent",
+ ["entry-spacing"] = "entryspacing",
+ ["line-spacing"] = "linespacing",
+ ["widest-label"] = "widest_label",
+ }
+ local bib_option_order = {
+ "index",
+ "second-field-align",
+ "hanging-indent",
+ "line-spacing",
+ "entry-spacing",
+ "widest-label",
+ }
+
+ for option, param in pairs(bib_option_map) do
+ if params[param] then
+ bib_options[option] = params[param]
+ end
+ end
+
+ local bib_option_list = {}
+ for _, option in ipairs(bib_option_order) do
+ local value = bib_options[option]
+ if value and value ~= "" then
+ table.insert(bib_option_list, string.format("%s = %s", option, tostring(value)))
+ end
+ end
+ local bib_options_str = table.concat(bib_option_list, ", ")
+
+ local bibstart = string.format("\\begin{thebibliography}{%s}\n", bib_options_str)
+ local bib_lines = {}
+ table.insert(bib_lines, bibstart)
+
+ for _, bib_item in ipairs(bib_items) do
+ table.insert(bib_lines, bib_item)
+ end
+
+ if params.bibend then
+ table.insert(bib_lines, params.bibend)
+ end
+ return bib_lines
+end
+
+function CslCitationManager:set_categories(categories_str)
+ if self.ref_section.engine then
+
+ local category_dict = latex_parser.parse_prop(categories_str)
+ for category, keys in pairs(category_dict) do
+ category_dict[category] = latex_parser.parse_seq(keys)
+ end
+ for category, keys in pairs(category_dict) do
+ for _, key in ipairs(keys) do
+ local item = self.ref_section.engine.registry.registry[key]
+ if item then
+ if not item.categories then
+ -- TODO: Extend ItemData field types
+ item.categories = {}
+ end
+ if not util.in_list(category, item.categories) then
+ table.insert(item.categories, category)
+ end
+ else
+ util.error(string.format("Invalid citation key '%s'.", key))
+ end
+ end
+ end
+ end
+end
+
+local command_info = {
+ {"\\csl at aux@style", 2},
+ {"\\csl at aux@data", 2},
+ {"\\csl at aux@cite", 2},
+ {"\\csl at aux@options", 2},
+ {"\\csl at aux@bibliography", 2},
+ {"\\@input", 1},
+}
+
+local balanced = lpeg.P{ "{" * ((1 - lpeg.S"{}") + lpeg.V(1))^0 * "}" }
+
+--- at param text string
+--- at param num_args integer?
+--- at return string[]
+local function get_command_arguments(text, command, num_args)
+ num_args = num_args or 1
+ local grammar = lpeg.P(command) * lpeg.Ct((lpeg.S(" \t\r\n")^0 * lpeg.C(balanced))^num_args)
+ local arguments = grammar:match(text)
+ if not arguments then
+ return {}
+ end
+ --- at cast arguments string[]
+ for i, argument in ipairs(arguments) do
+ arguments[i] = string.sub(argument, 2, -2)
+ end
+ return arguments
+end
+
+---Convert to a filter object described in
+--- <https://citeproc-js.readthedocs.io/en/latest/running.html#selective-output-with-makebibliography>
+--- at param filter_str string e.g., "type={book},notcategory={csl},notcategory={tex}"
+--- at return table
+function CslCitationManager:_parser_filter(filter_str)
+ local conditions = {}
+ for i, condition in ipairs(latex_parser.parse_seq(filter_str)) do
+ local negative
+ local field, value = string.match(condition, "(%w+)%s*=%s*{([^}]+)}")
+ if field then
+ if string.match(field, "^not") then
+ negative = true
+ field = string.gsub(field, "^not", "")
+ end
+ if field == "category" then
+ field = "categories"
+ end
+ if field == "keyword" or field == "type" or field == "categories" then
+ table.insert(conditions, {
+ field = field,
+ value = value,
+ negative = negative,
+ })
+ end
+ end
+ end
+ -- util.debug(conditions)
+ return {select = conditions}
+end
+
+
+
+--- at param aux_content string
+--- at return string
+function CslCitationManager:read_aux_file(aux_content)
+ local command_arguments = self:_get_csl_commands(aux_content)
+
+ -- First pass, only register infomation
+ for _, command_argument in ipairs(command_arguments) do
+ local command, ref_section_index, content = table.unpack(command_argument)
+
+ local ref_section = self.ref_sections[ref_section_index]
+ self.ref_section = ref_section
+ if not ref_section then
+ ref_section = RefSection:new()
+ self.ref_sections[ref_section_index] = ref_section
+ self.ref_section = ref_section
+ end
+ if command == "\\csl at aux@style" then
+ ref_section.style_id = content
+ elseif command == "\\csl at aux@data" then
+ util.extend(ref_section.bib_resources, util.split(content, "%s*,%s*"))
+ elseif command == "\\csl at aux@cite" then
+ self:register_citation_info(tostring(ref_section_index), content)
+ -- TODO: refsection bib resources
+ -- elseif command == "\\csl at aux@bibliography" then
+ -- -- table.insert(ref_section.bibliography_configs, content)
+ end
+ end
+
+ local global_style = self.global_ref_section.style_id
+ if global_style and global_style ~= "" then
+ util.info(string.format("Global style file: %s.csl", global_style))
+ else
+ util.warning("Missing global style name. Will use default APA style.")
+ self.global_ref_section.style_id = "apa"
+ end
+
+ -- if #citations == 0 then
+ -- util.error(string.format("No citation commands in file %s", aux_file))
+ -- end
+
+ -- if #bib_files == 0 then
+ -- util.warning("empty bibliography data files")
+ -- else
+ -- for i, bib_file in ipairs(bib_files) do
+ -- util.info(string.format("Database file #%d: %s", i, bib_file))
+ -- end
+ -- end
+
+ -- Second pass, only register infomation
+ local output_lines = {}
+ for _, command_argument in ipairs(command_arguments) do
+ local command, ref_section_index, content = table.unpack(command_argument)
+
+ local ref_section = self.ref_sections[ref_section_index]
+ assert(ref_section)
+ self.ref_section = ref_section
+
+ if command == "\\csl at aux@cite" then
+ if not ref_section.engine then
+ if not ref_section.style_id or ref_section.style_id == "" then
+ ref_section.style_id = self.global_ref_section.style_id
+ end
+ if #ref_section.bib_resources == 0 then
+ ref_section.bib_resources = self.global_ref_section.bib_resources
+ end
+ if not ref_section.lang or ref_section.lang == "" then
+ ref_section.lang = self.global_ref_section.lang
+ end
+ ref_section:make_citeproc_engine()
+ if self.hyperref_loaded then
+ ref_section.engine:enable_linking()
+ end
+ local style_class = ref_section.engine:get_style_class()
+ local style_class_setup = string.format("\\csloptions{%d}{class = {%s = %s}}", ref_section_index, ref_section.style_id, style_class)
+ table.insert(output_lines, style_class_setup)
+ end
+ self:register_citation_info(tostring(ref_section_index), content)
+ if ref_section.engine then
+ local citation = self:_make_citation(content)
+ local citation_str = ref_section.engine:process_citation(citation)
+
+ table.insert(output_lines, string.format("\\cslcitation{%s}{%s}", citation.citationID, citation_str))
+ end
+
+ elseif command == "\\csl at aux@bibliography" then
+ if not ref_section.engine then
+ ref_section:make_citeproc_engine()
+ end
+ if ref_section.engine then
+ local bib_lines = self:make_bibliography(content)
+ table.insert(output_lines, "")
+ util.extend(output_lines, bib_lines)
+ table.insert(output_lines, "")
+ end
+
+ elseif command == "\\csl at aux@options" then
+ local options = latex_parser.parse_prop(content)
+ if options.categories then
+ self:set_categories(options.categories)
+ end
+ if options.locale and options.locale ~= "" then
+ ref_section.lang = options.locale
+ end
+ -- TODO: == "true"?
+ if options.linking then
+ self.hyperref_loaded = true
+ end
+ end
+ end
+ return table.concat(output_lines, "\n") .. "\n"
+end
+
+--- at param aux_content string
+--- at return [string, integer, string][]
+function CslCitationManager:_get_csl_commands(aux_content)
+ --- at type [string, integer, string][]
+ local command_arguments = {}
+ for _, line in ipairs(util.split(aux_content, "%s*\n")) do
+ for _, command_argment in ipairs(command_info) do
+ local command, num_args = table.unpack(command_argment)
+ if util.startswith(line, command) then
+ local arguments = get_command_arguments(line, command, num_args)
+ if command == "\\@input" then
+ local sub_aux_file = arguments[1]
+ self:read_aux_file(sub_aux_file)
+ else
+ local ref_section_index = tonumber(arguments[1])
+ if not ref_section_index then
+ util.error(string.format("Invalid refsection index '%s'.", ref_section_index))
+ return {}
+ end
+ local content = util.strip(arguments[2])
+ table.insert(command_arguments, {command, ref_section_index, content})
+ end
+ break
+
+ end
+ end
+ end
+ return command_arguments
+end
+
+
+citeproc_manager.CslCitationManager = CslCitationManager
+
+return citeproc_manager
Property changes on: trunk/Master/texmf-dist/scripts/citation-style-language/citeproc-manager.lua
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Modified: trunk/Master/texmf-dist/scripts/citation-style-language/citeproc-node-choose.lua
===================================================================
--- trunk/Master/texmf-dist/scripts/citation-style-language/citeproc-node-choose.lua 2024-07-31 23:41:56 UTC (rev 71943)
+++ trunk/Master/texmf-dist/scripts/citation-style-language/citeproc-node-choose.lua 2024-08-01 19:56:55 UTC (rev 71944)
@@ -253,8 +253,8 @@
local variable = condition.value
local variable_type = util.variable_types[variable] or "standard"
- if variable_type ~= "standard" and variable_type ~= "number" then
- util.warning(string.format('Expecting number variable for condition "is-numeric", got %s "%s"', variable_type, variable))
+ if variable_type ~= "standard" and variable_type ~= "number" then
+ util.warning(string.format("Expecting number variable for condition 'is-numeric', got %s '%s'", variable_type, variable))
return false
end
@@ -263,7 +263,7 @@
return false
end
if type(value) ~= "string" and type(value) ~= "number" then
- util.error(string.format('Expecting a string or number for variable "%s", got "%s"', variable, type(value)))
+ util.error(string.format("Expecting a string or number for variable '%s', got '%s'", variable, type(value)))
end
return util.is_numeric(value)
@@ -273,7 +273,7 @@
local variable_type = util.variable_types[variable] or "standard"
if variable_type ~= "date" then
- util.warning(string.format('Expecting date variable for condition "is-uncertain-date", got "%s"', variable_type, variable))
+ util.warning(string.format("Expecting date variable for condition 'is-uncertain-date', got '%s'", variable_type, variable))
return false
end
local value = context:get_variable(variable)
@@ -283,6 +283,10 @@
return self:is_uncertain_date(value)
elseif condition.condition == "locator" then
+ local locator = context:get_variable("locator")
+ if not locator or locator == "" then
+ return false
+ end
local locator_label = context:get_variable("label")
if locator_label == "sub verbo" then
locator_label = "sub-verbo"
Modified: trunk/Master/texmf-dist/scripts/citation-style-language/citeproc-node-citation.lua
===================================================================
--- trunk/Master/texmf-dist/scripts/citation-style-language/citeproc-node-citation.lua 2024-07-31 23:41:56 UTC (rev 71943)
+++ trunk/Master/texmf-dist/scripts/citation-style-language/citeproc-node-citation.lua 2024-08-01 19:56:55 UTC (rev 71944)
@@ -41,6 +41,7 @@
local Formatted = output.Formatted
local PlainText = output.PlainText
local InlineElement = output.InlineElement
+local UndefinedCite = output.UndefinedCite
local CiteInline = output.CiteInline
local DisamStringFormat = output.DisamStringFormat
local SortStringFormat = output.SortStringFormat
@@ -470,7 +471,7 @@
if context.reference then
ir = self:build_ir(engine, state, context, active_layout)
else
- ir = Rendered:new({Formatted:new({PlainText:new(tostring(cite_item.id))}, {["font-weight"] = "bold"})}, self)
+ ir = Rendered:new({UndefinedCite:new({PlainText:new(tostring(cite_item.id))}, cite_item)}, self)
end
ir.cite_item = cite_item
Modified: trunk/Master/texmf-dist/scripts/citation-style-language/citeproc-node-names.lua
===================================================================
--- trunk/Master/texmf-dist/scripts/citation-style-language/citeproc-node-names.lua 2024-07-31 23:41:56 UTC (rev 71943)
+++ trunk/Master/texmf-dist/scripts/citation-style-language/citeproc-node-names.lua 2024-08-01 19:56:55 UTC (rev 71944)
@@ -131,7 +131,7 @@
child.after_name = true
end
else
- util.warning(string.format('Unknown element "%s".', element_name))
+ util.warning(string.format("Unknown element '%s'.", element_name))
end
end
o:get_delimiter_attribute(node)
Modified: trunk/Master/texmf-dist/scripts/citation-style-language/citeproc-node-number.lua
===================================================================
--- trunk/Master/texmf-dist/scripts/citation-style-language/citeproc-node-number.lua 2024-07-31 23:41:56 UTC (rev 71943)
+++ trunk/Master/texmf-dist/scripts/citation-style-language/citeproc-node-number.lua 2024-08-01 19:56:55 UTC (rev 71944)
@@ -59,8 +59,9 @@
local number
if not state.suppressed[self.variable] then
number = context:get_variable(self.variable, self.form)
+ --- at cast number string | number?
end
- if not number then
+ if not number or number == "" then
local ir = Rendered:new({}, self)
ir.group_var = GroupVar.Missing
return ir
Modified: trunk/Master/texmf-dist/scripts/citation-style-language/citeproc-node-sort.lua
===================================================================
--- trunk/Master/texmf-dist/scripts/citation-style-language/citeproc-node-sort.lua 2024-07-31 23:41:56 UTC (rev 71943)
+++ trunk/Master/texmf-dist/scripts/citation-style-language/citeproc-node-sort.lua 2024-08-01 19:56:55 UTC (rev 71944)
@@ -77,7 +77,7 @@
if uca_languages[language] then
Sort.collator = uca_languages[language](Sort.collator)
else
- util.warning(string.format('Locale "%s" is not provided by lua-uca. The sorting order may be incorrect.', lang))
+ util.warning(string.format("Locale '%s' is not provided by lua-uca. The sorting order may be incorrect.", lang))
end
end
end
Modified: trunk/Master/texmf-dist/scripts/citation-style-language/citeproc-node-text.lua
===================================================================
--- trunk/Master/texmf-dist/scripts/citation-style-language/citeproc-node-text.lua 2024-07-31 23:41:56 UTC (rev 71943)
+++ trunk/Master/texmf-dist/scripts/citation-style-language/citeproc-node-text.lua 2024-08-01 19:56:55 UTC (rev 71944)
@@ -86,6 +86,7 @@
if self.variable then
ir = self:build_variable_ir(engine, state, context)
elseif self.macro then
+ -- util.debug(self.macro)
ir = self:build_macro_ir(engine, state, context)
elseif self.term then
ir = self:build_term_ir(engine, state, context)
@@ -108,9 +109,10 @@
if not state.suppressed[variable] then
text = context:get_variable(variable, self.form)
+ --- at case text string | number?
end
- if not text then
+ if not text or text == "" then
local ir = Rendered:new({}, self)
ir.group_var = GroupVar.Missing
return ir
Modified: trunk/Master/texmf-dist/scripts/citation-style-language/citeproc-output.lua
===================================================================
--- trunk/Master/texmf-dist/scripts/citation-style-language/citeproc-output.lua 2024-07-31 23:41:56 UTC (rev 71943)
+++ trunk/Master/texmf-dist/scripts/citation-style-language/citeproc-output.lua 2024-08-01 19:56:55 UTC (rev 71944)
@@ -93,19 +93,28 @@
end
-function InlineElement:_debug()
- local text = self._type .. "("
+function InlineElement:_debug(level)
+ level = level or 0
+ local text = ""
+ if level == 0 then
+ text = "\n"
+ end
+ text = text .. self._type
+ if self.formatting then
+ text = text .. "["
+ for attr, value in pairs(self.formatting) do
+ text = text .. attr .. '="' .. value .. '"'
+ end
+ text = text .. "]"
+ end
+ text = text .. "("
if self.value then
text = text .. '"' .. self.value .. '"'
elseif self.inlines then
- local inlines_text = ""
for _, inline in ipairs(self.inlines) do
- if inlines_text ~= "" then
- inlines_text = inlines_text .. ", "
- end
- inlines_text = inlines_text .. inline:_debug()
+ text = text .. "\n" .. string.rep(" ", level + 1) .. inline:_debug(level + 1) .. ", "
end
- text = text .. inlines_text
+ text = text .. "\n" .. string.rep(" ", level)
end
text = text .. ")"
return text
@@ -292,6 +301,23 @@
end
+--- at class UndefinedCite: InlineElement
+--- at field cite_item CitationItem
+local UndefinedCite = InlineElement:derive("UndefinedCite")
+
+--- at param inlines InlineElement[]
+--- at param cite_item CitationItem
+--- at return UndefinedCite
+function UndefinedCite:new(inlines, cite_item)
+ local o = InlineElement.new(self)
+ o.inlines = inlines
+ o.cite_item = cite_item
+ setmetatable(o, self)
+ return o
+end
+
+
+
--- at param text string
--- at param context Context?
--- at param is_external boolean?
@@ -864,6 +890,7 @@
or util.is_instance(inline, NoCase)
or util.is_instance(inline, NoDecor)
or util.is_instance(inline, CiteInline)
+ or util.is_instance(inline, UndefinedCite)
or (util.is_instance(inline, Formatted)
and inline.formatting["font-variant"] ~= "small-caps"
and inline.formatting["vertical-align"] ~= "sup"
@@ -953,7 +980,8 @@
(inline._type == "Formatted" and inline.formatting["vertical-align"] == "sub") then
seen_one = seen_one or inline_contains_word(inline)
- elseif inline._type == "Formatted" or inline._type == "Quoted" or inline._type == "CiteInline" then
+ elseif inline._type == "Formatted" or inline._type == "Quoted"
+ or inline._type == "CiteInline" or inline._type == "UndefinedCite" then
seen_one = self:apply_text_case_inner(inline.inlines, text_case, seen_one, is_uppercase) or seen_one
end
@@ -1273,7 +1301,6 @@
elseif inline._type == "Code" or
inline._type == "MathML" or
inline._type == "MathTeX" then
- return
elseif inline.inlines then -- Div, ...
self:flip_flop(inline.inlines, state)
@@ -1336,7 +1363,6 @@
elseif inline._type == "Code" or
inline._type == "MathML" or
inline._type == "MathTeX" then
- return
elseif inline.inlines then -- Div, ...
self:flip_flop_micro_inlines(inline.inlines, state)
@@ -1475,8 +1501,8 @@
idx = idx + 1
end
- elseif (first._type == "Formatted" or first._type == "CiteInline")
- and second._type == "PlainText" then
+ elseif (first._type == "Formatted" or first._type == "CiteInline"
+ or first._type == "UndefinedCite") and second._type == "PlainText" then
local success = smash_just_punc(first, second)
if success then
if second.value == "" then
@@ -1572,7 +1598,8 @@
for _, inline in ipairs(inlines) do
if inline._type == "Quoted" or inline._type == "Formatted" or
- inline._type == "Div" or inline._type == "CiteInline" then
+ inline._type == "Div" or inline._type == "CiteInline"
+ or inline._type == "UndefinedCite" then
self:move_punctuation(inline.inlines)
end
end
@@ -1635,6 +1662,9 @@
elseif inline._type == "CiteInline" then
return self:write_cite(inline, context)
+ elseif inline._type == "UndefinedCite" then
+ return self:write_undefined_cite(inline, context)
+
elseif inline._type == "Code" then
return self:write_code(inline, context)
@@ -1686,6 +1716,11 @@
return self:write_inlines(inline.inlines, context)
end
+function Markup:write_undefined_cite(inline, context)
+ local bold_inline = Formatted:new({PlainText:new(inline.cite_item.id)}, {["font-weight"] = "bold"})
+ return self:write_formatted(bold_inline, context)
+end
+
function Markup:write_code(inline, context)
return inline.value
end
@@ -1831,6 +1866,10 @@
return str
end
+function LatexWriter:write_undefined_cite(inline, context)
+ return string.format("\\cslundefinedcite{%s}", inline.cite_item.id)
+end
+
function LatexWriter:write_code(inline, context)
return inline.value
end
@@ -2155,6 +2194,7 @@
output_module.Linked = Linked
output_module.Div = Div
output_module.CiteInline = CiteInline
+output_module.UndefinedCite = UndefinedCite
output_module.Code = Code
output_module.MathTeX = MathTeX
output_module.MathTML = MathML
Modified: trunk/Master/texmf-dist/scripts/citation-style-language/citeproc-util.lua
===================================================================
--- trunk/Master/texmf-dist/scripts/citation-style-language/citeproc-util.lua 2024-07-31 23:41:56 UTC (rev 71943)
+++ trunk/Master/texmf-dist/scripts/citation-style-language/citeproc-util.lua 2024-08-01 19:56:55 UTC (rev 71944)
@@ -78,7 +78,7 @@
elseif str == "false" then
return false
else
- util.warning(string.format('Invalid boolean string "%s"', str))
+ util.warning(string.format("Invalid boolean string '%s'", str))
return false
end
end
@@ -133,7 +133,7 @@
function util.set_logging_file(path)
util.logging_file = io.open(path, "w")
if not util.logging_file then
- util.error(string.format('Cannot write to "%s".', path))
+ util.error(string.format("Cannot write to '%s'.", path))
end
util.logging_file = io.open(path, 'a')
end
@@ -150,20 +150,24 @@
util.num_warnings = 0
+--- at param message string
function util.error(message)
util.num_errors = util.num_errors + 1
if luatexbase then
- -- The luatexbase.module_error() prints the traceback, which causes panic
- -- luatexbase.module_error("citeproc", message)
-
- -- TODO: Enhance the error output. Make it like `\msg_error`.
- texio.write_nl("term", "\n")
- tex.error("Module citeproc Error: " .. message)
-
- -- tex.print(string.format("\\PackageError{citation-style-language}{%s}{}", message))
-
+ -- Run in LuaLaTeX
+ tex.print(string.format("\\csname msg_error:nnn\\endcsname{citeproc}{citeproc-error}{%s}", message))
+ -- Don't use the following methods.
+ -- `error()` prints long traceback when run in LuaLaTeX.
+ -- texio.write_nl("term", "\n")
+ -- `tex.error()` prints annoying `\lua_now:e #1->` when called from LaTeX3 interface.
+ -- `luatexbase.module_error()` prints traceback.
+ -- tex.print(string.format("\\PackageError{CSL}{%s}{}", message))
else
- message = "Error: " .. message
+ -- Run in citeproc-lua script
+ -- This format is used by latexmk. DO NOT change.
+ message = "Error: " .. message
+ -- Following bibtex and biber, the error message is printed to stdout rather than stderr.
+ -- And the error doesn't break the execution of the script.
print(message)
if util.logging_file then
util.logging_file:write(message .. "\n")
@@ -176,12 +180,10 @@
function util.warning(message)
util.num_warnings = util.num_warnings + 1
if luatexbase then
- texio.write_nl("term", "\n")
- luatexbase.module_warning("citeproc", message)
+ tex.print(string.format("\\csname msg_warning:nnn\\endcsname{citeproc}{citeproc-warning}{%s}", message))
- -- tex.print(string.format("\\PackageWarning{citation-style-language}{%s}{}", message))
-
else
+ -- This format is used by latexmk. DO NOT change.
message = "Warning: " .. message
if util.logging_file then
util.logging_file:write(message .. "\n")
@@ -207,8 +209,15 @@
function util.debug(obj)
local text
- if type(obj) == "table" and obj._debug then
- text = obj:_debug()
+ if type(obj) == "table" and (obj._debug or (obj[1] and obj[1]._debug)) then
+ if obj._debug then
+ text = obj:_debug()
+ else
+ text = ""
+ for _, child in ipairs(obj) do
+ text = text .. child:_debug()
+ end
+ end
else
if not inspect then
inspect = require("inspect")
@@ -243,6 +252,9 @@
if sep == "" then
util.error("Empty separator")
end
+ if str == "" then
+ return {}
+ end
if string.find(str, sep) == nil then
return { str }
end
@@ -368,6 +380,8 @@
return res
end
+--- at param str string
+--- at return string
function util.lstrip (str)
if not str then
error("Invalid input")
@@ -376,6 +390,21 @@
return res
end
+--- at param str string
+--- at param prefix string
+--- at return string
+function util.remove_prefix(str, prefix)
+ if type(str) ~= "string" or type(prefix) ~= "string" then
+ error("Invalid input")
+ end
+ if util.startswith(str, prefix) then
+ return string.sub(str, #prefix + 1)
+ end
+ return str
+end
+
+--- at param str string
+--- at return string
function util.rstrip (str)
if not str then
error("Invalid input")
@@ -384,6 +413,8 @@
return res
end
+--- at param str string
+--- at return string
function util.strip (str)
return util.lstrip(util.rstrip(str))
end
@@ -390,7 +421,7 @@
function util.startswith(str, prefix)
if type(str) ~= "string" then
- util.error(string.format('\n%s\n"%s" is not a string.', debug.traceback(), str))
+ util.error(string.format("\n%s\n'%s' is not a string.", debug.traceback(), str))
end
return string.sub(str, 1, #prefix) == prefix
end
@@ -1140,7 +1171,7 @@
local file = io.open(path, "r")
if not file then
if not allowe_missing then
- util.error(string.format('Cannot open file "%s".', path))
+ util.error(string.format("Cannot open file '%s'.", path))
end
return nil
end
@@ -1156,7 +1187,7 @@
function util.write_file(text, path)
local file = io.open(path, "w")
if not file then
- util.error(string.format('Cannot write to file "%s".', path))
+ util.error(string.format("Cannot write to file '%s'.", path))
return
end
file:write(text)
@@ -1286,7 +1317,7 @@
--- at return { authors: integer[], year: integer }
function util.get_trigraph_param(trigraph)
if not trigraph or string.sub(trigraph, 1, 1) ~= "A" then
- util.error(string.format('Bad trigraph definition: "%s"', trigraph))
+ util.error(string.format("Bad trigraph definition: '%s'", trigraph))
end
local param = {
authors = {},
@@ -1303,7 +1334,7 @@
elseif char == "0" then
param.year = param.year + 1
else
- util.error(string.format('Invalid character "%s" in trigraph definition "%s"', char, trigraph))
+ util.error(string.format("Invalid character '%s' in trigraph definition '%s'", char, trigraph))
end
end
return param
Modified: trunk/Master/texmf-dist/scripts/citation-style-language/citeproc.lua
===================================================================
--- trunk/Master/texmf-dist/scripts/citation-style-language/citeproc.lua 2024-07-31 23:41:56 UTC (rev 71943)
+++ trunk/Master/texmf-dist/scripts/citation-style-language/citeproc.lua 2024-08-01 19:56:55 UTC (rev 71944)
@@ -16,7 +16,7 @@
util = require("citeproc.util")
end
-citeproc.__VERSION__ = "0.5.0"
+citeproc.__VERSION__ = "0.6.0"
citeproc.new = engine.CiteProc.new
citeproc.util = util
Modified: trunk/Master/texmf-dist/tex/latex/citation-style-language/citation-style-language-bib.sty
===================================================================
--- trunk/Master/texmf-dist/tex/latex/citation-style-language/citation-style-language-bib.sty 2024-07-31 23:41:56 UTC (rev 71943)
+++ trunk/Master/texmf-dist/tex/latex/citation-style-language/citation-style-language-bib.sty 2024-08-01 19:56:55 UTC (rev 71944)
@@ -34,7 +34,7 @@
\__csl_collect_bibliography:n
{
\lua_now:e
- { csl.bibliography("\l__csl_bib_filter_tl") }
+ { csl_citation_manager:bibliography("\l__csl_bib_filter_tl") }
}
}
}
@@ -53,11 +53,11 @@
}
\tl_use:N \l__csl_bibliography_tl
}
- { \msg_warning:nn { citation-style-language } { bibliography / empty } }
+ { \msg_warning:nn { citation-style-language } { empty-bibliography } }
\group_end:
}
-\msg_new:nnn { citation-style-language } { bibliography / empty }
+\msg_new:nnn { citation-style-language } { empty-bibliography }
{ The~ bibliography~ is~ empty. }
\DeclareDocumentCommand \bibliography { m }
@@ -108,11 +108,16 @@
\cs_new:Npn \__csl_write_aux_bibliography:n #1
{
\if at filesw
- \iow_now:Nn \@auxout { \csl at aux@bibliography {#1} }
+ \iow_now:Nx \@auxout
+ {
+ \token_to_str:N \csl at aux@bibliography
+ { \int_use:N \g__csl_ref_section_index_int }
+ {#1}
+ }
\fi
}
-\cs_new:Npn \csl at aux@bibliography #1 { }
+\cs_new:Npn \csl at aux@bibliography #1#2 { }
\tl_new:N \l__csl_bib_index_tl
@@ -182,7 +187,7 @@
}
{
\tl_set:Nn \@noitemerr
- { \msg_warning:nn { citation-style-language } { bibliography / empty } }
+ { \msg_warning:nn { citation-style-language } { empty-bibliography } }
\endlist
\group_end:
\exp_args:NV \__csl_print_bib_note:n \l__csl_bib_post_note_tl
@@ -355,6 +360,96 @@
}
+% ### Bibliography sections and segments
+
+
+\int_new:N \g__csl_ref_section_index_int
+\int_new:N \g__csl_max_ref_section_index_int
+\int_gset:Nn \g__csl_ref_section_index_int { 0 }
+\int_gset:Nn \g__csl_max_ref_section_index_int { 0 }
+
+\keys_define:nn { csl / ref-section }
+ {
+ style .code:n =
+ {
+ \tl_set:Nn \l__csl_style_tl {#1}
+ \renewcommand \csl at style {#1}
+ } ,
+ bib-resource .clist_set:N = \l__csl_bib_resources_clist ,
+ locale .tl_set:N = \l__csl_locale_tl ,
+ }
+
+\NewDocumentCommand \refsection { O { } }
+ {
+ \int_gincr:N \g__csl_max_ref_section_index_int
+ \int_gset_eq:NN \g__csl_ref_section_index_int \g__csl_max_ref_section_index_int
+
+ \tl_clear:N \l__csl_style_tl
+ \clist_clear:N \l__csl_bib_resources_clist
+ \tl_clear:N \l__csl_locale_tl
+ \keys_set:nn { csl / ref-section } { #1 }
+ \tl_if_empty:NTF \l__csl_style_tl
+ {
+ \tl_set_eq:NN \l__csl_style_tl \g__csl_global_style_tl
+ \tl_set_eq:NN \csl at style \l__csl_style_tl
+ }
+ {
+ \tl_set_eq:NN \csl at style \l__csl_style_tl
+ \exp_args:NV \__csl_write_aux_bibstyle:n \l__csl_style_tl
+ }
+ \clist_if_empty:NF \l__csl_bib_resources_clist
+ % { \clist_set_eq:NN \l__csl_bib_resources_clist \g__csl_global_bib_resources_clist }
+ {
+ \exp_args:Nx \__csl_write_aux_bibdata:n
+ { \clist_use:Nn \l__csl_bib_resources_clist { , } }
+ }
+ \tl_if_empty:NTF \l__csl_locale_tl
+ { \tl_set_eq:NN \l__csl_locale_tl \g__csl_global_locale_tl }
+ {
+ \exp_args:Nx \__csl_write_aux_options:n
+ { locale = \l__csl_locale_tl }
+ }
+ \sys_if_engine_luatex:TF
+ {
+ \lua_now:e
+ {
+ csl_citation_manager:begin_ref_section(
+ "\l__csl_style_tl",
+ "\clist_use:Nn \l__csl_bib_resources_clist { , }",
+ "\l__csl_locale_tl"
+ )
+ }
+ \str_if_eq:eeTF
+ {
+ \lua_now:n
+ {
+ tex.print(tostring(
+ csl_citation_manager.ref_section.initialized
+ ))
+ }
+ }
+ { true }
+ { \bool_set_true:N \l__csl_engine_initialized_bool }
+ { \bool_set_false:N \l__csl_engine_initialized_bool }
+ \__csl_get_style_class_luatex:
+ }
+ {
+ \__csl_get_style_class:
+ }
+ }
+
+\cs_set_eq:NN \newrefsection \refsection
+
+\cs_new:Npn \endrefsection {
+ \int_compare:nNnT { \g__csl_ref_section_index_int } > { 0 }
+ {
+ \int_gzero:N \g__csl_ref_section_index_int
+ \sys_if_engine_luatex:T
+ { \lua_now:n { csl_citation_manager:end_ref_section() } }
+ }
+}
+
+
% ### Bibliography Headings and Environments
\prop_new:N \l__csl_bib_env_begin_prop
@@ -381,7 +476,7 @@
{
\cs_if_exist:cF { __csl_head_ #1 :n }
{
- \msg_error:nnn { citation-style-language } { bib-heading-undefined }
+ \msg_error:nnn { citation-style-language } { undefined-bib-heading }
{#1}
}
\tl_if_blank:nTF {#2}
@@ -393,7 +488,7 @@
{ \exp_args:NV \label \l__csl_bib_head_label_tl }
}
-\msg_new:nnn { citation-style-language } { bib-heading-undefined }
+\msg_new:nnn { citation-style-language } { undefined-bib-heading }
{ Bibliography~ heading~ '#1'~ undefined. }
\keys_define:nn { csl / bib-heading }
@@ -426,6 +521,10 @@
\expandafter \newcommand \csname __csl_head_ #1 :n \endcsname [1] [ {#2} ]
}
+
+\cs_if_exist:NF \refname
+ { \cs_set:Npn \refname { References } }
+
\cs_if_exist:NTF \chapter
{
% `book` or `report`
@@ -437,19 +536,19 @@
\defbibheading { biblist } [ \biblistname ]
{
\chapter* {#1}
- \@mkboth { \MakeMarkcase {#1} } { \MakeMarkcase {#1} }
+ \@mkboth { \MakeUppercase {#1} } { \MakeUppercase {#1} }
}
\defbibheading { bibintoc } [ \bibname ]
{
\chapter* {#1}
\addcontentsline { toc } { chapter } {#1}
- \@mkboth { \MakeMarkcase {#1} } { \MakeMarkcase {#1} }
+ \@mkboth { \MakeUppercase {#1} } { \MakeUppercase {#1} }
}
\defbibheading { biblistintoc } [ \biblistname ]
{
\chapter* {#1}
\addcontentsline { toc } { chapter } {#1}
- \@mkboth { \MakeMarkcase {#1} } { \MakeMarkcase {#1} }
+ \@mkboth { \MakeUppercase {#1} } { \MakeUppercase {#1} }
}
\defbibheading { bibnumbered } [ \bibname ]
{ \chapter {#1} }
@@ -459,7 +558,7 @@
{
\section* {#1}
\if at twoside
- \markright { \MakeMarkcase {#1} }
+ \markright { \MakeUppercase {#1} }
\fi
}
\defbibheading { subbibintoc } [ \refname ]
@@ -467,7 +566,7 @@
\section* {#1}
\addcontentsline { toc } { section } {#1}
\if at twoside
- \markright { \MakeMarkcase {#1} }
+ \markright { \MakeUppercase {#1} }
\fi
}
\defbibheading { subbibnumbered } [ \refname ]
@@ -483,19 +582,19 @@
\defbibheading { biblist } [ \biblistname ]
{
\section* {#1}
- \@mkboth { \MakeMarkcase {#1} } { \MakeMarkcase {#1} }
+ \@mkboth { \MakeUppercase {#1} } { \MakeUppercase {#1} }
}
\defbibheading { bibintoc } [ \refname ]
{
\section* {#1}
\addcontentsline { toc } { section } {#1}
- \@mkboth { \MakeMarkcase {#1} } { \MakeMarkcase {#1} }
+ \@mkboth { \MakeUppercase {#1} } { \MakeUppercase {#1} }
}
\defbibheading { biblistintoc } [ \biblistname ]
{
\section* {#1}
\addcontentsline { toc } { section } {#1}
- \@mkboth { \MakeMarkcase {#1} } { \MakeMarkcase {#1} }
+ \@mkboth { \MakeUppercase {#1} } { \MakeUppercase {#1} }
}
\defbibheading { bibnumbered } [ \refname ]
{ \section {#1} }
@@ -531,7 +630,7 @@
{
\prop_get:NnNF \l__csl_bib_notes_prop {#1} \l_tmpa_tl
{
- \msg_error:nnn { citation-style-language } { bib-note-undefined }
+ \msg_error:nnn { citation-style-language } { undefined-bib-note }
{#1}
}
\tl_if_empty:NF \l_tmp_tl
@@ -547,7 +646,7 @@
}
}
-\msg_new:nnn { citation-style-language } { bib-note-undefined }
+\msg_new:nnn { citation-style-language } { undefined-bib-note }
{ Bibliography~ note~ '#1'~ undefined. }
@@ -593,7 +692,7 @@
\tl_put_right:Nn \l_tmpa_tl { ##1 = {##2} }
}
\sys_if_engine_luatex:T
- { \lua_now:e { csl.set_categories("\l_tmpa_tl") } }
+ { \lua_now:e { csl_citation_manager:set_categories("\l_tmpa_tl") } }
{
\tl_put_left:Nx \l_tmpa_tl { categories = \c_left_brace_str }
\tl_put_right:NV \l_tmpa_tl \c_right_brace_str
Modified: trunk/Master/texmf-dist/tex/latex/citation-style-language/citation-style-language-cite.sty
===================================================================
--- trunk/Master/texmf-dist/tex/latex/citation-style-language/citation-style-language-cite.sty 2024-07-31 23:41:56 UTC (rev 71943)
+++ trunk/Master/texmf-dist/tex/latex/citation-style-language/citation-style-language-cite.sty 2024-08-01 19:56:55 UTC (rev 71944)
@@ -246,10 +246,17 @@
\cs_new:Npn \__csl_set_locator:nn #1#2
{
- \prop_put:Nnn \l__csl_cite_item_prop { label } {#1}
- \prop_put:Nnn \l__csl_cite_item_prop { locator } {#2}
+ \tl_if_empty:nTF {#2}
+ { \msg_warning:nnn { citation-style-language } { empty-locator } {#1} }
+ {
+ \prop_put:Nnn \l__csl_cite_item_prop { label } {#1}
+ \prop_put:Nnn \l__csl_cite_item_prop { locator } {#2}
+ }
}
+\msg_new:nnn { citation-style-language } { empty-locator }
+ { Empty~ '#1'~ locator. }
+
\keys_define:nn { csl / cite-item }
{
prefix .prop_put:N = \l__csl_cite_item_prop,
@@ -376,7 +383,7 @@
\__csl_serialize_prop:NN \l__csl_citation_info_prop \l__csl_citation_info_tl
% Write to .aux file
% \tl_show:N \l__csl_citation_info_tl
- \exp_args:NV \__csl_write_aux_citation:n \l__csl_citation_info_tl
+ \exp_args:NVV \__csl_write_aux_citation:nn \g__csl_ref_section_index_int \l__csl_citation_info_tl
\bool_if:NT \l__csl_regression_test_bool
{ \tl_show:N \l__csl_citation_info_tl }
% Print the citation string
@@ -404,7 +411,7 @@
}
\cs_new:Npn \__csl_cite_aux:n #1
- { \lua_now:e { csl.cite("\lua_escape:n {#1}") } }
+ { \lua_now:e { csl_citation_manager:cite("\lua_escape:n {#1}") } }
% #1: seq
% #2: tl
@@ -488,11 +495,12 @@
}
-\cs_new:Npn \__csl_write_aux_citation:n #1
- % #1: citation info "{<citationID>}{{id=ITEM-1},{id=ITEM-2}}{<noteIndex>}"
+\cs_new:Npn \__csl_write_aux_citation:nn #1#2
+ % #1: refsection index (already converted to tl)
+ % #2: citation info "{<citationID>}{{id=ITEM-1},{id=ITEM-2}}{<noteIndex>}"
{
\if at filesw
- \iow_now:Nn \@auxout { \csl at aux@cite {#1} }
+ \iow_now:Nn \@auxout { \csl at aux@cite {#1} {#2} }
\fi
}
@@ -550,8 +558,8 @@
\tl_set:Nn \l__csl_citation_tl { [ \textbf {#1} ] }
}
-% \msg_new:nnn { citation-style-language } { citation / undefined }
-% { Citation~ `#1'~ on~ page~ \thepage \space undefined~ \msg_line_context: . }
+% \msg_new:nnn { citation-style-language } { undefined-citation }
+% { Citation~ '#1'~ on~ page~ \thepage \space undefined~ \msg_line_context: . }
\cs_new:Npn \__csl_warn_citation_undefined:n #1
{
@@ -580,9 +588,9 @@
}
\bool_if:NT \l__csl_regression_test_bool
{ \tl_show:N \l__csl_citation_info_tl }
- \exp_args:NV \__csl_no_cite_write_aux:n \l__csl_citation_info_tl
+ \exp_args:NVV \__csl_no_cite_write_aux:nn \g__csl_ref_section_index_int \l__csl_citation_info_tl
\sys_if_engine_luatex:T
- { \lua_now:n { csl.nocite("#1") } }
+ { \lua_now:n { csl_citation_manager:nocite("#1") } }
\tl_clear:N \l__csl_citation_tl
\bool_if:NT \l__csl_regression_test_bool
{ \tl_show:N \l__csl_citation_tl }
@@ -589,14 +597,14 @@
}
-\cs_new:Npn \__csl_no_cite_write_aux:n #1
+\cs_new:Npn \__csl_no_cite_write_aux:nn #1#2
{
\__csl_if_preamble:TF
{
\hook_gput_code:nnn { begindocument } { . }
- { \exp_args:Nx \__csl_write_aux_citation:n { #1 } }
+ { \__csl_write_aux_citation:nn {#1} {#2} }
}
- { \exp_args:Nx \__csl_write_aux_citation:n { #1 } }
+ { \__csl_write_aux_citation:nn {#1} {#2} }
}
@@ -612,10 +620,10 @@
% Used in aux files to register cite items.
% #1: a citation object
-\cs_set:Npn \csl at aux@cite #1
+\cs_set:Npn \csl at aux@cite #1#2
{
\sys_if_engine_luatex:T
- { \lua_now:e { csl.register_citation_info("\lua_escape:n {#1}") } }
+ { \lua_now:e { csl_citation_manager:register_citation_info(#1, "\lua_escape:n {#2}") } }
}
@@ -627,3 +635,10 @@
% #1: cite id
% #2: cite contents
\cs_new:Npn \cslcite #1#2 {#2}
+
+% This command is for use with hyperref.
+% #1: cite id
+\cs_new:Npn \cslundefinedcite #1 {
+ \textbf {#1}
+ \__csl_warn_citation_undefined:n {#1}
+}
Modified: trunk/Master/texmf-dist/tex/latex/citation-style-language/citation-style-language-compatible.sty
===================================================================
--- trunk/Master/texmf-dist/tex/latex/citation-style-language/citation-style-language-compatible.sty 2024-07-31 23:41:56 UTC (rev 71943)
+++ trunk/Master/texmf-dist/tex/latex/citation-style-language/citation-style-language-compatible.sty 2024-08-01 19:56:55 UTC (rev 71944)
@@ -98,25 +98,33 @@
% ### `hyperref`
\cs_set:Npn \__csl_hyperref_cite_item:nn #1#2
- { \hyper@@link [ cite ] { } { cite. #1 \@extra at b@citeb } { #2 } }
+ {
+ \hyper@@link [ cite ] { }
+ { cite \int_use:N \g__csl_ref_section_index_int . #1 \@extra at b@citeb } { #2 }
+ }
\cs_new:Npn \__csl_hyperref_lbibitem:nn [#1]#2
{
\clist_gput_right:Nn \g__csl_bib_items_clist {#2}
\@skiphyperreftrue
- \H at item[%
- \ifx\Hy at raisedlink\@empty
- \hyper at anchorstart{cite.#2\@extra at b@citeb}%
- \@BIBLABEL{#1}%
- \hyper at anchorend
- \else
- \Hy at raisedlink{%
- \hyper at anchorstart{cite.#2\@extra at b@citeb}\hyper at anchorend
- }%
- \@BIBLABEL{#1}%
- \fi
- \hfill
- ]%
+ \H at item
+ [
+ \ifx \Hy at raisedlink \@empty
+ \hyper at anchorstart
+ { cite \int_use:N \g__csl_ref_section_index_int . #2 \@extra at b@citeb }
+ \@BIBLABEL {#1}
+ \hyper at anchorend
+ \else
+ \Hy at raisedlink
+ {
+ \hyper at anchorstart
+ { cite \int_use:N \g__csl_ref_section_index_int . #2 \@extra at b@citeb }
+ \hyper at anchorend
+ }
+ \@BIBLABEL {#1}
+ \fi
+ \hfill
+ ]
\@skiphyperreffalse
\ignorespaces
}
@@ -128,7 +136,8 @@
\Hy at raisedlink
{
\hyper at anchorstart
- { cite. #1 \@extra at b@citeb } \relax
+ { cite \int_use:N \g__csl_ref_section_index_int . #1 \@extra at b@citeb }
+ \relax
\hyper at anchorend
}
\ignorespaces
Modified: trunk/Master/texmf-dist/tex/latex/citation-style-language/citation-style-language-init.sty
===================================================================
--- trunk/Master/texmf-dist/tex/latex/citation-style-language/citation-style-language-init.sty 2024-07-31 23:41:56 UTC (rev 71943)
+++ trunk/Master/texmf-dist/tex/latex/citation-style-language/citation-style-language-init.sty 2024-08-01 19:56:55 UTC (rev 71944)
@@ -16,8 +16,9 @@
{ \__csl_initialize_lua_module: }
{
\__csl_load_bbl:
- \__csl_read_style_class:
+ \__csl_get_style_class:
}
+ \__csl_set_ref_section_level:
}
@@ -25,19 +26,20 @@
\cs_new:Npn \__csl_write_aux_info:
{
+ \tl_if_empty:NF \l__csl_style_tl
+ { \exp_args:NV \__csl_write_aux_bibstyle:n \l__csl_style_tl }
\tl_if_empty:NT \l__csl_style_tl
+ { \tl_set_eq:NN \l__csl_style_tl \g__csl_aux_bibstyle_tl }
+ \tl_if_empty:NT \l__csl_style_tl
{
- \tl_set_eq:NN \l__csl_style_tl \g__csl_aux_bibstyle_tl
- \edef \csl at style { \g__csl_aux_bibstyle_tl }
- }
- \tl_if_empty:VTF \l__csl_style_tl
- {
\msg_warning:nn { citation-style-language } { missing-style-name }
\tl_set:Nn \l__csl_style_tl { apa }
}
- { \exp_args:NV \__csl_write_aux_bibstyle:n \l__csl_style_tl }
+ \tl_set_eq:NN \csl at style \l__csl_style_tl
+ \clist_if_empty:NT \l__csl_bib_resources_clist
+ { \clist_set_eq:NN \l__csl_bib_resources_clist \g__csl_aux_bib_files_clist }
\clist_if_empty:NTF \l__csl_bib_resources_clist
- { \clist_set_eq:NN \l__csl_bib_resources_clist \g__csl_aux_bib_files_clist }
+ { \msg_warning:nn { citation-style-language } { empty-bib-resources } }
{
\exp_args:Nx \__csl_write_aux_bibdata:n
{ \clist_use:Nn \l__csl_bib_resources_clist { , } }
@@ -48,7 +50,11 @@
\cs_new:Npn \__csl_write_aux_bibstyle:n #1
{
\if at filesw
- \iow_now:Nx \@auxout { \token_to_str:N \csl at aux@style {#1} }
+ \iow_now:Nx \@auxout
+ {
+ \token_to_str:N \csl at aux@style
+ { \int_use:N \g__csl_ref_section_index_int } {#1}
+ }
\fi
}
@@ -56,7 +62,11 @@
{
\if at filesw
% Full expansion for files like \jobname.bib
- \iow_now:Nx \@auxout { \token_to_str:N \csl at aux@data {#1} }
+ \iow_now:Nx \@auxout
+ {
+ \token_to_str:N \csl at aux@data
+ { \int_use:N \g__csl_ref_section_index_int } {#1}
+ }
\fi
}
@@ -63,35 +73,45 @@
% In earlier time, \bibdata{xxx.json} was used but this causes latexmk unable
% to find xxx.json.bib and it refuses to run the $bibtex procedure.
% John Collins suggests using a different command than \bibdata.
-\cs_new:Npn \csl at aux@data #1
- { \clist_gput_right:Nn \g__csl_aux_bib_files_clist {#1} }
+\cs_new:Npn \csl at aux@data #1#2
+ {
+ \str_if_eq:nnT {#1} { 0 }
+ { \clist_gput_right:Nn \g__csl_aux_bib_files_clist {#2} }
+ }
\cs_new:Npn \__csl_initialize_lua_module:
{
- \clist_if_empty:NT \l__csl_bib_resources_clist
- { \msg_warning:nn { citation-style-language } { empty-bib-resources } }
+ \tl_set:Nx \l_tmpa_tl { \clist_use:Nn \l__csl_bib_resources_clist { , } }
\lua_now:e
{
- csl.init(
+ csl_citation_manager:init(
"\l__csl_style_tl",
- "\l__csl_bib_resources_clist",
+ "\l_tmpa_tl",
"\l__csl_locale_tl"
)
}
-
-
- \str_if_eq:eeT { \lua_now:n { tex.print(csl.initialized) } } { true }
+ \str_if_eq:eeTF
+ {
+ \lua_now:n
+ {
+ tex.print(tostring(
+ csl_citation_manager.ref_section.initialized
+ ))
+ }
+ }
+ { true }
{ \bool_set_true:N \l__csl_engine_initialized_bool }
- \__csl_get_style_class:
+ { \bool_set_false:N \l__csl_engine_initialized_bool }
+ \__csl_get_style_class_luatex:
\@ifpackageloaded { hyperref }
- { \lua_now:n { csl.enable_linking() } }
+ { \lua_now:n { csl_citation_manager:enable_linking() } }
{ }
}
\msg_new:nnn { citation-style-language } { missing-style-name }
- { Missing~ style~ name.\\Will~ use~ default~ APA~ style. }
+ { Missing~ style~ name.~ Will~ use~ default~ APA~ style. }
\msg_new:nnn { citation-style-language } { empty-bib-resources }
{ Empty~ bibliographic~ resources.~ Use~ \token_to_str:N \addbibresource. }
@@ -101,13 +121,16 @@
% In-text (including numeric or author-date) or note style
% \bool_new:N \l__csl_note_style_bool
-\cs_new:Npn \__csl_get_style_class: {
+\cs_new:Npn \__csl_get_style_class_luatex: {
+ \bool_set_false:N \l__csl_note_bool
\bool_if:NT \l__csl_engine_initialized_bool
{
- \tl_set:Nx \l__csl_class_tl { \lua_now:n { csl.get_style_class() } }
+ \tl_set:Nx \l__csl_class_tl { \lua_now:n { tex.print(csl_citation_manager:get_style_class()) } }
\tl_if_eq:NnT \l__csl_class_tl { note }
{ \bool_set_true:N \l__csl_note_bool }
}
+ \int_compare:nNnT { \g__csl_ref_section_index_int } = { 0 }
+ { \bool_gset_eq:NN \g__csl_global_note_class_bool \l__csl_note_bool }
}
@@ -266,15 +289,17 @@
\cs_new:Npn \__csl_write_aux_options:n #1
{
\if at filesw
- \iow_now:Nn \@auxout { \csl at aux@options {#1} }
+ \iow_now:Nx \@auxout
+ {
+ \token_to_str:N \csl at aux@options
+ { \int_use:N \g__csl_ref_section_index_int } {#1}
+ }
\fi
}
-\cs_new:Npn \csl at aux@options #1 { }
+\cs_new:Npn \csl at aux@options #1#2 { }
-\tl_new:N \g__csl_bibliography_setup_tl
-
% Load .bbl at the beginning of document to save one pass of latex.
% In this procedure, the \cslcitation command is processed and the contents
% of `thebibliography` is stored into \g__csl_bibliographies_prop.
@@ -283,10 +308,6 @@
% The \@input@ prints "No file ....bbl" in the .log file from which
% the latexmk decides to run $bibtex or not.
\__csl_collect_bibliography:n { \@input@ { \jobname .bbl } }
- % Execute the \cslsetup part to set the style class.
- % \tl_show:N \g__csl_bibliography_setup_tl
- \tl_use:N \g__csl_bibliography_setup_tl
- % \bool_show:N \l__csl_note_bool
}
@@ -302,8 +323,6 @@
% URLs may contain "%" and "#" characters.
\char_set_catcode_other:N \%
\char_set_catcode_other:N \#
- \RenewDocumentCommand \cslsetup { m }
- { \tl_gset:Nn \g__csl_bibliography_setup_tl { \cslsetup { ##1 } } }
\RenewDocumentEnvironment { thebibliography } { m +b }
{
\tl_set:Nn \l__csl_bib_index_tl { 1 }
@@ -321,13 +340,53 @@
\group_end:
}
+% At the moment, the `\csloptions` only reads the style class from `.bbl`
+% generated by `citeproc-lua`.
+% #1: refsection index
+% #2: refsection options
+\NewDocumentCommand \csloptions { m m }
+ { \keys_set:nn { csl / options } { #2 } }
+% The class option is in the `<style>=<class>` form
+% (e.g. `\csloptions{class={apa=in-text}}`).
+\keys_define:nn { csl / options }
+ {
+ class .code:n = { \prop_gput_from_keyval:Nn \g__csl_style_class_prop {#1} },
+ }
+
+\prop_new:N \g__csl_style_class_prop
+
% The `\textcite` bahaves differently with note styles.
% Thus we read the style class from the `.csl` file with non-LuaTeX engines.
\ior_new:N \l__csl_style_ior
+\cs_new:Npn \__csl_get_style_class:
+ {
+ \tl_clear:N \l__csl_class_tl
+ \bool_set_false:N \l__csl_note_bool
+ \prop_get:NVNF \g__csl_style_class_prop \l__csl_style_tl \l__csl_class_tl
+ { \__csl_read_style_class: }
+ \tl_if_empty:NF \l__csl_class_tl
+ {
+ \str_case:VnTF \l__csl_class_tl
+ {
+ { note } { \bool_set_true:N \l__csl_note_bool }
+ { in-text } { \bool_set_false:N \l__csl_note_bool }
+ }
+ {
+ \int_compare:nNnT { \g__csl_ref_section_index_int } = { 0 }
+ {
+ \bool_gset_eq:NN \g__csl_global_note_class_bool \l__csl_note_bool
+ }
+ }
+ {
+ \msg_error:nnV { citation-style-language } { invalid-style-class }
+ \l__csl_class_tl
+ }
+ }
+ }
+
\cs_new:Npn \__csl_read_style_class:
{
- \bool_set_false:N \l__csl_note_bool
\tl_if_blank:VF \l__csl_style_tl
{
\exp_args:NNx \ior_open:Nn \l__csl_style_ior { \l__csl_style_tl .csl }
@@ -334,16 +393,68 @@
\ior_map_inline:Nn \l__csl_style_ior
{
% \tl_show:n {##1}
- \tl_if_in:nnT {##1} { class="note" }
+ \tl_if_in:nnTF {##1} { class="note" }
{
\tl_set:Nn \l__csl_class_tl { note }
\bool_set_true:N \l__csl_note_bool
+ \prop_gput:NVn \g__csl_style_class_prop \l__csl_style_tl { note }
\ior_map_break:
}
+ {
+ \tl_if_in:nnT {##1} { class="in-text" }
+ {
+ \tl_set:Nn \l__csl_class_tl { in-text }
+ \bool_set_false:N \l__csl_note_bool
+ \prop_gput:NVn \g__csl_style_class_prop \l__csl_style_tl { in-text }
+ \ior_map_break:
+ }
+ }
}
\ior_close:N \l__csl_style_ior
}
}
-% \msg_new:nnn { citation-style-language } { file / non-exist }
+\msg_new:nnn { citation-style-language } { invalid-style-class }
+ { Invalid~ style~ class~ '#1'. }
+
+% \msg_new:nnn { citation-style-language } { file-non-exist }
% { No~ file~ #1. }
+
+\cs_new:Npn \__csl_set_ref_section_level:
+ {
+ \str_case:Vn \l__csl_bib_ref_section_str
+ {
+ { none } { }
+ { part }
+ { \__csl_patch_ref_section:n { part } }
+ { chapter }
+ { \__csl_patch_ref_section:n { chapter } }
+ { chapter+ }
+ {
+ \__csl_patch_ref_section:n { part }
+ \__csl_patch_ref_section:n { chapter }
+ }
+ { section }
+ { \__csl_patch_ref_section:n { section } }
+ { section+ }
+ {
+ \__csl_patch_ref_section:n { part }
+ \__csl_patch_ref_section:n { chapter }
+ \__csl_patch_ref_section:n { section }
+ }
+ { subsection }
+ { \__csl_patch_ref_section:n { subsection } }
+ { subsection+ }
+ {
+ \__csl_patch_ref_section:n { part }
+ \__csl_patch_ref_section:n { chapter }
+ \__csl_patch_ref_section:n { section }
+ \__csl_patch_ref_section:n { subsection }
+ }
+ }
+ }
+
+\cs_new:Npn \__csl_patch_ref_section:n #1
+ {
+ \hook_gput_code:nnn { cmd / #1 / before } { . } { \newrefsection }
+ }
Modified: trunk/Master/texmf-dist/tex/latex/citation-style-language/citation-style-language.sty
===================================================================
--- trunk/Master/texmf-dist/tex/latex/citation-style-language/citation-style-language.sty 2024-07-31 23:41:56 UTC (rev 71943)
+++ trunk/Master/texmf-dist/tex/latex/citation-style-language/citation-style-language.sty 2024-08-01 19:56:55 UTC (rev 71944)
@@ -9,7 +9,7 @@
\RequirePackage{expl3}
\RequirePackage{xparse}
-\ProvidesExplPackage {citation-style-language} {2024-06-09} {0.5.0}
+\ProvidesExplPackage {citation-style-language} {2024-07-31} {0.6.0}
{Citation Style Language for LaTeX}
\RequirePackage { l3keys2e }
@@ -16,9 +16,16 @@
\RequirePackage { url }
+\prop_gput:Nnn \g_msg_module_name_prop { citation-style-language } { CSL }
+\prop_gput:Nnn \g_msg_module_type_prop { citeproc } { Module }
+
+\msg_new:nnn { citeproc } { citeproc-error } {#1}
+\msg_new:nnn { citeproc } { citeproc-warning } {#1}
+
+
% Check incompatible packages
\msg_new:nnn { citation-style-language } { incompatible-package }
- { The~ `#1'~ package~ is~ incompatible~ with~ `citation-style-language'. }
+ { Package~ '#1'~ is~ incompatible~ with~ 'citation-style-language'. }
\clist_map_inline:nn
{
@@ -34,7 +41,13 @@
% Load Lua module in LuaTeX
\sys_if_engine_luatex:T
- { \lua_now:n { csl = require("citeproc-latex") } }
+ {
+ \lua_now:n
+ {
+ citeproc_manager = require("citeproc-manager")
+ csl_citation_manager = citeproc_manager.CslCitationManager:new()
+ }
+ }
% Global options
@@ -44,11 +57,15 @@
\bool_new:N \l__csl_regression_test_bool
+\tl_new:N \g__csl_global_style_tl
\tl_new:N \l__csl_style_tl
\newcommand \csl at style {} % For latex2e interface
\tl_new:N \l__csl_class_tl % TODO: This should be removed
+\bool_new:N \g__csl_global_note_class_bool
\bool_new:N \l__csl_note_bool
+\clist_new:N \g__csl_global_bib_resources_clist
\clist_new:N \l__csl_bib_resources_clist
+\tl_new:N \g__csl_global_locale_tl
\tl_new:N \l__csl_locale_tl
\bool_new:N \l__csl_back_ref_bool
\str_new:N \l__csl_back_ref_type_str
@@ -62,6 +79,7 @@
\tl_new:N \l__csl_bib_item_sep_tl
\tl_new:N \l__csl_bib_par_indent_tl
\tl_new:N \l__csl_bib_hang_tl
+\str_new:N \l__csl_bib_ref_section_str
\keys_define:nn { csl }
@@ -71,14 +89,19 @@
{
\tl_set:Nn \l__csl_style_tl {#1}
\renewcommand \csl at style {#1}
+ \tl_gset:Nn \g__csl_global_style_tl {#1}
} ,
- class .code:n =
+ class .code:n = {} , % Deprecated, should be removed in the next release.
+ bib-resource .code:n =
{
- \tl_set:Nn \l__csl_class_tl {#1}
- \tl_if_eq:NnT \l__csl_class_tl { note }
- { \bool_set_true:N \l__csl_note_bool }
+ \clist_set:Nn \l__csl_bib_resources_clist {#1}
+ \clist_gset_eq:NN \g__csl_global_bib_resources_clist \l__csl_bib_resources_clist
} ,
- locale .tl_set:N = \l__csl_locale_tl ,
+ locale .code:n =
+ {
+ \tl_set:Nn \l__csl_locale_tl {#1}
+ \tl_gset:Nn \g__csl_global_locale {#1}
+ } ,
backref .choices:nn =
{ true, page, section, false }
{ \exp_args:NV \__csl_set_back_ref:n \l_keys_choice_tl } ,
@@ -92,13 +115,10 @@
bib-item-sep .tl_set:N = \l__csl_bib_item_sep_tl ,
bib-par-indent .tl_set:N = \l__csl_bib_par_indent_tl ,
bib-hang .tl_set:N = \l__csl_bib_hang_tl ,
- % The following keys are for easier interaction between LaTeX and
- % citeproc-lua engine and they are not designed for end-users.
- undefined-cites .code:n =
- {
- \clist_map_inline:nn {#1}
- { \__csl_warn_citation_undefined:n {##1} }
- } ,
+ % ref section
+ ref-section .choices:nn =
+ { none, part, chapter, chapter+, section, section+, subsection, subsection+ }
+ { \str_set:NV \l__csl_bib_ref_section_str \l_keys_choice_tl } ,
}
\cs_new:Npn \__csl_set_back_ref:n #1
@@ -124,6 +144,7 @@
bib-entry-page-break = true ,
bib-par-indent = { \parindent } ,
bib-hang = { 1 em } ,
+ ref-section = none ,
}
@@ -138,8 +159,11 @@
}
\tl_new:N \g__csl_aux_bibstyle_tl
-\cs_set:Npn \csl at aux@style #1
- { \tl_gset:Nn \g__csl_aux_bibstyle_tl {#1} }
+\cs_set:Npn \csl at aux@style #1#2
+ {
+ \str_if_eq:nnT {#1} { 0 }
+ { \tl_gset:Nn \g__csl_aux_bibstyle_tl {#2} }
+ }
% Write to an empty `.ccf` file for use with latexmk
Modified: trunk/Master/texmf-dist/tex/latex/citation-style-language/styles/apa.csl
===================================================================
--- trunk/Master/texmf-dist/tex/latex/citation-style-language/styles/apa.csl 2024-07-31 23:41:56 UTC (rev 71943)
+++ trunk/Master/texmf-dist/tex/latex/citation-style-language/styles/apa.csl 2024-08-01 19:56:55 UTC (rev 71944)
@@ -14,7 +14,7 @@
<category citation-format="author-date"/>
<category field="psychology"/>
<category field="generic-base"/>
- <updated>2024-06-06T05:59:25+00:00</updated>
+ <updated>2024-07-19T10:52:31-04:00</updated>
<rights license="http://creativecommons.org/licenses/by-sa/3.0/">This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 License</rights>
</info>
<locale xml:lang="en">
@@ -23,6 +23,10 @@
<single>ed. & trans.</single>
<multiple>eds. & trans.</multiple>
</term>
+ <term name="editor-translator" form="short">
+ <single>ed. & trans.</single>
+ <multiple>eds. & trans.</multiple>
+ </term>
<term name="translator" form="short">trans.</term>
<term name="interviewer" form="short">
<single>interviewer</single>
@@ -32,6 +36,7 @@
<single>ed.</single>
<multiple>eds.</multiple>
</term>
+ <term name="performer" form="verb">recorded by</term>
<term name="circa" form="short">ca.</term>
<term name="bc"> B.C.E.</term>
<term name="ad"> C.E.</term>
@@ -41,7 +46,12 @@
</term>
<term name="software">computer software</term>
<term name="at" form="long">before the</term>
+ <term name="collection">archival collection</term>
+ <term name="post">online post</term>
+ <term name="at" form="long">before the</term>
<term name="hearing" form="verb">testimony of</term>
+ <term name="review-of" form="long">review of the</term>
+ <term name="review-of" form="short">review of</term>
</terms>
</locale>
<locale xml:lang="da">
@@ -82,101 +92,158 @@
<term name="et-al">et al.</term>
</terms>
</locale>
- <!-- TODO: New types: classic collection document event hearing performance periodical regulation -software- standard -->
- <!-- TODO: New creator roles: chair compiler contributor curator executive-producer guest host narrator organizer performer producer script-writer series-creator -->
- <!-- TODO: New variables:
- available-date submitted
- part-number printing-number supplement-number
- part-title volume-title
- archive_collection
- division jurisdiction
- event-title
- language
- license
- reviewed-genre
+ <!-- For Indigeneous Knowledge, assume the item is stored as `document` or `speech`
+ and that Nation/Community, treaty, where the Elder lives,
+ and topic are all stored in `title`
+ cf. https://libguides.norquest.ca/c.php?g=314831&p=5188823.
+ If the item is stored as `interview`, assume that Nation/Community, treat, and topic
+ are stored in `title`, 'Oral teaching' or similar is stored in `archive`, and where
+ the Elder lives is stored in `archive-place`.
-->
- <!-- TODO: New terms:
- advance-online-publication
- album on audio-recording
- original-work-published
- personal-communication
- preprint
- review-of
- item types
+ <!-- Reviews are detected if an item has type `review` or `review-book` or if it has any of the variables
+ `reviewed-title`, `reviewed-author`, or `reviewed-genre`. For the latter case, reviews are commonly
+ stored as types `article-journal`, `article-magazine`, `article-newspaper`, `post-weblog`, or `webpage`
-->
- <!-- TODO: Check Indigeneous Knowledge format -->
<!-- General categories of item types:
- Periodical: article-journal article-magazine article-newspaper post-weblog review review-book
+ Periodical: article-journal article-magazine article-newspaper periodical post-weblog review review-book
Periodical or Booklike: paper-conference
Booklike: article book broadcast chapter classic collection dataset document
entry entry-dictionary entry-encyclopedia event figure
- graphic interview manuscript map motion_picture musical_score pamphlet patent
- performance periodical personal_communication post report
+ graphic interview manuscript map motion_picture musical_score
+ pamphlet patent performance personal_communication post report
software song speech standard thesis webpage
Legal: bill hearing legal_case legislation regulation treaty
-->
+ <!-- Equivalencies:
+ classic == book
+ document == report, but give full date
+ standard == report
+ performance == speech
+ event == speech
+ collection == book, but give full date
+ -->
+ <!-- Role equivalencies:
+ compiler == editor
+ organizer, curator == chair
+ script-writer == director
+ producer == director (but don't print both)
+ guest, host == director
+ series-creator, executive-producer == editor
+ -->
<!-- APA references contain four parts: author, date, title, source -->
<macro name="author-bib">
- <!-- TODO: New creator roles (media, contributor) -->
- <!-- TODO: Add new item types -->
- <names variable="composer" delimiter=", ">
- <name name-as-sort-order="all" and="symbol" sort-separator=", " initialize-with=". " delimiter=", " delimiter-precedes-last="always"/>
- <substitute>
- <names variable="author"/>
- <names variable="illustrator"/>
- <names variable="director">
- <name name-as-sort-order="all" and="symbol" sort-separator=", " initialize-with=". " delimiter=", " delimiter-precedes-last="always"/>
- <label form="long" prefix=" (" suffix=")" text-case="title"/>
- </names>
- <choose>
- <if variable="container-title">
- <choose>
- <if type="book entry entry-dictionary entry-encyclopedia" match="any">
- <choose>
- <if variable="title">
- <group delimiter=" ">
- <text macro="title"/>
- <text macro="parenthetical"/>
- </group>
- </if>
- <else>
- <text macro="title-and-descriptions"/>
- </else>
- </choose>
- </if>
- </choose>
- </if>
- </choose>
- <!-- TODO: Test for editortranslator and put that first as that becomes available -->
- <names variable="editor" delimiter=", ">
- <name name-as-sort-order="all" and="symbol" sort-separator=", " initialize-with=". " delimiter=", " delimiter-precedes-last="always"/>
- <label form="short" prefix=" (" suffix=")" text-case="title"/>
- </names>
- <names variable="editorial-director">
- <name name-as-sort-order="all" and="symbol" sort-separator=", " initialize-with=". " delimiter=", " delimiter-precedes-last="always"/>
- <label form="short" prefix=" (" suffix=")" text-case="title"/>
- </names>
- <names variable="collection-editor">
- <name name-as-sort-order="all" and="symbol" sort-separator=", " initialize-with=". " delimiter=", " delimiter-precedes-last="always"/>
- <label form="short" prefix=" (" suffix=")" text-case="title"/>
- </names>
- <choose>
- <if variable="title">
- <group delimiter=" ">
- <text macro="title"/>
- <text macro="parenthetical"/>
- </group>
- </if>
- <else>
- <text macro="title-and-descriptions"/>
- </else>
- </choose>
- </substitute>
- </names>
+ <group delimiter=" ">
+ <names variable="composer" delimiter=", ">
+ <name name-as-sort-order="all" and="symbol" sort-separator=", " initialize-with=". " delimiter=", " delimiter-precedes-last="always"/>
+ <substitute>
+ <names variable="author"/>
+ <!-- Note: `narrator` only cited in secondary-contributors -->
+ <names variable="illustrator"/>
+ <names variable="script-writer director">
+ <!-- Note: Actors/performers and producers [not executive] not cited in APA style. -->
+ <name name-as-sort-order="all" and="symbol" sort-separator=", " initialize-with=". " delimiter=", " delimiter-precedes-last="always"/>
+ <label form="long" prefix=" (" suffix=")" text-case="title"/>
+ </names>
+ <names variable="guest host">
+ <name name-as-sort-order="all" and="symbol" sort-separator=", " initialize-with=". " delimiter=", " delimiter-precedes-last="always"/>
+ <label form="long" prefix=" (" suffix=")" text-case="title"/>
+ </names>
+ <names variable="producer">
+ <!-- Note: Producers not cited if there is a writer/director, but use if they are the principle creator. -->
+ <name name-as-sort-order="all" and="symbol" sort-separator=", " initialize-with=". " delimiter=", " delimiter-precedes-last="always"/>
+ <label form="long" prefix=" (" suffix=")" text-case="title"/>
+ </names>
+ <choose>
+ <if variable="container-title">
+ <choose>
+ <if type="book classic collection entry entry-dictionary entry-encyclopedia" match="any">
+ <!-- Items with book-like container-title substitute with their title and parenthetical,
+ but leave bracketed after container-title. This mimics the `container-booklike` formatting. -->
+ <choose>
+ <if variable="title">
+ <group delimiter=" ">
+ <text macro="title"/>
+ <text macro="parenthetical"/>
+ </group>
+ </if>
+ <else>
+ <text macro="title-and-descriptions"/>
+ </else>
+ </choose>
+ </if>
+ </choose>
+ </if>
+ </choose>
+ <names variable="series-creator executive-producer">
+ <name name-as-sort-order="all" and="symbol" sort-separator=", " initialize-with=". " delimiter=", " delimiter-precedes-last="always"/>
+ <label form="long" prefix=" (" suffix=")" text-case="title"/>
+ </names>
+ <names variable="editor-translator" delimiter=", ">
+ <name name-as-sort-order="all" and="symbol" sort-separator=", " initialize-with=". " delimiter=", " delimiter-precedes-last="always"/>
+ <label form="short" prefix=" (" suffix=")" text-case="title"/>
+ </names>
+ <!-- TODO: Split editor and translator into separate lines once processors begin to automatically create
+ the editor-translator variable. -->
+ <names variable="editor translator" delimiter=", ">
+ <name name-as-sort-order="all" and="symbol" sort-separator=", " initialize-with=". " delimiter=", " delimiter-precedes-last="always"/>
+ <label form="short" prefix=" (" suffix=")" text-case="title"/>
+ </names>
+ <names variable="editorial-director">
+ <name name-as-sort-order="all" and="symbol" sort-separator=", " initialize-with=". " delimiter=", " delimiter-precedes-last="always"/>
+ <label form="short" prefix=" (" suffix=")" text-case="title"/>
+ </names>
+ <names variable="compiler">
+ <name name-as-sort-order="all" and="symbol" sort-separator=", " initialize-with=". " delimiter=", " delimiter-precedes-last="always"/>
+ <label form="long" prefix=" (" suffix=")" text-case="title"/>
+ </names>
+ <choose>
+ <if type="event performance speech" match="any">
+ <names variable="chair">
+ <name name-as-sort-order="all" and="symbol" sort-separator=", " initialize-with=". " delimiter=", " delimiter-precedes-last="always"/>
+ <label form="long" prefix=" (" suffix=")" text-case="title"/>
+ </names>
+ <names variable="organizer">
+ <name name-as-sort-order="all" and="symbol" sort-separator=", " initialize-with=". " delimiter=", " delimiter-precedes-last="always"/>
+ <label form="long" prefix=" (" suffix=")" text-case="title"/>
+ </names>
+ </if>
+ </choose>
+ <names variable="curator">
+ <name name-as-sort-order="all" and="symbol" sort-separator=", " initialize-with=". " delimiter=", " delimiter-precedes-last="always"/>
+ <label form="long" prefix=" (" suffix=")" text-case="title"/>
+ </names>
+ <names variable="collection-editor">
+ <name name-as-sort-order="all" and="symbol" sort-separator=", " initialize-with=". " delimiter=", " delimiter-precedes-last="always"/>
+ <label form="short" prefix=" (" suffix=")" text-case="title"/>
+ </names>
+ <choose>
+ <if variable="title">
+ <!-- If an item has a title, substitute missing author with title and parenthetical, but leave bracketed
+ after the date (in the 'title' position). -->
+ <group delimiter=" ">
+ <text macro="title"/>
+ <text macro="parenthetical"/>
+ </group>
+ </if>
+ <else>
+ <!-- If an item has no title, substitute with bracketed followed by parenthetical. -->
+ <text macro="title-and-descriptions"/>
+ </else>
+ </choose>
+ </substitute>
+ </names>
+ <choose>
+ <!-- Print "with" contributor for books, but not for other types that commonly have them (eg, thesis, software) -->
+ <if type="book classic collection" match="any">
+ <names variable="contributor" prefix="(" suffix=")">
+ <label form="verb" suffix=" "/>
+ <name name-as-sort-order="all" and="symbol" sort-separator=", " initialize-with=". " delimiter=", " delimiter-precedes-last="always"/>
+ </names>
+ </if>
+ </choose>
+ </group>
</macro>
<macro name="author-intext">
- <!-- TODO: New creator roles -->
- <!-- TODO: Add new item types -->
<choose>
<if type="bill hearing legal_case legislation regulation treaty" match="any">
<text macro="title-intext"/>
@@ -212,18 +279,29 @@
<substitute>
<names variable="author"/>
<names variable="illustrator"/>
- <names variable="director"/>
+ <names variable="script-writer director"/>
+ <names variable="guest host"/>
+ <names variable="producer"/>
<choose>
<if variable="container-title">
<choose>
- <if type="book entry entry-dictionary entry-encyclopedia" match="any">
+ <if type="book classic collection entry entry-dictionary entry-encyclopedia" match="any">
<text macro="title-intext"/>
</if>
</choose>
</if>
</choose>
+ <names variable="series-creator executive-producer"/>
<names variable="editor"/>
<names variable="editorial-director"/>
+ <names variable="compiler"/>
+ <choose>
+ <if type="event performance speech" match="any">
+ <names variable="chair"/>
+ <names variable="organizer"/>
+ </if>
+ </choose>
+ <names variable="curator"/>
<text macro="title-intext"/>
</substitute>
</names>
@@ -241,7 +319,6 @@
</choose>
</macro>
<macro name="date-bib">
- <!-- TODO: Add new item types -->
<group delimiter=" " prefix="(" suffix=")">
<choose>
<if is-uncertain-date="issued">
@@ -257,7 +334,7 @@
<text variable="year-suffix"/>
</group>
<choose>
- <if type="article-magazine article-newspaper broadcast interview motion_picture pamphlet personal_communication post post-weblog song speech webpage" match="any">
+ <if type="article-magazine article-newspaper broadcast collection document event interview motion_picture pamphlet performance personal_communication post post-weblog song speech webpage" match="any">
<!-- Many video and audio examples in manual give full dates. Err on the side of too much information. -->
<date variable="issued">
<date-part name="month"/>
@@ -267,7 +344,7 @@
<else-if type="paper-conference">
<!-- Capture 'speech' stored as 'paper-conference' -->
<choose>
- <if variable="collection-editor editor editorial-director issue page volume" match="none">
+ <if variable="collection-editor compiler editor editorial-director issue page volume" match="none">
<date variable="issued">
<date-part name="month"/>
<date-part name="day" prefix=" "/>
@@ -275,14 +352,14 @@
</if>
</choose>
</else-if>
- <!-- Only year: article article-journal book chapter entry entry-dictionary entry-encyclopedia dataset figure graphic
- manuscript map musical_score paper-conference[published] patent report review review-book thesis -->
+ <!-- Only year: article article-journal book chapter classic entry entry-dictionary entry-encyclopedia dataset figure graphic
+ manuscript map musical_score paper-conference[published] patent periodical report review review-book software standard thesis -->
</choose>
</group>
</if>
<else-if variable="status">
<group>
- <!-- TODO: Should I print status as-is, or should I print the in-press term? -->
+ <!-- We print the status variable directly rather than using in-press, etc. terms. -->
<text variable="status" text-case="lowercase"/>
<text variable="year-suffix" prefix="-"/>
</group>
@@ -296,6 +373,7 @@
</group>
</macro>
<macro name="date-sort">
+ <!-- This is necessary to ensure that citeproc sorts all item types chonologically in the same list. -->
<choose>
<if type="article article-journal book chapter entry entry-dictionary entry-encyclopedia dataset figure graphic manuscript map musical_score patent report review review-book thesis" match="any">
<date variable="issued" date-parts="year" form="numeric"/>
@@ -303,7 +381,7 @@
<else-if type="paper-conference">
<!-- Capture 'speech' stored as 'paper-conference' -->
<choose>
- <if variable="collection-editor editor editorial-director issue page volume" match="any">
+ <if variable="collection-editor compiler editor editorial-director issue page volume" match="any">
<date variable="issued" date-parts="year" form="numeric"/>
</if>
<else>
@@ -339,7 +417,6 @@
</choose>
</macro>
<macro name="date-intext">
- <!-- TODO: Add new item types -->
<choose>
<if variable="issued">
<group delimiter="/">
@@ -387,7 +464,7 @@
</group>
</if>
<else-if variable="status">
- <!-- TODO: Should I print status as-is, or should I print the in-press term? -->
+ <!-- We print the status variable directly rather than using in-press, etc. terms. -->
<text variable="status" text-case="lowercase"/>
<text variable="year-suffix" prefix="-"/>
</else-if>
@@ -398,7 +475,7 @@
</choose>
</macro>
<!-- APA has two description elements following the title:
- title (parenthetical) [bracketed] -->
+ title (parenthetical) [bracketed] -->
<macro name="title-and-descriptions">
<choose>
<if variable="title">
@@ -412,7 +489,7 @@
<choose>
<if type="bill report" match="any">
<!-- Bills, resolutions, and congressional reports are not italicized and substitute bill number if no title. -->
- <!-- Can't distinguish congressional reports from other reports,
+ <!-- Can't distinguish congressional reports from other reports,
but giving the genre and number seems fine for other reports too. -->
<text macro="number"/>
<text macro="bracketed"/>
@@ -429,68 +506,125 @@
</choose>
</macro>
<macro name="title">
- <!-- TODO: Add new item types -->
<choose>
<if type="post webpage" match="any">
<!-- Webpages are always italicized -->
- <text variable="title" font-style="italic"/>
+ <text macro="title-plus-part-title" font-style="italic"/>
</if>
- <else-if variable="container-title" match="any">
- <!-- Other types are italicized based on presence of container-title.
+ <!-- Other types are italicized based on presence of container-title.
Assume that review and review-book are published in periodicals/blogs,
not just on a web page (ex. 69) -->
- <text variable="title"/>
+ <else-if type="article-journal article-magazine article-newspaper periodical post-weblog review review-book" match="any">
+ <text macro="periodical-title"/>
</else-if>
- <else>
+ <else-if type="paper-conference">
+ <!-- Treat paper-conference as book-like if it has an editor, otherwise as periodical-like -->
<choose>
- <if type="article-journal article-magazine article-newspaper post-weblog review review-book" match="any">
- <text variable="title" font-style="italic"/>
+ <if variable="collection-editor compiler editor editorial-director" match="any">
+ <text macro="booklike-title"/>
</if>
- <else-if type="paper-conference">
- <choose>
- <if variable="collection-editor editor editorial-director" match="any">
- <group delimiter=": " font-style="italic">
- <text variable="title"/>
- <!-- TODO: Replace with volume-title -->
- <choose>
- <if is-numeric="volume" match="none">
- <group delimiter=" ">
- <label variable="volume" form="short" text-case="capitalize-first"/>
- <text variable="volume"/>
- </group>
- </if>
- </choose>
- </group>
- </if>
- <else>
- <text variable="title" font-style="italic"/>
- </else>
- </choose>
- </else-if>
<else>
- <group delimiter=": " font-style="italic">
+ <text macro="periodical-title"/>
+ </else>
+ </choose>
+ </else-if>
+ <else>
+ <text macro="booklike-title"/>
+ </else>
+ </choose>
+ </macro>
+ <macro name="periodical-title">
+ <!-- For periodicals, assume that part-number and part-title refer to the article and append to title -->
+ <choose>
+ <if variable="container-title" match="any">
+ <text macro="title-plus-part-title"/>
+ </if>
+ <else>
+ <!-- for periodical items without container titles, don't append volume-title to title -->
+ <text macro="title-plus-part-title" font-style="italic"/>
+ </else>
+ </choose>
+ </macro>
+ <macro name="booklike-title">
+ <!-- For book-like items, assume part-number and part-title refer to the book/volume. -->
+ <choose>
+ <if variable="container-title" match="any">
+ <text variable="title"/>
+ </if>
+ <else>
+ <!-- For book-like items without container titles and with volume-title, append volume-title to title (ex. 30) -->
+ <text macro="title-plus-volume-title" font-style="italic"/>
+ </else>
+ </choose>
+ </macro>
+ <macro name="title-plus-part-title">
+ <choose>
+ <if variable="reviewed-author reviewed-genre reviewed-title" type="review review-book" match="any">
+ <!-- If a review has no `reviewed-title`, assume that `title` contains the title of the reviewed work
+ and omit it here; it is printed in the `reviewed-item` macro. -->
+ <choose>
+ <if variable="reviewed-title" match="none"/>
+ <else>
+ <group delimiter=": ">
<text variable="title"/>
- <!-- TODO: Replace with volume-title -->
- <choose>
- <if is-numeric="volume" match="none">
- <group delimiter=" ">
- <label variable="volume" form="short" text-case="capitalize-first"/>
- <text variable="volume"/>
- </group>
- </if>
- </choose>
+ <text macro="part-title"/>
</group>
</else>
</choose>
+ </if>
+ <else>
+ <group delimiter=": ">
+ <text variable="title"/>
+ <text macro="part-title"/>
+ </group>
</else>
</choose>
</macro>
+ <macro name="part-title">
+ <group delimiter=". ">
+ <group delimiter=" ">
+ <label variable="part-number" form="short" text-case="capitalize-first"/>
+ <text variable="part-number"/>
+ </group>
+ <text variable="part-title" text-case="capitalize-first"/>
+ </group>
+ </macro>
+ <macro name="title-plus-volume-title">
+ <group delimiter=": ">
+ <text variable="title"/>
+ <text macro="volume-title"/>
+ </group>
+ </macro>
+ <macro name="volume-title">
+ <group delimiter=": ">
+ <choose>
+ <if variable="volume-title">
+ <group delimiter=" ">
+ <group delimiter=". ">
+ <group delimiter=" ">
+ <label variable="volume" form="short" text-case="capitalize-first"/>
+ <text variable="volume"/>
+ </group>
+ <text variable="volume-title"/>
+ </group>
+ </group>
+ </if>
+ <else-if is-numeric="volume" match="none">
+ <group delimiter=" ">
+ <label variable="volume" form="short" text-case="capitalize-first"/>
+ <text variable="volume"/>
+ </group>
+ </else-if>
+ </choose>
+ <!-- For book-like items, assume part-number and part-title refer to the book/volume. -->
+ <text macro="part-title"/>
+ </group>
+ </macro>
<macro name="title-intext">
- <!-- TODO: Add new item types -->
<choose>
<if type="bill report">
<!-- Bills, resolutions, and congressional reports are not italicized and substitute bill number if no title. -->
- <!-- Can't distinguish congressional reports from other reports,
+ <!-- Can't distinguish congressional reports from other reports,
but giving the genre and number seems fine for other reports too. -->
<choose>
<if variable="title">
@@ -544,7 +678,6 @@
</choose>
</macro>
<macro name="parenthetical">
- <!-- TODO: Add new item types -->
<!-- (Secondary contributors; Database location; Genre no. 123; Report Series 123, Version, Edition, Volume, Page) -->
<group prefix="(" suffix=")">
<choose>
@@ -604,7 +737,7 @@
<text macro="secondary-contributors"/>
<choose>
<if type="broadcast graphic map motion_picture song" match="any">
- <!-- For audiovisual media, number information comes after title, not container-title -->
+ <!-- For audiovisual media, number information comes after title, not container-title (ex. 94) -->
<text macro="number"/>
</if>
</choose>
@@ -622,7 +755,6 @@
</group>
</macro>
<macro name="parenthetical-container">
- <!-- TODO: Add new item types -->
<choose>
<if variable="container-title" match="any">
<group prefix="(" suffix=")">
@@ -630,7 +762,7 @@
<text macro="database-location"/>
<choose>
<if type="broadcast graphic map motion_picture song" match="none">
- <!-- For audiovisual media, number information comes after title, not container-title -->
+ <!-- For audiovisual media, number information comes after title, not container-title (ex. 94) -->
<text macro="number"/>
</if>
</choose>
@@ -641,65 +773,12 @@
</choose>
</macro>
<macro name="bracketed">
- <!-- TODO: Add new item types -->
<!-- [Descriptive information] -->
<!-- If there is a number, genre is already printed in macro="number" -->
<group prefix="[" suffix="]">
<choose>
- <if variable="reviewed-author reviewed-title" type="review review-book" match="any">
- <!-- Reviewed item -->
- <group delimiter="; ">
- <group delimiter=", ">
- <group delimiter=" ">
- <!-- Assume that genre is entered as 'Review of the book' or similar -->
- <choose>
- <if variable="number" match="none">
- <choose>
- <if variable="genre">
- <text variable="genre" text-case="capitalize-first"/>
- </if>
- <else-if variable="medium">
- <text variable="medium" text-case="capitalize-first"/>
- </else-if>
- <else>
- <!-- TODO: Replace with term="review" -->
- <!-- TODO: Handle review vs review-of depending on presence of reviewed-title -->
- <!-- TODO: Add reviewed-genre -->
- <text value="Review of"/>
- </else>
- </choose>
- </if>
- <else>
- <choose>
- <if variable="medium">
- <text variable="medium" text-case="capitalize-first"/>
- </if>
- <else>
- <!-- TODO: Replace with term="review" -->
- <!-- TODO: Handle review vs review-of depending on presence of reviewed-title -->
- <!-- TODO: Add reviewed-genre -->
- <text value="Review of"/>
- </else>
- </choose>
- </else>
- </choose>
- <text macro="reviewed-title"/>
- </group>
- <names variable="reviewed-author">
- <label form="verb-short" suffix=" "/>
- <name and="symbol" initialize-with=". " delimiter=", "/>
- </names>
- </group>
- <choose>
- <if variable="genre" match="any">
- <choose>
- <if variable="number" match="none">
- <text variable="medium" text-case="capitalize-first"/>
- </if>
- </choose>
- </if>
- </choose>
- </group>
+ <if variable="reviewed-author reviewed-genre reviewed-title" type="review review-book" match="any">
+ <text macro="reviewed-item"/>
</if>
<else-if type="thesis">
<!-- Thesis type and institution -->
@@ -814,22 +893,35 @@
<choose>
<if variable="genre">
<text variable="genre" text-case="capitalize-first"/>
- <!-- TODO: Replace prefix with performer label -->
- <names variable="author" prefix="recorded by ">
- <name and="symbol" initialize-with=". " delimiter=", "/>
- </names>
+ <group delimiter=" ">
+ <text term="performer" form="verb"/>
+ <names variable="author">
+ <name and="symbol" initialize-with=". " delimiter=", "/>
+ <substitute>
+ <names variable="performer"/>
+ </substitute>
+ </names>
+ </group>
</if>
<else-if variable="medium">
<text variable="medium" text-case="capitalize-first"/>
- <!-- TODO: Replace prefix with performer label -->
- <names variable="author" prefix="recorded by ">
- <name and="symbol" initialize-with=". " delimiter=", "/>
- </names>
+ <group delimiter=" ">
+ <text term="performer" form="verb"/>
+ <names variable="author">
+ <name and="symbol" initialize-with=". " delimiter=", "/>
+ <substitute>
+ <names variable="performer"/>
+ </substitute>
+ </names>
+ </group>
</else-if>
<else>
- <!-- TODO: Replace prefix with performer label -->
- <names variable="author" prefix="Recorded by ">
+ <text term="performer" form="verb" text-case="capitalize-first"/>
+ <names variable="author">
<name and="symbol" initialize-with=". " delimiter=", "/>
+ <substitute>
+ <names variable="performer"/>
+ </substitute>
</names>
</else>
</choose>
@@ -840,15 +932,23 @@
<choose>
<if variable="medium">
<text variable="medium" text-case="capitalize-first"/>
- <!-- TODO: Replace prefix with performer label -->
- <names variable="author" prefix="recorded by ">
- <name and="symbol" initialize-with=". " delimiter=", "/>
- </names>
+ <group delimiter=" ">
+ <text term="performer" form="verb"/>
+ <names variable="author">
+ <name and="symbol" initialize-with=". " delimiter=", "/>
+ <substitute>
+ <names variable="performer"/>
+ </substitute>
+ </names>
+ </group>
</if>
<else>
- <!-- TODO: Replace prefix with performer label -->
- <names variable="author" prefix="Recorded by ">
+ <text term="performer" form="verb" text-case="capitalize-first"/>
+ <names variable="author">
<name and="symbol" initialize-with=". " delimiter=", "/>
+ <substitute>
+ <names variable="performer"/>
+ </substitute>
</names>
</else>
</choose>
@@ -871,16 +971,17 @@
<text macro="format"/>
</else-if>
<else>
- <!-- For conference presentations, chapters in reports, software, place bracketed after the container title -->
+ <!-- For conference presentations/performances/events, chapters in reports/standards/generic documents, software,
+ place bracketed after the container title -->
<choose>
- <if type="paper-conference speech" match="any">
+ <if type="event paper-conference performance speech" match="any">
<choose>
- <if variable="collection-editor editor editorial-director issue page volume" match="any">
+ <if variable="collection-editor compiler editor editorial-director issue page volume" match="any">
<text macro="format"/>
</if>
</choose>
</if>
- <else-if type="report software" match="none">
+ <else-if type="document report software standard" match="none">
<text macro="format"/>
</else-if>
</choose>
@@ -889,10 +990,9 @@
</group>
</macro>
<macro name="bracketed-intext">
- <!-- TODO: Add new item types -->
<group prefix="[" suffix="]">
<choose>
- <if variable="reviewed-author reviewed-title" type="review review-book" match="any">
+ <if variable="reviewed-title" match="any">
<group delimiter=" ">
<text term="review-of" text-case="capitalize-first"/>
<text macro="reviewed-title-intext"/>
@@ -937,14 +1037,80 @@
</choose>
</group>
</macro>
+ <macro name="reviewed-item">
+ <!-- Reviewed item -->
+ <group delimiter="; ">
+ <group delimiter=", ">
+ <group delimiter=" ">
+ <choose>
+ <if variable="reviewed-genre">
+ <group delimiter=" ">
+ <text term="review-of" form="long" text-case="capitalize-first"/>
+ <text variable="reviewed-genre" text-case="lowercase"/>
+ </group>
+ </if>
+ <!-- If no `reviewed-genre`, assume that `genre` or `medium` is entered as 'Review of the book' or similar -->
+ <else-if variable="number" match="none">
+ <choose>
+ <if variable="genre">
+ <text variable="genre" text-case="capitalize-first"/>
+ </if>
+ <else-if variable="medium">
+ <text variable="medium" text-case="capitalize-first"/>
+ </else-if>
+ <else-if type="review-book">
+ <group delimiter=" ">
+ <text term="review-of" form="long" text-case="capitalize-first"/>
+ <text term="book" form="long" text-case="lowercase"/>
+ </group>
+ </else-if>
+ <else>
+ <text term="review-of" form="short" text-case="capitalize-first"/>
+ </else>
+ </choose>
+ </else-if>
+ <else>
+ <choose>
+ <if variable="medium">
+ <text variable="medium" text-case="capitalize-first"/>
+ </if>
+ <else-if type="review-book">
+ <group delimiter=" ">
+ <text term="review-of" form="long" text-case="capitalize-first"/>
+ <text term="book" form="long" text-case="lowercase"/>
+ </group>
+ </else-if>
+ <else>
+ <text term="review-of" form="short" text-case="capitalize-first"/>
+ </else>
+ </choose>
+ </else>
+ </choose>
+ <text macro="reviewed-title"/>
+ </group>
+ <names variable="reviewed-author">
+ <label form="verb-short" suffix=" "/>
+ <name and="symbol" initialize-with=". " delimiter=", "/>
+ </names>
+ </group>
+ <choose>
+ <if variable="genre" match="any">
+ <choose>
+ <if variable="number" match="none">
+ <text variable="medium" text-case="capitalize-first"/>
+ </if>
+ </choose>
+ </if>
+ </choose>
+ </group>
+ </macro>
<macro name="bracketed-container">
- <!-- TODO: Add new item types -->
<group prefix="[" suffix="]">
<choose>
- <if type="paper-conference speech" match="any">
+ <if type="event paper-conference performance speech" match="any">
<!-- Conference presentations should describe the session [container] in bracketed unless published in a proceedings -->
<choose>
- <if variable="collection-editor editor editorial-director issue page volume" match="none">
+ <if variable="collection-editor compiler editor editorial-director issue page volume" match="none">
<text macro="format"/>
</if>
</choose>
@@ -953,8 +1119,8 @@
<!-- For entries in mobile app reference works, place bracketed after the container-title -->
<text macro="format"/>
</else-if>
- <else-if type="report">
- <!-- For chapters in reports, place bracketed after the container title -->
+ <else-if type="document report standard">
+ <!-- For chapters in report, standards, and generic documents, place bracketed after the container title -->
<text macro="format"/>
</else-if>
</choose>
@@ -961,15 +1127,13 @@
</group>
</macro>
<macro name="secondary-contributors">
- <!-- TODO: Add new item types -->
- <!-- TODO: Add new creator roles -->
<choose>
- <if type="article-journal article-magazine article-newspaper post-weblog review review-book" match="any">
+ <if type="article-journal article-magazine article-newspaper periodical post-weblog review review-book" match="any">
<text macro="secondary-contributors-periodical"/>
</if>
<else-if type="paper-conference">
<choose>
- <if variable="collection-editor editor editorial-director" match="any">
+ <if variable="collection-editor compiler editor editorial-director" match="any">
<text macro="secondary-contributors-booklike"/>
</if>
<else>
@@ -992,7 +1156,7 @@
</names>
</if>
</choose>
- <names variable="translator" delimiter="; ">
+ <names variable="translator narrator" delimiter="; ">
<name and="symbol" initialize-with=". " delimiter=", "/>
<label form="short" prefix=", " text-case="title"/>
</names>
@@ -999,7 +1163,6 @@
</group>
</macro>
<macro name="secondary-contributors-booklike">
- <!-- TODO: Add new item types -->
<group delimiter="; ">
<choose>
<if variable="title">
@@ -1009,7 +1172,8 @@
</names>
</if>
</choose>
- <!-- TODO: When editortranslator becomes available, add a test: variable="editortranslator" match="none"; then print translator -->
+ <!-- TODO: When editor-translator becomes available in processors, add a test:
+ variable="editor-translator" match="none"; then print translator -->
<choose>
<if type="post webpage" match="none">
<!-- Webpages treat container-title like publisher -->
@@ -1024,6 +1188,14 @@
<name and="symbol" initialize-with=". " delimiter=", "/>
<label form="short" prefix=", " text-case="title"/>
</names>
+ <names variable="illustrator narrator" delimiter="; ">
+ <name and="symbol" initialize-with=". " delimiter=", "/>
+ <label form="short" prefix=", " text-case="title"/>
+ </names>
+ <names variable="compiler chair organizer curator series-creator executive-producer" delimiter="; ">
+ <name and="symbol" initialize-with=". " delimiter=", "/>
+ <label form="long" prefix=", " text-case="title"/>
+ </names>
</group>
</if>
</choose>
@@ -1038,6 +1210,14 @@
<name and="symbol" initialize-with=". " delimiter=", "/>
<label form="short" prefix=", " text-case="title"/>
</names>
+ <names variable="illustrator narrator" delimiter="; ">
+ <name and="symbol" initialize-with=". " delimiter=", "/>
+ <label form="short" prefix=", " text-case="title"/>
+ </names>
+ <names variable="compiler chair organizer curator series-creator executive-producer" delimiter="; ">
+ <name and="symbol" initialize-with=". " delimiter=", "/>
+ <label form="long" prefix=", " text-case="title"/>
+ </names>
</group>
</else>
</choose>
@@ -1047,13 +1227,11 @@
<choose>
<if variable="archive-place" match="none">
<!-- With `archive-place`: physical archives. Without: online archives. -->
- <!-- TODO: Add archive_collection -->
<text variable="archive_location"/>
</if>
</choose>
</macro>
<macro name="number">
- <!-- TODO: Add new item types -->
<choose>
<if variable="number">
<group delimiter=", ">
@@ -1079,12 +1257,11 @@
</choose>
</macro>
<macro name="locators-booklike">
- <!-- TODO: Add new item types -->
<choose>
- <if type="article-journal article-magazine article-newspaper broadcast interview patent post post-weblog review review-book speech webpage" match="any"/>
+ <if type="article-journal article-magazine article-newspaper broadcast event interview patent performance periodical post post-weblog review review-book speech webpage" match="any"/>
<else-if type="paper-conference">
<choose>
- <if variable="collection-editor editor editorial-director" match="any">
+ <if variable="collection-editor compiler editor editorial-director" match="any">
<group delimiter=", ">
<text macro="version"/>
<text macro="edition"/>
@@ -1129,11 +1306,10 @@
</choose>
</macro>
<macro name="volume-booklike">
- <!-- TODO: Add new item types -->
<group delimiter=", ">
<!-- Report series [ex. 52] -->
<choose>
- <if type="report">
+ <if type="document report standard">
<group delimiter=" ">
<text variable="collection-title" text-case="title"/>
<text variable="collection-number"/>
@@ -1140,12 +1316,16 @@
</group>
</if>
</choose>
+ <group delimiter=" ">
+ <label variable="supplement-number" text-case="capitalize-first"/>
+ <text variable="supplement-number"/>
+ </group>
<choose>
<if variable="volume" match="any">
- <!-- TODO: Update using volume-title -->
<choose>
<!-- Non-numeric volumes are already printed as part of the book title -->
- <if is-numeric="volume" match="none"/>
+ <if variable="volume-title"/>
+ <else-if is-numeric="volume" match="none"/>
<else>
<group delimiter=" ">
<label variable="volume" form="short" text-case="capitalize-first"/>
@@ -1176,7 +1356,8 @@
<choose>
<if variable="reviewed-title">
<!-- Not possible to distinguish TV series episode from other reviewed
- works [Ex. 69] -->
+ works without reviewed-container-title [Ex. 69] -->
+ <!-- Adapt for reviewed-container-title if that becomes available -->
<text variable="reviewed-title" font-style="italic"/>
</if>
<else>
@@ -1188,7 +1369,9 @@
<macro name="reviewed-title-intext">
<choose>
<if variable="reviewed-title">
- <!-- Not possible to distinguish TV series episode from other reviewed works [Ex. 69] -->
+ <!-- Not possible to distinguish TV series episode from other reviewed
+ works without reviewed-container-title [Ex. 69] -->
+ <!-- Adapt for reviewed-container-title if that becomes available -->
<text variable="reviewed-title" form="short" font-style="italic" text-case="title"/>
</if>
<else>
@@ -1198,7 +1381,6 @@
</choose>
</macro>
<macro name="format">
- <!-- TODO: Add new item types -->
<choose>
<if variable="genre medium" match="any">
<group delimiter="; ">
@@ -1210,31 +1392,12 @@
<text variable="medium" text-case="capitalize-first"/>
</group>
</if>
- <!-- Generic labels for specific types -->
- <!-- TODO: Add terms for other types? -->
- <else-if type="dataset">
- <text term="dataset"/>
- </else-if>
- <else-if type="software">
- <text term="software" text-case="capitalize-first"/>
- </else-if>
- <else-if type="interview personal_communication" match="any">
- <choose>
- <if variable="archive container-title DOI publisher URL" match="none">
- <text term="personal-communication" text-case="capitalize-first"/>
- </if>
- <else-if type="interview">
- <text term="interview" text-case="capitalize-first"/>
- </else-if>
- </choose>
- </else-if>
- <else-if type="map">
- <text term="map" text-case="capitalize-first"/>
- </else-if>
+ <else>
+ <text macro="generic-type-label"/>
+ </else>
</choose>
</macro>
<macro name="format-intext">
- <!-- TODO: Add new item types -->
<choose>
<if variable="genre" match="any">
<text variable="genre" text-case="capitalize-first"/>
@@ -1242,11 +1405,17 @@
<else-if variable="medium">
<text variable="medium" text-case="capitalize-first"/>
</else-if>
- <!-- Generic labels for specific types -->
- <!-- TODO: Add terms for other types? -->
- <else-if type="dataset">
- <text term="dataset"/>
- </else-if>
+ <else>
+ <text macro="generic-type-label"/>
+ </else>
+ </choose>
+ </macro>
+ <macro name="generic-type-label">
+ <!-- Generic labels for specific types -->
+ <choose>
+ <if type="dataset">
+ <text term="dataset" text-case="capitalize-first"/>
+ </if>
<else-if type="software">
<text term="software" text-case="capitalize-first"/>
</else-if>
@@ -1261,21 +1430,47 @@
</choose>
</else-if>
<else-if type="map">
- <text term="map"/>
+ <text term="map" text-case="capitalize-first"/>
</else-if>
+ <else-if type="collection">
+ <text term="collection" text-case="capitalize-first"/>
+ </else-if>
+ <else-if type="song">
+ <text term="song" text-case="capitalize-first"/>
+ </else-if>
+ <else-if type="motion_picture">
+ <text term="motion_picture" text-case="capitalize-first"/>
+ </else-if>
+ <else-if type="post">
+ <text term="post" text-case="capitalize-first"/>
+ </else-if>
+ <else-if type="review">
+ <text term="review" text-case="capitalize-first"/>
+ </else-if>
+ <else-if type="review-book">
+ <text term="review-book" text-case="capitalize-first"/>
+ </else-if>
+ <else-if type="broadcast">
+ <text term="broadcast" text-case="capitalize-first"/>
+ </else-if>
+ <else-if type="figure">
+ <text term="figure" text-case="capitalize-first"/>
+ </else-if>
+ <else-if type="graphic">
+ <text term="graphic" text-case="capitalize-first"/>
+ </else-if>
</choose>
</macro>
<!-- APA 'source' element contains four parts:
container, event, publisher, access -->
<macro name="container">
- <!-- TODO: Add new item types -->
<choose>
- <if type="article-journal article-magazine article-newspaper post-weblog review review-book" match="any">
+ <if type="article-journal article-magazine article-newspaper periodical post-weblog review review-book" match="any">
<!-- Periodical items -->
<text macro="container-periodical"/>
</if>
<else-if type="paper-conference">
- <!-- Determine if paper-conference is a periodical or booklike -->
+ <!-- Determine if paper-conference is a periodical- or book-like -->
<choose>
<if variable="editor editorial-director collection-editor container-author" match="any">
<text macro="container-booklike"/>
@@ -1309,7 +1504,6 @@
<choose>
<if variable="number">
<!-- Ex. 6: Journal article with article number or eLocator -->
- <!-- This should be localized -->
<group delimiter=" ">
<text term="article-locator" text-case="capitalize-first"/>
<text variable="number"/>
@@ -1323,8 +1517,8 @@
<choose>
<if variable="issued">
<choose>
- <if variable="issue page volume" match="none">
- <!-- TODO: Should I print status as-is, or should I print the in-press term? -->
+ <if variable="issue number page volume" match="none">
+ <!-- We print the status variable directly rather than using in-press, etc. terms. -->
<text variable="status" text-case="capitalize-first"/>
</if>
</choose>
@@ -1333,33 +1527,54 @@
</group>
</macro>
<macro name="container-booklike">
- <!-- TODO: Add new item types -->
<choose>
<if variable="container-title" match="any">
<group delimiter=" ">
- <text term="in" text-case="capitalize-first"/>
+ <choose>
+ <if type="song">
+ <text term="on" text-case="capitalize-first"/>
+ </if>
+ <else>
+ <text term="in" text-case="capitalize-first"/>
+ </else>
+ </choose>
<group delimiter=", ">
- <names variable="editor translator" delimiter=", & ">
- <!-- TODO: Change to editortranslator and move editor to substitute -->
+ <names variable="series-creator executive-producer" delimiter=", & ">
<name and="symbol" initialize-with=". " delimiter=", "/>
- <label form="short" text-case="title" prefix=" (" suffix=")"/>
+ <label form="long" text-case="title" prefix=" (" suffix=")"/>
<substitute>
- <names variable="editorial-director"/>
- <names variable="collection-editor"/>
+ <names variable="editor-translator">
+ <name and="symbol" initialize-with=". " delimiter=", "/>
+ <label form="short" text-case="title" prefix=" (" suffix=")"/>
+ </names>
+ <!-- TODO: Split editor and translator lines once processors start to automatically
+ create editor-translator variable. -->
+ <names variable="editor translator">
+ <name and="symbol" initialize-with=". " delimiter=", "/>
+ <label form="short" text-case="title" prefix=" (" suffix=")"/>
+ </names>
+ <names variable="editorial-director">
+ <name and="symbol" initialize-with=". " delimiter=", "/>
+ <label form="short" text-case="title" prefix=" (" suffix=")"/>
+ </names>
+ <names variable="compiler"/>
+ <choose>
+ <if type="event performance speech" match="any">
+ <names variable="chair"/>
+ <names variable="organizer"/>
+ </if>
+ </choose>
+ <names variable="curator"/>
+ <names variable="collection-editor">
+ <name and="symbol" initialize-with=". " delimiter=", "/>
+ <label form="short" text-case="title" prefix=" (" suffix=")"/>
+ </names>
<names variable="container-author"/>
</substitute>
</names>
<group delimiter=": " font-style="italic">
<text variable="container-title"/>
- <!-- TODO: Replace with volume-title -->
- <choose>
- <if is-numeric="volume" match="none">
- <group delimiter=" ">
- <label variable="volume" form="short" text-case="capitalize-first"/>
- <text variable="volume"/>
- </group>
- </if>
- </choose>
+ <text macro="volume-title"/>
</group>
</group>
<text macro="parenthetical-container"/>
@@ -1369,7 +1584,6 @@
</choose>
</macro>
<macro name="publisher">
- <!-- TODO: Add new item types -->
<group delimiter="; ">
<choose>
<if type="thesis">
@@ -1377,6 +1591,9 @@
<if variable="archive DOI URL" match="none">
<text variable="publisher"/>
</if>
+ <else>
+ <text variable="archive"/>
+ </else>
</choose>
</if>
<else-if type="post webpage" match="any">
@@ -1389,12 +1606,12 @@
<else-if type="paper-conference">
<!-- For paper-conference, don't print publisher if in a journal-like proceedings -->
<choose>
- <if variable="collection-editor editor editorial-director" match="any">
+ <if variable="collection-editor compiler editor editorial-director" match="any">
<text variable="publisher"/>
</if>
</choose>
</else-if>
- <else-if type="article-journal article-magazine article-newspaper post-weblog" match="none">
+ <else-if type="article-journal article-magazine article-newspaper periodical post-weblog review review-book" match="none">
<text variable="publisher"/>
</else-if>
</choose>
@@ -1404,15 +1621,27 @@
<!-- With `archive-place`: physical archives. Without: online archives. -->
<!-- For physical archives, print the location before the archive name.
For electronic archives, these are printed in macro="description". -->
- <!-- TODO: Split "archive_location" into "archive_collection" and "archive_location" -->
<!-- Must test for archive_collection:
With collection: archive_collection (archive_location), archive, archive-place
No collection: archive (archive_location), archive-place
-->
- <text variable="archive_location"/>
+ <choose>
+ <if variable="archive_collection">
+ <group delimiter=" ">
+ <text variable="archive_collection"/>
+ <text variable="archive_location" prefix="(" suffix=")"/>
+ </group>
+ <text variable="archive"/>
+ </if>
+ <else>
+ <group delimiter=" ">
+ <text variable="archive"/>
+ <text variable="archive_location" prefix="(" suffix=")"/>
+ </group>
+ </else>
+ </choose>
</if>
</choose>
- <text variable="archive"/>
<text variable="archive-place"/>
</group>
</group>
@@ -1439,19 +1668,30 @@
</choose>
</macro>
<macro name="event">
- <!-- TODO: Add new item types (e.g., event, collection, performance) -->
<choose>
<if variable="event event-title" match="any">
<!-- To prevent Zotero from printing event-place due to its double-mapping of all 'place' to
both publisher-place and event-place. Remove this 'choose' when that is changed. -->
<choose>
- <if variable="collection-editor editor editorial-director issue page volume" match="none">
- <!-- Don't print event info if published in a proceedings -->
+ <if type="paper-conference">
+ <choose>
+ <if variable="collection-editor compiler editor editorial-director issue page volume" match="none">
+ <!-- Don't print event info for conference papers published in a proceedings -->
+ <group delimiter=", ">
+ <text macro="event-title"/>
+ <text variable="event-place"/>
+ </group>
+ </if>
+ </choose>
+ </if>
+ <else>
+ <!-- For other item types, print event info even if published (e.g., for collection catalogs, performance programs.
+ These items aren't given explicit examples in the APA manual, so err on the side of providing too much information. -->
<group delimiter=", ">
<text macro="event-title"/>
<text variable="event-place"/>
</group>
- </if>
+ </else>
</choose>
</if>
</choose>
@@ -1472,19 +1712,30 @@
</macro>
<!-- After 'source', APA also prints publication history (original publication, reprint info, retraction info) -->
<macro name="publication-history">
- <!-- TODO: Add new item types -->
<choose>
- <if type="patent" match="none">
- <group prefix="(" suffix=")">
+ <if type="patent">
+ <text variable="references" prefix="(" suffix=")"/>
+ </if>
+ <else>
+ <group delimiter="; " prefix="(" suffix=")">
+ <!-- Print `status` here for things like "retracted" if it's not printed elsewhere already. -->
<choose>
+ <if variable="issued">
+ <choose>
+ <if variable="issue number page volume" match="any">
+ <text variable="status" text-case="capitalize-first"/>
+ </if>
+ </choose>
+ </if>
+ </choose>
+ <choose>
<if variable="references">
<!-- This provides the option for more elaborate description
- of publication history, such as full "reprinted" references
- (examples 11, 43, 44) or retracted references -->
+ of publication history, such as full "reprinted" references
+ (examples 11, 43, 44) -->
<text variable="references"/>
</if>
<else>
- <!-- TODO: Replace these with terms -->
<group delimiter=" ">
<text term="original-work-published" text-case="capitalize-first"/>
<choose>
@@ -1499,9 +1750,6 @@
</else>
</choose>
</group>
- </if>
- <else>
- <text variable="references" prefix="(" suffix=")"/>
</else>
</choose>
</macro>
@@ -1510,24 +1758,24 @@
<!-- `treaty`: for treaties -->
<!-- `legal_case`: for all legal and court cases -->
<!-- `bill`: for bills, resolutions, federal reports -->
- <!-- `hearing`: TODO for hearings and testimony -->
+ <!-- `hearing`: for hearings and testimony -->
<!-- `legislation`: for statutes, constitutional items, and charters -->
- <!-- `regulation`: TODO codified regulations, uncodified regulations, executive orders -->
+ <!-- `regulation`: codified regulations, uncodified regulations, executive orders -->
<group delimiter=" ">
<choose>
<if type="treaty">
<group delimiter=", " suffix=".">
<!-- APA generally defers to Bluebook for legal citations, but diverges without
- explanation for treaty items. We follow the Bluebook format that was used
+ explanation for treaty items. We follow the Bluebook format that was used
in APA 6th ed. -->
- <!-- APA manual omits treaty parties/authors, but per Bluebook
+ <!-- APA manual omits treaty parties/authors, but per Bluebook
they should be included at least for bilateral treaties. -->
<names variable="author">
<name initialize-with="." form="short" delimiter="-"/>
</names>
<text macro="date-legal"/>
- <!-- APA manual omits treaty source/report called for by Bluebook in favor of just URL.
- Both are included here, following the APA style used for all other item types
+ <!-- APA manual omits treaty source/report called for by Bluebook in favor of just URL.
+ Both are included here, following the APA style used for all other item types
to end the reference with a period, then give the URL afterward. -->
<text macro="container-legal"/>
</group>
@@ -1553,7 +1801,7 @@
<text variable="title" text-case="title"/>
</if>
<else-if type="hearing">
- <!-- APA uses a comma delimiter and omits "hearing before the" for hearings with testimony,
+ <!-- APA uses a comma delimiter and omits "hearing before the" for hearings with testimony,
but follows Bluebook rules (colon delimiter, prefix before the committee name) for
references to the whole hearing. We simply follow the Bluebook rules for both, but
use APA style capitalization (not capitalizing "Before" or the title of the hearing). -->
@@ -1609,7 +1857,7 @@
</group>
<choose>
<if variable="issued">
- <!-- APA manual includes "rev." before the revision year,
+ <!-- APA manual includes "rev." before the revision year,
but this isn't part of the Bluebook rules. -->
<date variable="issued">
<date-part name="year"/>
@@ -1616,7 +1864,7 @@
</date>
</if>
<else>
- <!-- Show proposal date for uncodified regualtions.
+ <!-- Show proposal date for uncodified regualtions.
Assume date is entered literally ala "proposed May 23, 2016".
TODO: Add 'proposed' term here if that becomes available -->
<date variable="submitted" form="text"/>
@@ -1682,10 +1930,10 @@
<text variable="genre"/>
<group delimiter=" ">
<choose>
- <!-- TODO: What was the logic for this? Do we still need this? -->
- <!-- If there is no session number or code/record title, print number.
- Is that trying to capture congressional reports/documents? -->
+ <!-- If there is no session number or code/record title, assume
+ assume the item is a congressional report and include 'No.' term. -->
<if variable="chapter-number container-title" match="none">
+ <!-- The item is a congressional report, rather than a bill or resultion. -->
<label variable="number" form="short" text-case="capitalize-first"/>
</if>
</choose>
@@ -1789,14 +2037,14 @@
</choose>
</macro>
<macro name="citation-locator">
- <!-- TODO: Add new locator types? -->
+ <!-- Abbreviate page and paragraph, leave other locator labels in long form, cf. Rule 8.13 -->
<group delimiter=" ">
<choose>
- <if locator="chapter">
- <label variable="locator" text-case="capitalize-first"/>
+ <if locator="page paragraph" match="any">
+ <label variable="locator" form="short"/>
</if>
<else>
- <label variable="locator" form="short"/>
+ <label variable="locator" text-case="capitalize-first"/>
</else>
</choose>
<text variable="locator"/>
@@ -1827,17 +2075,9 @@
</sort>
<layout>
<choose>
- <!-- TODO: Add new item types -->
<if type="bill hearing legal_case legislation regulation treaty" match="any">
<!-- Legal items have different orders and delimiters -->
- <choose>
- <if variable="DOI URL" match="any">
- <text macro="legal-cites"/>
- </if>
- <else>
- <text macro="legal-cites" suffix="."/>
- </else>
- </choose>
+ <text macro="legal-cites"/>
</if>
<else>
<group delimiter=" ">
Modified: trunk/Master/texmf-dist/tex/latex/citation-style-language/styles/ieee.csl
===================================================================
--- trunk/Master/texmf-dist/tex/latex/citation-style-language/styles/ieee.csl 2024-07-31 23:41:56 UTC (rev 71943)
+++ trunk/Master/texmf-dist/tex/latex/citation-style-language/styles/ieee.csl 2024-08-01 19:56:55 UTC (rev 71944)
@@ -44,8 +44,8 @@
<category citation-format="numeric"/>
<category field="engineering"/>
<category field="generic-base"/>
- <summary>IEEE style as per the 2021 guidelines, V 01.29.2021.</summary>
- <updated>2024-01-11T14:39:58-05:00</updated>
+ <summary>IEEE style as per the 2023 guidelines, V 11.29.2023.</summary>
+ <updated>2024-07-15T10:30:07-04:00</updated>
<rights license="http://creativecommons.org/licenses/by-sa/3.0/">This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 License</rights>
</info>
<locale xml:lang="en">
@@ -56,6 +56,7 @@
</date>
<terms>
<term name="chapter" form="short">ch.</term>
+ <term name="chapter-number" form="short">ch.</term>
<term name="presented at">presented at the</term>
<term name="available at">available</term>
</terms>
@@ -120,6 +121,7 @@
<substitute>
<names variable="editor"/>
<names variable="translator"/>
+ <text macro="director"/>
</substitute>
</names>
</macro>
@@ -129,6 +131,12 @@
<label form="short" prefix=", " text-case="capitalize-first"/>
</names>
</macro>
+ <macro name="director">
+ <names variable="director">
+ <name and="text" et-al-min="7" et-al-use-first="1" initialize-with=". "/>
+ <et-al font-style="italic"/>
+ </names>
+ </macro>
<macro name="locators">
<group delimiter=", ">
<text macro="edition"/>
@@ -148,7 +156,7 @@
</macro>
<macro name="title">
<choose>
- <if type="bill book graphic legal_case legislation motion_picture song" match="any">
+ <if type="bill book graphic legal_case legislation motion_picture song standard software" match="any">
<text variable="title" font-style="italic"/>
</if>
<else>
@@ -374,6 +382,10 @@
<text macro="collection"/>
<text macro="publisher"/>
<text macro="issued"/>
+ <group delimiter=" ">
+ <label variable="chapter-number" form="short"/>
+ <text variable="chapter-number"/>
+ </group>
<text macro="page"/>
</group>
<text macro="access"/>
@@ -399,6 +411,26 @@
</group>
<text macro="access"/>
</else-if>
+ <else-if type="software">
+ <group delimiter=". " suffix=".">
+ <text macro="title"/>
+ <text macro="issued" prefix="(" suffix=")"/>
+ <text variable="genre"/>
+ <text macro="publisher"/>
+ </group>
+ <text macro="access"/>
+ </else-if>
+ <else-if type="article">
+ <group delimiter=", " suffix=".">
+ <text macro="title"/>
+ <text macro="issued"/>
+ <group delimiter=": ">
+ <text macro="publisher" font-style="italic"/>
+ <text variable="number"/>
+ </group>
+ </group>
+ <text macro="access"/>
+ </else-if>
<else-if type="webpage post-weblog post" match="any">
<group delimiter=", " suffix=".">
<text macro="title"/>
@@ -423,6 +455,18 @@
</group>
<text macro="access"/>
</else-if>
+ <else-if type="standard">
+ <group delimiter=", " suffix=".">
+ <text macro="title"/>
+ <group delimiter=" ">
+ <text variable="genre"/>
+ <text variable="number"/>
+ </group>
+ <text macro="geographic-location"/>
+ <text macro="issued"/>
+ </group>
+ <text macro="access"/>
+ </else-if>
<!-- Generic/Fallback Formats -->
<else-if type="bill book graphic legal_case legislation report song" match="any">
<group delimiter=", " suffix=". ">
More information about the tex-live-commits
mailing list.