citum_engine/values/
list.rs1use crate::reference::Reference;
12use crate::values::{ComponentValues, ProcHints, ProcValues, RenderOptions};
13use citum_schema::template::{DelimiterPunctuation, TemplateGroup};
14
15impl ComponentValues for TemplateGroup {
16 fn values<F: crate::render::format::OutputFormat<Output = String>>(
18 &self,
19 reference: &Reference,
20 hints: &ProcHints,
21 options: &RenderOptions<'_>,
22 ) -> Option<ProcValues<F::Output>> {
23 let mut has_content = false;
24 let fmt = F::default();
25
26 let mut values = Vec::with_capacity(self.group.len());
28 for item in &self.group {
29 let Some(v) = item.values::<F>(reference, hints, options) else {
30 continue;
31 };
32 if v.value.is_empty() {
33 continue;
34 }
35
36 if !is_term_based(item) {
38 has_content = true;
39 }
40
41 let proc_item = crate::render::ProcTemplateComponent {
43 template_component: item.clone(),
44 template_index: options.current_template_index,
45 value: v.value,
46 prefix: v.prefix,
47 suffix: v.suffix,
48 url: v.url,
49 ref_type: Some(reference.ref_type().clone()),
50 config: Some(options.config.clone()),
51 bibliography_config: options.bibliography_config.clone(),
52 item_language: crate::values::effective_component_language(reference, item),
53 quote_marks: crate::render::format::QuoteMarks::from(options.locale),
54 sentence_initial: false,
55 pre_formatted: v.pre_formatted,
56 label_only: false,
57 };
58
59 let rendered = crate::render::render_component_with_format_and_renderer::<F>(
60 &proc_item,
61 &fmt,
62 options.show_semantics,
63 );
64 if !rendered.is_empty() {
65 values.push(rendered);
66 }
67 }
68
69 if values.is_empty() || !has_content {
70 return None;
71 }
72
73 let default_delimiter = DelimiterPunctuation::Comma;
75 let punctuation = self.delimiter.as_ref().unwrap_or(&default_delimiter);
76 let (script, realization) = crate::values::punctuation_realization_context(
77 crate::values::effective_item_language(reference).as_deref(),
78 options.config.multilingual.as_ref(),
79 options.locale.punctuation_realization.as_ref(),
80 );
81 let delimiter = crate::render::format::realize_punctuation(
82 punctuation,
83 script,
84 realization.as_deref(),
85 crate::render::format::PunctuationPosition::Separator,
86 );
87
88 let delimiter = if punctuation.is_semantic() {
89 fmt.text(&delimiter)
90 } else {
91 delimiter.into_owned()
92 };
93 let escaped_delimiter = fmt.join(vec![String::new(), String::new()], &delimiter);
98 let escaped_delimiter =
99 crate::render::format::RealizedPunctuation::new(escaped_delimiter.into());
100
101 let close_quote = crate::render::format::QuoteMarks::from(options.locale).close;
102 let joined = crate::render::punctuation::join_with_quote_movement(
103 values,
104 &escaped_delimiter,
105 options.config.punctuation_in_quote,
106 &close_quote,
107 );
108
109 Some(ProcValues {
110 value: joined,
111 prefix: None,
112 suffix: None,
113 url: None,
114 substituted_key: None,
115 pre_formatted: true,
116 })
117 }
118}
119
120fn is_term_based(component: &citum_schema::template::TemplateComponent) -> bool {
122 use citum_schema::template::TemplateComponent;
123 match component {
124 TemplateComponent::Term(_) => true,
125 TemplateComponent::Message(message) if message.message.starts_with("term.") => true,
126 TemplateComponent::Group(l) => l.group.iter().all(is_term_based),
127 _ => false,
128 }
129}