summaryrefslogtreecommitdiff
path: root/biblio/citation-style-language/citeproc-node-text.lua
blob: fae35350139b899adc5dab4cc5520134dedc780f (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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
--
-- Copyright (c) 2021-2022 Zeping Lee
-- Released under the MIT license.
-- Repository: https://github.com/zepinglee/citeproc-lua
--

local text_module = {}

local Element = require("citeproc-element").Element
local Rendered = require("citeproc-ir-node").Rendered
local YearSuffix = require("citeproc-ir-node").YearSuffix
local PlainText = require("citeproc-output").PlainText
local Linked = require("citeproc-output").Linked
local util = require("citeproc-util")


-- [Text](https://docs.citationstyles.org/en/stable/specification.html#text)
local Text = Element:derive("text", {
  -- Default attributes
  variable = nil,
  form = "long",
  macro = nil,
  term = nil,
  plural = false,
  value = nil,
  -- Style behavior
  formatting = nil,
  affixes = nil,
  delimiter = nil,
  display = nil,
  quotes = false,
  strip_periods = false,
  text_case = nil,
})

function Text:from_node(node)
  local o = Text:new()
  o:set_attribute(node, "variable")
  o:set_attribute(node, "form")
  o:set_attribute(node, "macro")
  o:set_attribute(node, "term")
  o:set_bool_attribute(node, "plural")
  o:set_attribute(node, "value")

  o:set_formatting_attributes(node)
  o:set_affixes_attributes(node)
  o:set_display_attribute(node)
  o:set_quotes_attribute(node)
  o:set_strip_periods_attribute(node)
  o:set_text_case_attribute(node)
  return o
end

function Text:build_ir(engine, state, context)
  local ir = nil
  if self.variable then
    ir = self:build_variable_ir(engine, state, context)
  elseif self.macro then
    ir = self:build_macro_ir(engine, state, context)
  elseif self.term then
    ir = self:build_term_ir(engine, state, context)
  elseif self.value then
    ir = self:build_value_ir(engine, state, context)
  end
  return ir
end

function Text:build_variable_ir(engine, state, context)
  local variable = self.variable
  local text

  if variable == "year-suffix" then
    return self:build_year_suffix_ir(engine, state, context)
  end

  if not state.suppressed[variable] then
    text = context:get_variable(variable, self.form)
  end

  if not text then
    local ir = Rendered:new({}, self)
    ir.group_var = "missing"
    return ir
  end
  if type(text) == "number" then
    text = tostring(text)
  end
  if util.variable_types[variable] == "number" then
    text = self:format_number(text, variable, "numeric", context)
  end

  local inlines
  if (variable == "URL" and engine.opt.url_link) or
     (variable == "DOI" and engine.opt.doi_link) or
     (variable == "PMID" and engine.opt.doi_link) or
     (variable == "PMID" and engine.opt.doi_link) then
    inlines = self:render_linked(engine, state, context, variable, text)
  else
    inlines = self:render_text_inlines(text, context)
  end

  local ir = Rendered:new(inlines, self)
  ir.group_var = "important"

  if variable == "citation-number" then
    ir.citation_number = context.reference["citation-number"]
  end

  -- Suppress substituted name variable
  if state.name_override and not context.sort_key then
    state.suppressed[variable] = true
  end

  return ir
end

function Text:render_linked(engine, state, context, variable, text)
  local href
  if variable == "URL" then
    href = text
  elseif self.affixes and self.affixes.prefix then
    if string.match(self.affixes.prefix, "https?://") then
      text = self.affixes.prefix .. text
      self.affixes.prefix = nil
      href = text
    end
  elseif variable == "DOI" then
    href = "https://doi.org/" .. text
  elseif variable == "PMID" then
    href = "https://www.ncbi.nlm.nih.gov/pubmed/" .. text
  elseif variable == "PMCID" then
    href = "https://www.ncbi.nlm.nih.gov/pmc/articles/" .. text
  end
  local inlines = {Linked:new(text, href)}
  local output_format = context.format
  local localized_quotes = nil
  if self.quotes then
    localized_quotes = context:get_localized_quotes()
  end
  inlines = output_format:with_format(inlines, self.formatting)
  inlines = output_format:affixed_quoted(inlines, self.affixes, localized_quotes)
  return output_format:with_display(inlines, self.display)
end

function Text:build_year_suffix_ir(engine, state, context)
  local text = context:get_variable(self.variable, self.form)
  local group_var
  if text then
    group_var = "important"
  else
    text = ""
    group_var = "missing"
  end

  local ir = YearSuffix:new({PlainText:new(text)}, self)
  ir.group_var = group_var
  ir.affixes = util.clone(self.affixes)
  ir.display = self.display
  ir.formatting = util.clone(self.formatting)
  if self.quotes then
    ir.quotes = context:get_localized_quotes()
  end
  return ir
end

function Text:build_macro_ir(engine, state, context)
  local macro = context:get_macro(self.macro)
  state:push_macro(self.macro)
  local ir = macro:build_ir(engine, state, context)
  state:pop_macro(self.macro)
  if ir then
    ir.affixes = util.clone(self.affixes)
    ir.display = self.display
    ir.formatting = util.clone(self.formatting)
    if self.quotes then
      ir.quotes = context:get_localized_quotes()
    end
  end
  return ir
end

function Text:build_term_ir(engine, state, context)
  local str = context:get_simple_term(self.term, self.form, self.plural)
  if not str then
    return nil
  end
  local inlines = self:render_text_inlines(str, context)
  return Rendered:new(inlines, self)
end

function Text:build_value_ir(engine, state, context)
  local inlines = self:render_text_inlines(self.value, context)
  return Rendered:new(inlines, self)
end


text_module.Text = Text

return text_module