Skip to content

Commit

Permalink
Fix note position in multiple chapters (#72)
Browse files Browse the repository at this point in the history
  • Loading branch information
zepinglee committed Aug 19, 2024
1 parent fbd557b commit de595ea
Show file tree
Hide file tree
Showing 14 changed files with 8,141 additions and 4 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Fixed

- Fix note position in multiple chapters ([#72](https://github.com/zepinglee/citeproc-lua/discussions/72)).

## [0.6.1] - 2024-08-15

### Fixed
Expand Down
106 changes: 102 additions & 4 deletions citeproc/citeproc-engine.lua
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,13 @@ local SortStringFormat = output.SortStringFormat
local Position = util.Position


---@alias CitationId string
---@alias ItemId string | number
---@alias NoteIndex integer
---@alias CitationId string
---@alias ChapterIndex number
---@alias CitationData {citationID: CitationId, citationItems: CitationItem[], properties: CitationProperties, citation_index: integer}

---@alias CitationProperties { noteIndex: integer, mode: string? }
---@alias CitationProperties { noteIndex: NoteIndex, chapterIndex: ChapterIndex, mode: string? }

---@class NameVariable
---@field family string?
Expand Down Expand Up @@ -294,14 +295,18 @@ function CiteProc:updateUncitedItems(uncited_ids)
end


---@alias PreCitation [CitationId, NoteIndex, ChapterIndex]
---@alias PostCitation [CitationId, NoteIndex, ChapterIndex]

---@param citation CitationData
---@param citationsPre (CitationId | NoteIndex)[]
---@param citationsPost (CitationId | NoteIndex)[]
---@param citationsPre PreCitation[]
---@param citationsPost PostCitation[]
---@return (table | (integer | string | CitationId)[])[]
function CiteProc:processCitationCluster(citation, citationsPre, citationsPost)
-- util.debug(string.format('processCitationCluster(%s)', citation.citationID))
self:check_valid_citation_element()
citation = self:normalize_citation_input(citation)
self:_check_input(citation, citationsPre, citationsPost)

-- Registor citation
self.registry.citations_by_id[citation.citationID] = citation
Expand Down Expand Up @@ -406,6 +411,9 @@ function CiteProc:normalize_citation_input(citation)
if not citation.properties.noteIndex then
citation.properties.noteIndex = 0
end
if not citation.properties.chapterIndex then
citation.properties.chapterIndex = 0
end

return citation
end
Expand Down Expand Up @@ -451,6 +459,83 @@ function CiteProc:normalize_cite_item(cite_item)
return cite_item
end

---@param citation CitationData
---@param citationsPre PreCitation[]
---@param citationsPost PostCitation[]
function CiteProc:_check_input(citation, citationsPre, citationsPost)
---@type {[CitationId]: boolean}
local citation_dict = {}
local last_note_number = 0
local last_chapter_number = 0

for i, pre_citation in ipairs(citationsPre) do
local citation_id = pre_citation[1]
local note_number = pre_citation[2]
local chapter_number = pre_citation[3]
if citation_dict[citation_id] then
error(string.format("Previously referenced citationID '%s' encountered in citationsPre", citation_id))
end
if note_number and note_number > 0 then
if note_number < last_note_number then
util.warning(string.format("Note index sequence is not sane at citationsPre[%d]", i))
end
last_note_number = note_number
end
if chapter_number and chapter_number > 0 then
if chapter_number < last_chapter_number then
util.warning(string.format("Chapter index sequence is not sane at citationsPre[%d]", i))
end
last_chapter_number = chapter_number
end
citation_dict[citation_id] = true
end

do
local citation_id = citation.citationID
local note_number = citation.properties.noteIndex
local chapter_number = citation.properties.chapterIndex
if (citation_dict[citation_id]) then
error("Citation with previously referenced citationID " .. citation_id)
end
if note_number and note_number > 0 then
if note_number < last_note_number then
util.warning("Note index sequence is not sane for citation " .. citation_id)
end
last_note_number = note_number
end
if chapter_number and chapter_number > 0 then
if chapter_number < last_chapter_number then
util.warning("Chapter index sequence is not sane for citation " .. citation_id)
end
last_chapter_number = chapter_number
end
citation_dict[citation_id] = true
end

for i, post_citation in ipairs(citationsPost) do
local citation_id = post_citation[1]
local note_number = post_citation[2]
local chapter_number = post_citation[3]
if citation_dict[citation_id] then
error(string.format("Previously referenced citationID '%s' encountered in citationsPost", citation_id))
end
if note_number and note_number > 0 then
if note_number < last_note_number then
util.warning(string.format("Note index sequence is not sane at citationsPost[%d]", i))
end
last_note_number = note_number
end
if chapter_number and chapter_number > 0 then
if chapter_number < last_chapter_number then
util.warning(string.format("Chapter index sequence is not sane at citationsPost[%d]", i))
end
last_chapter_number = chapter_number
end
citation_dict[citation_id] = true
end

end

-- A variant of processCitationCluster() for easy use with LaTeX.
-- It should be run after refreshing the registry (updateItems()) with all items
function CiteProc:process_citation(citation)
Expand Down Expand Up @@ -517,6 +602,8 @@ function CiteProc:get_tainted_citation_ids(citation_note_pairs)
-- have position properties.
local in_text_citations = {}

local last_chapter_number = 0

local previous_citation
for citation_index, pair in ipairs(citation_note_pairs) do
local citation_id, note_number = table.unpack(pair)
Expand All @@ -525,6 +612,15 @@ function CiteProc:get_tainted_citation_ids(citation_note_pairs)
citation.properties.noteIndex = note_number
citation.citation_index = citation_index

local chapter_number = citation.properties.chapterIndex
if chapter_number and chapter_number ~= last_chapter_number then
self.cite_first_note_numbers = {}
self.cite_last_note_numbers = {}
self.note_citations_map = {}
previous_citation = nil
end


local tainted = false

local prev_citation = previous_citation
Expand Down Expand Up @@ -559,6 +655,8 @@ function CiteProc:get_tainted_citation_ids(citation_note_pairs)
previous_citation = citation
end
end

last_chapter_number = chapter_number
end

-- Update tainted citation ids because of citation-number's change
Expand Down
9 changes: 9 additions & 0 deletions citeproc/citeproc-manager.lua
Original file line number Diff line number Diff line change
Expand Up @@ -573,6 +573,15 @@ function CslCitationManager:_make_citation(citation_info)
util.error(string.format("Invalid note index '%s'.", note_index))
end

local chapter_index = citation.properties.chapterIndex
if not chapter_index or chapter_index == "" then
citation.properties.chapterIndex = nil
elseif type(chapter_index) == "string" and string.match(chapter_index, "^%d+$") then
citation.properties.chapterIndex = tonumber(chapter_index)
else
util.error(string.format("Invalid chapter index '%s'.", chapter_index))
end

-- util.debug(citation)
return citation
end
Expand Down
5 changes: 5 additions & 0 deletions latex/citation-style-language-cite.sty
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,11 @@
\__csl_process_citation_id:NN \l__csl_citation_id_tl #1
\__csl_get_note_index:N \l__csl_note_index_tl
\prop_put:NnV \l__csl_citation_properties_prop { noteIndex } \l__csl_note_index_tl
\int_if_exist:NT \c@chapter
{
\prop_put:Nnx \l__csl_citation_properties_prop { chapterIndex }
{ \int_use:N \c@chapter }
}
\__csl_add_back_ref_info:
}

Expand Down
1 change: 1 addition & 0 deletions scripts/testjs.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@
cp "$@" ../citeproc-js/fixtures/local/lua_tmp.txt
cd ../citeproc-js
cslrun -s lua_tmp
rm ../citeproc-js/fixtures/local/lua_tmp.txt
Loading

0 comments on commit de595ea

Please sign in to comment.