Skip to content

Commit 89358f9

Browse files
committed
Fix issues #50, #53, and #58
Issue #50: Add validation for invalid page separators - Add detection for en-dash, em-dash, minus sign, and other invalid dash characters in page numbers - Provide suggested corrections by replacing invalid dashes with standard hyphens - Return error message when invalid dash characters are detected Issue #53: Fix capitalization validation with surrounding punctuation - Add strip_leading_trailing_non_letters() helper function to extract leading/trailing non-alphabetic characters - Update format_title() to strip punctuation before checking caps.txt, then reapply after adding braces - Update format_journal_name() with same fix - Fixes incorrect brace placement like {(BHI}) → ({BHI}) Issue #58: Add MacOS TeXShop/TeX Live setup instructions - Add new section "MacOS Setup with TeXShop and TeX Live" to README - Document TeX Live's ~/Library/texmf/ approach for GUI applications - Explain why environment variables don't work with Mac GUI apps - Provide step-by-step instructions with symbolic link setup - Update table of contents with new subsections
1 parent ce48365 commit 89358f9

File tree

2 files changed

+99
-21
lines changed

2 files changed

+99
-21
lines changed

README.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ The main bibtex file ([cdl.bib](https://raw.githubusercontent.com/ContextLab/CDL
1616
- [`compare`](#compare)
1717
- [`commit`](#commit)
1818
- [Using the bibtex file as a common bibliography for all *local* LaTeX files](#using-the-bibtex-file-as-a-common-bibliography-for-all-local-latex-files)
19+
- [General Unix/Linux Setup (Command Line Compilation)](#general-unixlinux-setup-command-line-compilation)
20+
- [MacOS Setup with TeXShop and TeX Live](#macos-setup-with-texshop-and-tex-live)
1921
- [Using the bibtex file on Overleaf](#using-the-bibtex-file-on-overleaf)
2022
- [Acknowledgements](#acknowledgements)
2123

@@ -190,6 +192,8 @@ called, and a pull request must be submitted in order to integrate the changes
190192
into the main ContextLab fork.
191193

192194
# Using the bibtex file as a common bibliography for all *local* LaTeX files
195+
196+
## General Unix/Linux Setup (Command Line Compilation)
193197
1. Check out this repository to your home directory
194198
2. Add the following lines to your `~/.bash_profile` (or `~/.zshrc`, etc.):
195199
```
@@ -208,6 +212,28 @@ latex filename
208212
pdflatex filename
209213
```
210214

215+
## MacOS Setup with TeXShop and TeX Live
216+
217+
Mac GUI applications like TeXShop don't execute within your shell environment, which means the environment variable approach described above won't work when compiling through the TeXShop GUI. Instead, use TeX Live's built-in support for personal files:
218+
219+
1. Check out this repository (we'll assume you cloned it to your home directory: `~/CDL-bibliography`)
220+
2. Create the TeX Live personal texmf directory structure for bibliography files:
221+
```bash
222+
mkdir -p ~/Library/texmf/bibtex/bib
223+
```
224+
3. Create a symbolic link from your personal texmf directory to the CDL-bibliography repository. **Important**: You must use the absolute path (not relative paths or `~`):
225+
```bash
226+
ln -s /Users/YOUR_USERNAME/CDL-bibliography/cdl.bib ~/Library/texmf/bibtex/bib/cdl.bib
227+
```
228+
Replace `YOUR_USERNAME` with your actual macOS username, or use `$HOME` instead:
229+
```bash
230+
ln -s $HOME/CDL-bibliography/cdl.bib ~/Library/texmf/bibtex/bib/cdl.bib
231+
```
232+
4. In your .tex file, use the line `\bibliography{cdl}` to generate a bibliography using the citation keys defined in cdl.bib
233+
5. Compile your document using TeXShop's GUI or from the command line
234+
235+
**Note**: This approach also works for command-line compilation, so you don't need to set up the environment variables if you use this method.
236+
211237
# Using the bibtex file on Overleaf
212238
You can use [git submodules](https://blog.github.com/2016-02-01-working-with-submodules/) to maintain a reference to the cdl.bib file in this repository that you can easily keep in sync with latest version. This avoids the need to maintain a separate .bib file in each Overleaf project.
213239

bibcheck/helpers.py

Lines changed: 73 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -427,6 +427,21 @@ def roman2int(s):
427427

428428

429429
def valid_pages(p):
430+
# Check for invalid dash characters (en-dash, em-dash, minus sign, etc.)
431+
invalid_dashes = {
432+
'\u2013': 'en-dash (–)',
433+
'\u2014': 'em-dash (—)',
434+
'\u2212': 'minus sign (−)',
435+
'\u2010': 'hyphen (‐)',
436+
'\u2011': 'non-breaking hyphen (‑)',
437+
}
438+
439+
for dash_char, dash_name in invalid_dashes.items():
440+
if dash_char in p:
441+
# Return False with error message
442+
suggested_fix = p.replace(dash_char, '-')
443+
return False, [p, suggested_fix]
444+
430445
valid, kind, val = valid_page(p)
431446
if valid: #"single" page
432447
return True, [p, p]
@@ -483,21 +498,25 @@ def format_journal_name(n, key=journal_key, force_caps=force_caps):
483498
#words = ['-'.join([format_journal_name(x) for x in w.split('-')]) if len(w.split('-')) > 1 else w for w in words] #deal with hyphens
484499

485500
for i, w in enumerate(words):
486-
words[i] = w.capitalize()
487-
488-
#deal with hyphens
489-
if len(w.split('-')) > 1:
490-
words[i] = '-'.join(format_journal_name(c, key=key, force_caps=force_caps) for c in w.split('-'))
491-
492-
if (i > 0) and (w.lower() in uncaps):
493-
words[i] = words[i].lower()
494-
495-
correct_caps = [f for f in force_caps if f.lower() == remove_non_letters(w.lower())]
501+
# Strip leading/trailing non-letters before checking caps
502+
prefix, core, suffix = strip_leading_trailing_non_letters(w)
503+
correct_caps = [f for f in force_caps if f.lower() == remove_non_letters(core.lower())]
504+
496505
if len(correct_caps) >= 1:
497506
c = correct_caps[-1]
498507
if not (c[0] == '{' and c[-1] == '}'):
499-
c = insert_non_letters('{' + c + '}', remove_curlies(w, join=' '))
500-
words[i] = c
508+
c = insert_non_letters('{' + c + '}', remove_curlies(core, join=' '))
509+
# Add back prefix and suffix
510+
words[i] = prefix + c + suffix
511+
else:
512+
words[i] = w.capitalize()
513+
514+
#deal with hyphens
515+
if len(w.split('-')) > 1:
516+
words[i] = '-'.join(format_journal_name(c, key=key, force_caps=force_caps) for c in w.split('-'))
517+
518+
if (i > 0) and (w.lower() in uncaps):
519+
words[i] = words[i].lower()
501520
return ' '.join(words)
502521

503522
#rearrange author name (first middle last suffix)
@@ -624,7 +643,36 @@ def before_letters(s, c): #true if c occurs before the first letter in s
624643
def after_letters(s, c): #true if c occurs after the last letter in s
625644
return before_letters(s[::-1], c)
626645

627-
def insert_non_letters(x, y):
646+
def strip_leading_trailing_non_letters(s):
647+
"""Strip leading and trailing non-alphabetic characters from a string.
648+
Returns (prefix, core, suffix) where core contains only letters and internal punctuation."""
649+
if len(s) == 0:
650+
return '', '', ''
651+
652+
# Find first letter
653+
first_letter = -1
654+
for i, c in enumerate(s):
655+
if c.lower() in ascii_lowercase:
656+
first_letter = i
657+
break
658+
659+
if first_letter == -1: # No letters found
660+
return s, '', ''
661+
662+
# Find last letter
663+
last_letter = -1
664+
for i in range(len(s) - 1, -1, -1):
665+
if s[i].lower() in ascii_lowercase:
666+
last_letter = i
667+
break
668+
669+
prefix = s[:first_letter]
670+
core = s[first_letter:last_letter + 1]
671+
suffix = s[last_letter + 1:]
672+
673+
return prefix, core, suffix
674+
675+
def insert_non_letters(x, y):
628676
z = ''
629677
i = 0 #position in x
630678
j = 0 #position in y
@@ -641,15 +689,15 @@ def insert_non_letters(x, y):
641689
j += 1
642690
else: #x[i] and y[j] are both in ascii_lowercase but x[i] != x[j] -- throw an error
643691
raise Exception(f'"{y}" is not a compatable template for "{x}"')
644-
692+
645693
#insert trailing punctuation from y
646694
if (j < len(y)) and (remove_non_letters(y[j:]) == ''):
647695
z += y[j:]
648-
696+
649697
#insert trailing punctuation from x
650698
if (i < len(x)) and (remove_non_letters(x[i:]) == ''):
651699
z += x[i:]
652-
700+
653701
return z
654702

655703
def format_title(title):
@@ -689,15 +737,19 @@ def ends_in_punctuation(s):
689737

690738
#leave "a" and specified caps unchanged
691739
if w.lower() == 'a' or (before_letters(w, '{') and after_letters(w, '}')):
692-
reformatted_title.append(w)
740+
reformatted_title.append(w)
693741
#if w contains curly braces, just append it unchanged
694742
elif (w.count('{') > 0) or (w.count('}') > 0):
695-
reformatted_title.append(w)
743+
reformatted_title.append(w)
696744
else:
697-
caps_match = [f for f in force_caps if f.lower() == remove_non_letters(w.lower())]
745+
# Strip leading/trailing non-letters before checking caps
746+
prefix, core, suffix = strip_leading_trailing_non_letters(w)
747+
caps_match = [f for f in force_caps if f.lower() == remove_non_letters(core.lower())]
698748
if len(caps_match) > 0:
699-
w = insert_non_letters('{' + caps_match[-1] + '}', w)
700-
elif not ends_in_punctuation(prev_w):
749+
# Apply braces only to the core, then add back prefix and suffix
750+
core_with_braces = insert_non_letters('{' + caps_match[-1] + '}', remove_curlies(core, join=' '))
751+
w = prefix + core_with_braces + suffix
752+
elif not ends_in_punctuation(prev_w):
701753
w = w.lower()
702754
reformatted_title.append(w)
703755
prev_w = w

0 commit comments

Comments
 (0)