summaryrefslogtreecommitdiff
path: root/paper/lua-filters/section-refs/section-refs.lua
blob: 68e61d0dac13efae3bbd620e6b3f23f15b9ae9a1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
function is_ref_div (blk)
   return (blk.t == "Div" and blk.identifier == "refs")
end

function is_ref_header (blk)
   return (blk.t == "Header" and blk.identifier == "bibliography")
end

function get_all_refs (blks)
   for _, b in pairs(blks) do
      if is_ref_div(b) then
	 return b.content
      end
   end
end

function remove_all_refs (blks)
   local out = {}
   for _, b in pairs(blks) do
      if not (is_ref_div(b) or is_ref_header(b)) then
	 table.insert(out, b)
      end
   end
   return out
end

-- We return a {number, ref} pair so we can sort in the individual
-- bibliographies.
function citation_to_numbered_ref (citation, all_refs)
   local div_id = "ref-" .. citation.id
   for i, d in ipairs(all_refs) do
      if d.t == "Div" and d.identifier == div_id then
	 return {i, d}
      end
   end
end


function get_partial_refs (blocks, all_refs)
   local cites = {}
   local citegetter = {
      Cite = function (el)
	 for _, c in pairs(el.citations) do
	    table.insert(cites, c)
	 end
      end
   }

   for _, b in pairs(blocks) do
      pandoc.walk_block(b, citegetter)
   end


   -- first we make a list of the {number, ref} pairs so we can sort
   -- them. Then after sorting, we're going to make a new list with
   -- only the second element.
   local numbered_refs = {}
   for _, c in pairs(cites) do
      local r = citation_to_numbered_ref(c, all_refs)
      if r then
	 table.insert(numbered_refs, r)
      end
   end

   table.sort(numbered_refs, function(x, y) return x[1] < y[1] end)

   local refs = {}
   for _, nr in pairs(numbered_refs) do
      table.insert(refs, nr[2])
   end

   return refs
end

function add_section_refs (blks, lvl, refs_title, all_refs)
   local output_blks = {}
   local section = {}
   local refs_num = 0

   local go = function ()
      refs_num = refs_num + 1
      local section_refs = get_partial_refs(section, all_refs)
      if refs_title then
	 local hdr = pandoc.Header(lvl + 1,
				   refs_title,
				   pandoc.Attr("bibliography-" .. tostring(refs_num),
					       {"unnumbered"}))
	 table.insert(section_refs, 1, hdr)
      end
      local refs_div = pandoc.Div(section_refs,
				  pandoc.Attr("refs-" .. tostring(refs_num),
					      {"references"}))
      table.insert(section, refs_div)
      for _, x in pairs(section) do
	 table.insert(output_blks, x)
      end
   end

   -- to avoid putting a bib after an intro paragraph.
   local seen_hdr_before = false
   for _, b in pairs(blks) do
      if b.t == "Header" and b.level <= lvl then
	 if seen_hdr_before then
	    go()
	    section = {b}
	 else
	    seen_hdr_before = true
	    table.insert(section, b)
	 end
      else
	 table.insert(section, b)
      end
   end
   go()
   return output_blks
end

function Pandoc(doc)
   if PANDOC_VERSION == nil then -- if pandoc_version < 2.1
      io.stderr:write("WARNING: pandoc >= 2.1 required for section-refs filter\n")
      return doc
   end
   local refs_title = doc.meta["reference-section-title"]
   -- if we get it from a command-line field, read it in as md.
   if type(refs_title) == "string" then
      refs_title = pandoc.read(refs_title, "markdown").blocks[1].content
   end
   local lvl = tonumber(doc.meta["section-refs-level"]) or 1
   local all_refs = get_all_refs(doc.blocks)
   -- we only want to do something if there are refs to work
   -- with. This way, if this is run without pandoc-citeproc, it will
   -- just return the same document.
   if all_refs then
      local unreffed = remove_all_refs(doc.blocks)
      local output = add_section_refs(unreffed, lvl, refs_title, all_refs)
      return pandoc.Pandoc(output, doc.meta)
   end
end