use rowan::TextRange;
use crate::bib::semantic::Model;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct BibOutlineItem {
pub name: String,
pub detail: String,
pub range: TextRange,
pub selection_range: TextRange,
}
pub fn outline(model: &Model) -> Vec<BibOutlineItem> {
model
.entries()
.iter()
.map(|entry| BibOutlineItem {
name: entry.key.to_string(),
detail: entry.entry_type.to_string(),
range: entry.range,
selection_range: entry.key_range,
})
.collect()
}
#[cfg(test)]
mod tests {
use super::*;
use crate::bib::parse;
fn outline_of(src: &str) -> Vec<BibOutlineItem> {
outline(&Model::build(&parse(src).syntax()))
}
#[test]
fn one_item_per_entry_in_source_order() {
let items = outline_of("@article{b, title = {B}}\n@book{a, title = {A}}\n");
let names: Vec<&str> = items.iter().map(|i| i.name.as_str()).collect();
assert_eq!(names, vec!["b", "a"]);
assert_eq!(items[0].detail, "article");
assert_eq!(items[1].detail, "book");
}
#[test]
fn string_and_comment_blocks_are_omitted() {
let items = outline_of("@string{cup = {C}}\n@comment{x}\n@misc{k, title = {T}}\n");
let names: Vec<&str> = items.iter().map(|i| i.name.as_str()).collect();
assert_eq!(names, vec!["k"]);
}
#[test]
fn selection_range_is_the_key() {
let src = "@article{key, title = {T}}\n";
let items = outline_of(src);
assert_eq!(items.len(), 1);
let sel = &src[items[0].selection_range];
assert_eq!(sel, "key");
}
}