aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorlukeflo2025-08-23 21:29:35 +0200
committerlukeflo2025-08-23 21:29:35 +0200
commit71632fca42977560aaf77dd521b0b6b51319ec17 (patch)
tree651d5cbaf8cc94a5eb05c84866b0f05a720ca0f0
parent2c1e8342b29b36e09ec90a1cb3d5819c7143273c (diff)
downloadbibiman-71632fca42977560aaf77dd521b0b6b51319ec17.tar.gz
bibiman-71632fca42977560aaf77dd521b0b6b51319ec17.zip
implement a customizable fourth column for `EntryTable`
+ Now one can select a fourth column to be displayed in the config file + Possible values: journaltitle, organization, institution, publisher, pubtype + Defaults to pubtype
-rw-r--r--src/bibiman/bibisetup.rs101
-rw-r--r--src/bibiman/entries.rs29
-rw-r--r--src/bibiman/search.rs6
-rw-r--r--src/config.rs10
-rw-r--r--src/tui/ui.rs14
-rw-r--r--tests/test-config.toml5
6 files changed, 140 insertions, 25 deletions
diff --git a/src/bibiman/bibisetup.rs b/src/bibiman/bibisetup.rs
index 1f8a912..ed189ce 100644
--- a/src/bibiman/bibisetup.rs
+++ b/src/bibiman/bibisetup.rs
@@ -19,6 +19,7 @@ use biblatex::{self, Bibliography};
use biblatex::{ChunksExt, Type};
use color_eyre::owo_colors::OwoColorize;
use itertools::Itertools;
+use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::ffi::{OsStr, OsString};
use std::{fs, path::PathBuf};
@@ -28,6 +29,24 @@ use crate::app;
use crate::cliargs::{self};
use crate::config::BibiConfig;
+/// Custom field used for the fourth column of the `EntryTable`
+#[derive(Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord, Deserialize, Serialize)]
+pub enum CustomField {
+ #[serde(alias = "journaltitle")]
+ Journaltitle,
+ #[serde(alias = "organization")]
+ Organization,
+ #[serde(alias = "institution")]
+ Institution,
+ #[serde(alias = "series")]
+ Series,
+ #[serde(alias = "publisher")]
+ Publisher,
+ #[serde(alias = "pubtype")]
+ #[default]
+ Pubtype,
+}
+
// Set necessary fields
// TODO: can surely be made more efficient/simpler
#[derive(Debug)]
@@ -47,7 +66,7 @@ pub struct BibiData {
pub short_author: String,
pub title: String,
pub year: String,
- pub pubtype: String,
+ pub custom_field: (CustomField, String),
pub keywords: String,
pub citekey: String,
pub abstract_text: String,
@@ -64,14 +83,14 @@ pub struct BibiRow<'a> {
pub authors: &'a str,
pub title: &'a str,
pub year: &'a str,
- pub pubtype: &'a str,
+ pub custom_field_value: &'a str,
pub symbols: &'a [Option<String>; 3],
}
impl BibiData {
// This functions decides which fields are rendered in the entry table
// Fields which should be usable but not visible can be left out
- pub fn ref_vec(&mut self, cfg: &BibiConfig) -> BibiRow {
+ pub fn ref_vec(&mut self, cfg: &BibiConfig) -> BibiRow<'_> {
self.short_author = match self.authors.split_once(",") {
Some((first, _rest)) => {
if self.authors().contains("(ed.)") {
@@ -111,7 +130,7 @@ impl BibiData {
},
title: self.title(),
year: self.year(),
- pubtype: self.pubtype(),
+ custom_field_value: self.custom_field_value(),
symbols: &self.symbols,
}
}
@@ -132,8 +151,8 @@ impl BibiData {
&self.year
}
- pub fn pubtype(&self) -> &str {
- &self.pubtype
+ pub fn custom_field_value(&self) -> &str {
+ &self.custom_field.1
}
pub fn citekey(&self) -> &str {
@@ -281,7 +300,10 @@ impl BibiSetup {
short_author: String::new(),
title: Self::get_title(k, bibliography),
year: Self::get_year(k, bibliography),
- pubtype: Self::get_pubtype(k, bibliography),
+ custom_field: (
+ cfg.general.custom_column.clone(),
+ Self::get_custom_field(k, bibliography, &cfg.general.custom_column),
+ ),
keywords: Self::get_keywords(k, bibliography),
citekey: k.to_owned(),
abstract_text: Self::get_abstract(k, bibliography),
@@ -385,8 +407,69 @@ impl BibiSetup {
}
}
- pub fn get_pubtype(citekey: &str, biblio: &Bibliography) -> String {
- biblio.get(citekey).unwrap().entry_type.to_string()
+ pub fn get_custom_field(
+ citekey: &str,
+ biblio: &Bibliography,
+ custom_field: &CustomField,
+ ) -> String {
+ match custom_field {
+ CustomField::Journaltitle => {
+ if let Ok(val) = biblio
+ .get(citekey)
+ .expect(&format!("Citekey {} not found in bibliography", citekey))
+ .journal_title()
+ {
+ val.format_verbatim()
+ } else {
+ "empty".to_string()
+ }
+ }
+ CustomField::Organization => {
+ if let Ok(val) = biblio.get(citekey).expect("").organization() {
+ let values: Vec<String> = val
+ .iter()
+ .map(|i| i.get(0).unwrap().v.get().to_string())
+ .collect();
+ values.join("; ")
+ } else {
+ "empty".to_string()
+ }
+ }
+ CustomField::Institution => {
+ if let Ok(val) = biblio.get(citekey).unwrap().institution() {
+ let values = val
+ .into_iter()
+ .map(|i| i.v.get().to_owned())
+ .collect::<Vec<_>>();
+ values.join("; ")
+ } else {
+ "empty".to_string()
+ }
+ }
+ CustomField::Series => {
+ if let Ok(val) = biblio.get(citekey).expect("").series() {
+ let values = val
+ .into_iter()
+ .map(|i| i.v.get().to_owned())
+ .collect::<Vec<_>>();
+ values.join("; ")
+ } else {
+ "empty".to_string()
+ }
+ }
+ CustomField::Publisher => {
+ if let Ok(val) = biblio.get(citekey).expect("").publisher() {
+ let values: Vec<String> = val
+ .iter()
+ .map(|i| i.get(0).unwrap().v.get().to_string())
+ .collect();
+ values.join("; ")
+ } else {
+ "empty".to_string()
+ }
+ }
+ CustomField::Pubtype => biblio.get(citekey).expect("").entry_type.to_string(),
+ }
}
pub fn get_keywords(citekey: &str, biblio: &Bibliography) -> String {
diff --git a/src/bibiman/entries.rs b/src/bibiman/entries.rs
index 8f678bc..db6d6bf 100644
--- a/src/bibiman/entries.rs
+++ b/src/bibiman/entries.rs
@@ -106,9 +106,11 @@ impl EntryTable {
EntryTableColumn::Year => self
.entry_table_items
.sort_by(|a, b| b.year.to_lowercase().cmp(&a.year.to_lowercase())),
- EntryTableColumn::Pubtype => self
- .entry_table_items
- .sort_by(|a, b| b.pubtype.to_lowercase().cmp(&a.pubtype.to_lowercase())),
+ EntryTableColumn::Pubtype => self.entry_table_items.sort_by(|a, b| {
+ b.custom_field_value()
+ .to_lowercase()
+ .cmp(&a.custom_field_value().to_lowercase())
+ }),
}
} else if !self.entry_table_reversed_sort {
match self.entry_table_selected_column {
@@ -121,9 +123,11 @@ impl EntryTable {
EntryTableColumn::Year => self
.entry_table_items
.sort_by(|a, b| a.year.to_lowercase().cmp(&b.year.to_lowercase())),
- EntryTableColumn::Pubtype => self
- .entry_table_items
- .sort_by(|a, b| a.pubtype.to_lowercase().cmp(&b.pubtype.to_lowercase())),
+ EntryTableColumn::Pubtype => self.entry_table_items.sort_by(|a, b| {
+ a.custom_field_value()
+ .to_lowercase()
+ .cmp(&b.custom_field_value().to_lowercase())
+ }),
}
}
}
@@ -132,7 +136,10 @@ impl EntryTable {
#[cfg(test)]
mod tests {
use crate::{
- bibiman::{bibisetup::BibiRow, BibiData},
+ bibiman::{
+ bibisetup::{BibiRow, CustomField},
+ BibiData,
+ },
cliargs::CLIArgs,
config::BibiConfig,
};
@@ -157,7 +164,7 @@ mod tests {
short_author: String::new(),
title: "A title".to_string(),
year: "2000".to_string(),
- pubtype: "article".to_string(),
+ custom_field: (CustomField::Pubtype, "article".to_string()),
keywords: "key1, key2".to_string(),
citekey: "miller_2000".to_string(),
abstract_text: "An abstract".to_string(),
@@ -177,7 +184,7 @@ mod tests {
short_author: String::new(),
title: "A title".to_string(),
year: "2000".to_string(),
- pubtype: "article".to_string(),
+ custom_field: (CustomField::Pubtype, "article".to_string()),
keywords: "key1, key2".to_string(),
citekey: "miller_2000".to_string(),
abstract_text: "An abstract".to_string(),
@@ -197,7 +204,7 @@ mod tests {
authors: "Miller et al.",
title: "A title",
year: "2000",
- pubtype: "article",
+ custom_field_value: "article",
symbols: &[None, None, None]
}
);
@@ -207,7 +214,7 @@ mod tests {
authors: "Miller et al. (ed.)",
title: "A title",
year: "2000",
- pubtype: "article",
+ custom_field_value: "article",
symbols: &[None, None, None]
}
)
diff --git a/src/bibiman/search.rs b/src/bibiman/search.rs
index f6679a4..e0c5f17 100644
--- a/src/bibiman/search.rs
+++ b/src/bibiman/search.rs
@@ -37,7 +37,7 @@ impl BibiSearch {
&inner_vec.authors,
&inner_vec.title,
&inner_vec.year,
- &inner_vec.pubtype,
+ &inner_vec.custom_field_value(),
&inner_vec.keywords,
&inner_vec.citekey
)
@@ -119,6 +119,8 @@ pub fn search_pattern_in_file<'a>(pattern: &str, file: &'a PathBuf) -> Option<&'
mod tests {
use std::ffi::OsString;
+ use crate::bibiman::bibisetup::CustomField;
+
use super::*;
#[test]
@@ -129,7 +131,7 @@ mod tests {
short_author: "".to_string(),
title: "Title".to_string(),
year: "1999".to_string(),
- pubtype: "article".to_string(),
+ custom_field: (CustomField::Pubtype, "article".to_string()),
keywords: "hello, bye".to_string(),
citekey: "author_1999".to_string(),
abstract_text: "An abstract with multiple sentences. Here is the second".to_string(),
diff --git a/src/config.rs b/src/config.rs
index 4e46fdd..e3798e4 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -30,7 +30,7 @@ use figment::{
use ratatui::style::Color;
use serde::{Deserialize, Serialize};
-use crate::cliargs::CLIArgs;
+use crate::{bibiman::bibisetup::CustomField, cliargs::CLIArgs};
const DEFAULT_CONFIG: &str = r##"
# [general]
@@ -67,6 +67,11 @@ const DEFAULT_CONFIG: &str = r##"
# file_symbol = "F"
# link_symbol = "L"
+## Select a custom column beside standard "author", "title" and "year"
+## Possible values are "journaltitle", "organization", "instituion", "publisher"
+## and "pubtype" (which is the default)
+# custom_column = "pubtype"
+
# [colors]
## Default values for dark-themed terminal
## Possible values are:
@@ -113,6 +118,7 @@ pub struct General {
pub note_symbol: String,
pub file_symbol: String,
pub link_symbol: String,
+ pub custom_column: CustomField,
}
/// Substruct [colors] in config.toml
@@ -152,6 +158,7 @@ impl Default for BibiConfig {
note_symbol: String::from("N"),
file_symbol: String::from("F"),
link_symbol: String::from("L"),
+ custom_column: CustomField::Pubtype,
},
colors: Self::dark_colors(),
}
@@ -173,6 +180,7 @@ impl BibiConfig {
note_symbol: String::from("N"),
file_symbol: String::from("F"),
link_symbol: String::from("L"),
+ custom_column: CustomField::Pubtype,
},
colors: if args.light_theme {
Self::light_colors()
diff --git a/src/tui/ui.rs b/src/tui/ui.rs
index 69ca058..2180838 100644
--- a/src/tui/ui.rs
+++ b/src/tui/ui.rs
@@ -18,6 +18,7 @@
use std::path::PathBuf;
use super::popup::{PopupArea, PopupItem};
+use crate::bibiman::bibisetup::CustomField;
use crate::bibiman::entries::EntryTableColumn;
use crate::bibiman::{CurrentArea, FormerArea};
use crate::cliargs::CLIArgs;
@@ -623,6 +624,15 @@ pub fn render_entrytable(app: &mut App, cfg: &BibiConfig, frame: &mut Frame, rec
.fg(cfg.colors.main_text_color)
.bg(cfg.colors.bar_bg_color);
+ let custom_col_title: &str = match cfg.general.custom_column {
+ CustomField::Journaltitle => "Journaltitle",
+ CustomField::Organization => "Organization",
+ CustomField::Institution => "Institution",
+ CustomField::Series => "Series",
+ CustomField::Publisher => "Publisher",
+ CustomField::Pubtype => "Pubtype",
+ };
+
let header = Row::new(vec![
Cell::from(Line::from("Res.")).bg(cfg.colors.bar_bg_color),
Cell::from(
@@ -705,7 +715,7 @@ pub fn render_entrytable(app: &mut App, cfg: &BibiConfig, frame: &mut Frame, rec
),
),
Cell::from(
- Line::from(vec![{ Span::raw("Pubtype") }, {
+ Line::from(vec![{ Span::raw(custom_col_title) }, {
if let Some(EntryTableColumn::Pubtype) =
app.bibiman.entry_table.entry_table_sorted_by_col
{
@@ -786,7 +796,7 @@ pub fn render_entrytable(app: &mut App, cfg: &BibiConfig, frame: &mut Frame, rec
Cell::from(Line::from(item.authors)),
Cell::from(Line::from(item.title)),
Cell::from(Line::from(item.year)),
- Cell::from(Line::from(item.pubtype)),
+ Cell::from(Line::from(item.custom_field_value)),
]);
// let row = item
diff --git a/tests/test-config.toml b/tests/test-config.toml
index 1d29043..0b93cf3 100644
--- a/tests/test-config.toml
+++ b/tests/test-config.toml
@@ -32,6 +32,11 @@ file_symbol = " "
link_symbol = "󰌹 "
note_symbol = "󰧮"
+## Select a custom column beside standard "author", "title" and "year"
+## Possible values are "journaltitle", "organization", "instituion", "publisher"
+## and "pubtype" (which is the default)
+custom_column = "publisher"
+
# [colors]
## Default values for dark-themed terminal
## Possible values are: