feat: Add capitalization choices for title and author

This commit is contained in:
Marty Oehme 2025-06-11 14:41:45 +02:00
parent dc4c30e2e1
commit 7e7c720682
Signed by: Marty
GPG key ID: 4E535BC19C61886E
2 changed files with 52 additions and 9 deletions

View file

@ -67,6 +67,8 @@ default-formatter = python
full-year = False full-year = False
title-words = 4 title-words = 4
title-chars = -1 title-chars = -1
title-case = capitalize
author-case = capitalize
``` ```
### Full year ### Full year
@ -122,6 +124,30 @@ title-chars = -1
This will ensure that a maximum of 4 words will be placed in the ref, but they do not have a maximum character length, This will ensure that a maximum of 4 words will be placed in the ref, but they do not have a maximum character length,
so will always be fully written out (the default behavior if no title length options are provided). so will always be fully written out (the default behavior if no title length options are provided).
### Capitalization
Both the author and the title can receive different capitalization.
The options for capitalization are `capitalize`, `lower` and `upper`.
They can be set independently for author (`author-case`) and title (`title-case`).
```cfg
[plugins.bbt]
title-case = capitalize
author-case = lower
```
The example above would produce a reference like `name2008TitleShort`, whereas:
```cfg
[plugins.bbt]
title-case = upper
author-case = upper
```
produces `NAME2008TITLESHORT`.
If either of the settings are set to any other string they are simply passed through to the reference as they are.
### Fallback formatter ### Fallback formatter
For anything that is not a reference, use this formatter. For anything that is not a reference, use this formatter.

View file

@ -15,6 +15,8 @@ DEFAULT_OPTIONS = {
"title-words": 3, "title-words": 3,
"title-chars": -1, "title-chars": -1,
"full-year": True, "full-year": True,
"author-case": "capitalize", # or "lower" or "upper"
"title-case": "capitalize", # or "lower" or "upper"
} }
} }
papis.config.register_default_settings(DEFAULT_OPTIONS) papis.config.register_default_settings(DEFAULT_OPTIONS)
@ -60,20 +62,24 @@ class BBTFormatter(papis.format.Formatter):
return fallback_formatted return fallback_formatted
def format_with_bbt(self, doc: papis.document.DocumentLike) -> str: def format_with_bbt(self, doc: papis.document.DocumentLike) -> str:
author_unfmt = ( author = self.get_author(
doc["author_list"][0]["family"] doc["author_list"][0]["family"]
if "author_list" in doc if "author_list" in doc
else str(doc["author"]).split(maxsplit=1)[0] # pyright: ignore[reportAny] else str(doc["author"]).split(maxsplit=1)[0] # pyright: ignore[reportAny]
if "author" in doc if "author" in doc
else "UNKNOWN" else "UNKNOWN"
) )
author = re.sub("[^a-z]+", "", author_unfmt.lower())
year = self.get_year( year = self.get_year(
doc["year"] if "year" in doc else doc["date"] if "date" in doc else "" doc["year"] if "year" in doc else doc["date"] if "date" in doc else ""
) )
title = self.get_title(doc["title"] if "title" in doc else "NO TITLE") title = self.get_title(doc["title"] if "title" in doc else "NO TITLE")
return f"{author}{year}{title}" return f"{author}{year}{title}"
def get_author(self, author: str) -> str:
author = re.sub("[^a-zA-Z]+", "", author)
author_case = papis.config.getstring("author-case", OPTIONS_SECTION)
return self._case_str(author, author_case)
def get_year(self, date: str) -> str: def get_year(self, date: str) -> str:
"""Returns year string according to set year display options. """Returns year string according to set year display options.
@ -92,20 +98,31 @@ class BBTFormatter(papis.format.Formatter):
Removes skip-words, cleans any punctuation and spaces and trims Removes skip-words, cleans any punctuation and spaces and trims
the title length to that set in plugin length options.""" the title length to that set in plugin length options."""
title = re.sub("[^0-9a-z ]+", "", title.lower()) title = re.sub("[^0-9a-zA-Z ]+", "", title)
title_words = list( title_case = papis.config.getstring("title-case", OPTIONS_SECTION)
map( title_words = [
str.capitalize, self._case_str(word, title_case)
filter(lambda word: word and word not in SKIP_WORDS, title.split()), for word in title.split()
) if word not in SKIP_WORDS
) ]
wlen = papis.config.getint("title-words", OPTIONS_SECTION) wlen = papis.config.getint("title-words", OPTIONS_SECTION)
clen = papis.config.getint("title-chars", OPTIONS_SECTION) clen = papis.config.getint("title-chars", OPTIONS_SECTION)
wlen = None if wlen == -1 else wlen wlen = None if wlen == -1 else wlen
clen = None if clen == -1 else clen clen = None if clen == -1 else clen
title = "".join(title_words[:wlen])[:clen] title = "".join(title_words[:wlen])[:clen]
return title return title
def _case_str(self, s: str, case: str) -> str:
if case == "lower":
return s.lower()
elif case == "capitalize":
return s.capitalize()
elif case == "upper":
return s.upper()
return s
SKIP_WORDS = set( SKIP_WORDS = set(
[ [