Skip to content

Commit

Permalink
Sort stuff
Browse files Browse the repository at this point in the history
  • Loading branch information
reknih committed Oct 14, 2023
1 parent b307aa1 commit 229dcaf
Show file tree
Hide file tree
Showing 6 changed files with 366 additions and 123 deletions.
79 changes: 63 additions & 16 deletions src/csl/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,25 @@ use std::num::NonZeroUsize;

use citationberg::taxonomy::{Locator, OtherTerm, Term, Variable};
use citationberg::{
taxonomy as csl_taxonomy, Affixes, CslMacro, Display, FontStyle, FontVariant,
FontWeight, InheritableNameOptions, Locale, LocaleCode, Style, TermForm,
TextDecoration, VerticalAlign,
taxonomy as csl_taxonomy, Affixes, Bibliography, Citation, CslMacro, Display,
FontStyle, FontVariant, FontWeight, InheritableNameOptions, Locale, LocaleCode,
Style, TermForm, TextDecoration, ToFormatting, VerticalAlign,
};
use citationberg::{
DateForm, IndependentStyleSettings, LongShortForm, OrdinalLookup, TextCase,
};

use crate::csl::rendering::RenderCsl;
use crate::csl::taxonomy::resolve_name_variable;
use crate::lang::CaseFolder;
use crate::types::{ChunkKind, ChunkedString, Date, MaybeTyped, Numeric, Person};
use crate::Entry;

mod rendering;
mod sort;
mod taxonomy;

use taxonomy::{
resolve_date_variable, resolve_number_variable, resolve_standard_variable,
};
use taxonomy::{resolve_date_variable, resolve_standard_variable};

/// A context that contains all information related to rendering a single entry.
#[derive(Debug, Clone, Copy, PartialEq)]
Expand Down Expand Up @@ -62,6 +62,10 @@ pub(crate) struct StyleContext<'a> {
locale_file: &'a [Locale],
/// Which locale we're using.
locale: LocaleCode,
/// Citation style.
citation: &'a Citation,
/// Bibliography layout.
bibliography: Option<&'a Bibliography>,
}

impl<'a> StyleContext<'a> {
Expand All @@ -79,6 +83,8 @@ impl<'a> StyleContext<'a> {
locale,
style_locales: style.locale.as_slice(),
locale_file,
citation: style.citation.as_ref()?,
bibliography: style.bibliography.as_ref(),
})
}

Expand All @@ -101,8 +107,43 @@ impl<'a> StyleContext<'a> {
writing: WritingContext::new(),
}
}

pub fn citation(&self, items: &mut [CitationItem<'_>]) -> Vec<ElemChild> {
self.sort(items, self.citation.sort.as_ref());
let mut res = Vec::new();

for CitationItem(entry, locator) in items.iter() {
let mut ctx = self.ctx(entry, CiteProperties::with_locator(*locator));
ctx.writing.push_name_options(&self.citation.name_options);
self.citation.layout.render(&mut ctx);
res.extend(ctx.flush());
}

if res.iter().all(|c| !c.has_content()) {
return Vec::new();
}

let root_fmt = Formatting::default().apply(self.citation.layout.to_formatting());
if let Some(prefix) = &self.citation.layout.prefix {
res.insert(
0,
ElemChild::Text(Formatted { text: prefix.clone(), formatting: root_fmt }),
);
}

if let Some(suffix) = &self.citation.layout.suffix {
res.push(ElemChild::Text(Formatted {
text: suffix.clone(),
formatting: root_fmt,
}));
}

simplify_children(res)
}
}

pub struct CitationItem<'a>(&'a Entry, Option<SpecificLocator<'a>>);

impl<'a> StyleContext<'a> {
/// Retrieve a macro.
fn get_macro(&self, name: &str) -> Option<&'a CslMacro> {
Expand Down Expand Up @@ -335,7 +376,7 @@ impl WritingContext {
self.format_stack.len()
);

simplify_children(self.elem_stack.finish())
self.elem_stack.finish()
}

/// Note that we have used a macro that had non-empty content.
Expand Down Expand Up @@ -464,7 +505,7 @@ pub(crate) struct Context<'a> {
writing: WritingContext,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[derive(Debug, Clone, Default, Copy, PartialEq, Eq)]
pub struct CiteProperties<'a> {
/// Whether this citation is in a note and within `near-note-distance` to
/// the previous citation of the same item.
Expand All @@ -480,9 +521,18 @@ pub struct CiteProperties<'a> {
/// if not disambiguated by `choose`.
pub is_disambiguation: bool,
/// Locator with its type.
pub locator: Option<(Locator, &'a str)>,
pub locator: Option<SpecificLocator<'a>>,
}

impl<'a> CiteProperties<'a> {
fn with_locator(locator: Option<SpecificLocator<'a>>) -> Option<Self> {
Some(Self { locator, ..Self::default() })
}
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct SpecificLocator<'a>(Locator, &'a str);

impl<'a> Context<'a> {
/// Push a format on top of the stack if it is not empty.
fn push_format(&mut self, format: citationberg::Formatting) -> FormatIdx {
Expand Down Expand Up @@ -712,7 +762,7 @@ impl<'a> Context<'a> {
variable: csl_taxonomy::NumberVariable,
) -> Option<MaybeTyped<Cow<'a, Numeric>>> {
self.writing.prepare_variable_query(variable)?;
let res = resolve_number_variable(self.instance.entry, variable);
let res = self.instance.resolve_number_variable(variable);

if res.is_some() {
self.writing.usage_info.borrow_mut().last_mut().has_non_empty_vars = true;
Expand Down Expand Up @@ -1279,14 +1329,11 @@ mod tests {
let style_ctx = StyleContext::new(&style, locale, &en_locale).unwrap();

for entry in &bib {
let mut ctx = style_ctx.ctx(entry, None);
let cit_style = style.citation.as_ref().unwrap();
ctx.writing.push_name_options(&cit_style.name_options);

cit_style.layout.render(&mut ctx);
let mut item = [CitationItem(entry, None)];
let citation = style_ctx.citation(&mut item);
let mut buf = String::new();

for e in dbg!(ctx.flush()) {
for e in citation {
e.write_buf(&mut buf, BufWriteFormat::VT100).unwrap();
}

Expand Down
97 changes: 72 additions & 25 deletions src/csl/rendering.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,13 +84,18 @@ impl RenderCsl for citationberg::Text {

impl RenderCsl for citationberg::Number {
fn render(&self, ctx: &mut Context) {
let depth = ctx.push_elem(self.formatting);
let value = ctx.resolve_number_variable(self.variable);
if ctx.instance.sorting {
if let Some(MaybeTyped::Typed(n)) = value {
n.fmt_value(ctx, true).unwrap();
return;
}
}

let depth = ctx.push_elem(self.formatting);
let affix_loc = ctx.apply_prefix(&self.affixes);

let cidx = ctx.push_case(self.text_case);

let value = ctx.resolve_number_variable(self.variable);
match value {
Some(MaybeTyped::Typed(num)) if num.will_transform() => {
let normal_num = if self.form == NumberForm::Numeric
Expand Down Expand Up @@ -189,6 +194,51 @@ impl RenderCsl for citationberg::Date {
let Some(variable) = self.variable else { return };
let Some(date) = ctx.resolve_date_variable(variable) else { return };

if ctx.instance.sorting {
let year;
let mut month = false;
let mut day = false;

if self.is_localized() {
match self.parts {
Some(DateParts::Year) => year = true,
Some(DateParts::YearMonth) => {
year = true;
month = true;
}
Some(DateParts::YearMonthDay) | None => {
year = true;
month = true;
day = true;
}
}
} else {
year = self.date_part.iter().any(|i| i.name == DatePartName::Year);
month = self.date_part.iter().any(|i| i.name == DatePartName::Month);
day = self.date_part.iter().any(|i| i.name == DatePartName::Day);
};

if year {
write!(ctx, "{:04}", date.year).unwrap();
}

if month {
write!(
ctx,
"{:02}",
date.month.map(|m| m as i32 + 1).unwrap_or_default()
)
.unwrap();
}

if day {
write!(ctx, "{:02}", date.day.map(|d| d as i32 + 1).unwrap_or_default())
.unwrap();
}

return;
}

let base = if let Some(form) = self.form {
let Some(base) = ctx.localized_date(form) else { return };
Some(base)
Expand Down Expand Up @@ -401,12 +451,14 @@ impl RenderCsl for Names {
let plural = persons.len() != 1;
add_names(self, ctx, persons);

if let Some(label) = &self.label {
render_label_with_var(
label,
ctx,
ctx.term(term, label.form, plural).unwrap_or_default(),
)
if !ctx.instance.sorting {
if let Some(label) = &self.label {
render_label_with_var(
label,
ctx,
ctx.term(term, label.form, plural).unwrap_or_default(),
)
}
}

if i > 0 {
Expand Down Expand Up @@ -445,10 +497,13 @@ fn add_names(names: &citationberg::Names, ctx: &mut Context, persons: Vec<&Perso
let et_al_use_last =
names.options.et_al_use_last.unwrap_or_default() && take + 2 <= persons.len();
let mut last_inverted = false;
let demote_non_dropping = matches!(
ctx.style.settings.demote_non_dropping_particle,
DemoteNonDroppingParticle::DisplayAndSort
);

let demote_non_dropping = match ctx.style.settings.demote_non_dropping_particle {
DemoteNonDroppingParticle::Never => false,
DemoteNonDroppingParticle::SortOnly => ctx.instance.sorting,
DemoteNonDroppingParticle::DisplayAndSort => true,
};

let name_opts = names.name.options(&names.options);

for (i, name) in persons.iter().take(take).enumerate() {
Expand Down Expand Up @@ -506,7 +561,6 @@ fn add_names(names: &citationberg::Names, ctx: &mut Context, persons: Vec<&Perso
write_name(
name,
ctx,
false,
name_opts.form == NameForm::Long,
reverse,
demote_non_dropping,
Expand All @@ -523,7 +577,6 @@ fn add_names(names: &citationberg::Names, ctx: &mut Context, persons: Vec<&Perso
write_name(
name,
ctx,
false,
name_opts.form == NameForm::Long,
matches!(names.options.name_as_sort_order, Some(NameAsSortOrder::All)),
demote_non_dropping,
Expand Down Expand Up @@ -554,7 +607,6 @@ fn add_names(names: &citationberg::Names, ctx: &mut Context, persons: Vec<&Perso
fn write_name(
name: &Person,
ctx: &mut Context,
sorting: bool,
long: bool,
reverse: bool,
demote_non_dropping: bool,
Expand Down Expand Up @@ -718,7 +770,7 @@ fn write_name(
};

match (long, reverse, demote_non_dropping) {
_ if name.is_institutional() && sorting => {
_ if name.is_institutional() && ctx.instance.sorting => {
let idx = ctx.push_format(family_format);
let cidx = ctx.push_case(family_case);
// TODO make locale aware
Expand Down Expand Up @@ -752,8 +804,9 @@ fn write_name(
}
}
}
(true, _, false) if sorting => reverse_keep_particle(ctx),
(true, _, true) if sorting => reverse_demote_particle(ctx),
// Always reverse when sorting.
(true, _, false) if ctx.instance.sorting => reverse_keep_particle(ctx),
(true, _, true) if ctx.instance.sorting => reverse_demote_particle(ctx),
(true, true, false) => reverse_keep_particle(ctx),
(true, true, true) => reverse_demote_particle(ctx),
(true, false, _) => {
Expand Down Expand Up @@ -1151,13 +1204,7 @@ impl RenderCsl for citationberg::LayoutRenderingElement {
impl RenderCsl for citationberg::Layout {
fn render(&self, ctx: &mut Context) {
let fidx = ctx.push_format(self.to_formatting());

let affixes = self.to_affixes();
let affix_pos = ctx.apply_prefix(&affixes);

render_with_delimiter(&self.elements, self.delimiter.as_deref(), ctx);

ctx.apply_suffix(&affixes, affix_pos);
ctx.pop_format(fidx);
}
}
Expand Down
Loading

0 comments on commit 229dcaf

Please sign in to comment.