BibTeXKit is a modern, Swift-native framework for parsing, displaying, and manipulating BibTeX bibliographic data. Built with SwiftUI, it provides beautiful syntax highlighting and a highly customizable viewing experience across all Apple platforms.
- Beautiful Syntax Highlighting — 7 built-in themes including Monokai, Solarized, and Xcode styles
- Responsive Design — Adapts perfectly from Apple Watch to Mac
- Highly Customizable — Toggle copy buttons, line numbers, metadata, and more
- Complete BibTeX Support — All 17 standard entry types plus custom types
- LaTeX Conversion — Automatic LaTeX to Unicode conversion (ü → ü)
- Quality API — SwiftUI view modifiers that feel native
- 100% Test Coverage — Comprehensive test suite
- Thread Safe — Full
Sendableconformance for modern concurrency
Add BibTeXKit to your project via Xcode:
- File → Add Package Dependencies...
- Enter:
https://github.com/ezefranca/BibTeXKit.git - Select "Up to Next Major Version" with
1.0.1
Or add to your Package.swift:
dependencies: [
.package(url: "https://github.com/ezefranca/BibTeXKit.git", from: "1.0.1")
]import SwiftUI
import BibTeXKit
struct ContentView: View {
let bibtex = """
@article{einstein1905,
author = {Albert Einstein},
title = {On the Electrodynamics of Moving Bodies},
journal = {Annalen der Physik},
year = {1905}
}
"""
var body: some View {
BibTeXView(bibtex: bibtex)
}
}import BibTeXKit
let bibtex = "@article{key, author = {John Doe}, title = {Example}}"
do {
let entries = try BibTeXParser.parse(bibtex)
for entry in entries {
print("Type: \(entry.type)") // article
print("Key: \(entry.key)") // key
print("Author: \(entry.author)") // John Doe
}
} catch {
print("Parse error: \(error)")
}BibTeXKit uses familiar SwiftUI view modifier patterns:
BibTeXView(bibtex: myBibTeX)
.lineNumbers(true)
.bibTeXTheme(MonokaiTheme())
.copyButtonHidden()
.showMetadata(true)
.formattingStyle(.aligned)
.cornerRadius(12)
.maxHeight(400)| Modifier | Description |
|---|---|
.bibTeXTheme(_:) |
Set syntax highlighting theme |
.lineNumbers(_:) |
Show/hide line numbers |
.copyButtonHidden(_:) |
Show/hide copy button |
.copyButtonPosition(_:) |
Position: .topTrailing, .bottomLeading, etc. |
.copyButtonStyle(_:) |
Style: .iconOnly, .labeled, .compact |
.showMetadata(_:) |
Show entry type badge and field count |
.formattingStyle(_:) |
.standard, .compact, .minimal, .aligned |
.maxHeight(_:) |
Maximum height before scrolling |
.minHeight(_:) |
Minimum height |
.cornerRadius(_:) |
Container corner radius |
.bordered(_:) |
Show/hide border |
.textSelection(_:) |
Enable/disable text selection |
.contentPadding(_:) |
Content padding |
.preset(_:) |
Apply a configuration preset |
BibTeXView(bibtex: bibtex)
.bibTeXTheme(DefaultLightTheme()) // Default light theme
.bibTeXTheme(DefaultDarkTheme()) // Default dark theme
.bibTeXTheme(XcodeLightTheme()) // Xcode light
.bibTeXTheme(XcodeDarkTheme()) // Xcode dark
.bibTeXTheme(MonokaiTheme()) // Monokai (dark)
.bibTeXTheme(SolarizedLightTheme()) // Solarized light
.bibTeXTheme(SolarizedDarkTheme()) // Solarized dark// Minimal - just the content
BibTeXView(bibtex: bibtex)
.preset(.minimal)
// Compact - for tight spaces
BibTeXView(bibtex: bibtex)
.preset(.compact)
// Full - all features enabled
BibTeXView(bibtex: bibtex)
.preset(.full)
// Mobile - optimized for phones
BibTeXView(bibtex: bibtex)
.preset(.mobile)Create your own theme by conforming to BibTeXTheme:
struct MyCustomTheme: BibTeXTheme {
let name = "My Theme"
let font = Font.system(size: 14, design: .monospaced)
let backgroundColor = Color(hex: "#1e1e1e")
let borderColor = Color.gray.opacity(0.3)
func color(for token: BibTeXToken) -> Color {
switch token {
case .entryType: return Color(hex: "#ff6b6b")
case .citationKey: return Color(hex: "#4ecdc4")
case .fieldName: return Color(hex: "#45b7d1")
case .string: return Color(hex: "#96ceb4")
case .comment: return Color(hex: "#6c757d")
default: return Color(hex: "#f8f9fa")
}
}
}
// Use it
BibTeXView(bibtex: bibtex)
.bibTeXTheme(MyCustomTheme())var options = BibTeXParser.Options()
options.convertLaTeXToUnicode = true // Convert \"{u} to ü
options.normalizeFieldNames = true // Lowercase field names
options.stripDelimiters = true // Remove extra whitespace
options.preserveRawBibTeX = true // Keep original string
let entries = try BibTeXParser.parse(bibtex, options: options)let entry = entries.first!
// Convenience properties
entry.author // Author field
entry.title // Title field
entry.year // Year field
entry.doi // DOI field
entry.journal // Journal field
entry.publisher // Publisher field
// Subscript access (case-insensitive)
entry["author"] // Same as entry.author
entry["TITLE"] // Case insensitive
// Author parsing
entry.authors // ["First Author", "Second Author"]
// Validation
let validation = entry.validate()
validation.isValid // true if all required fields present
validation.missingRequired // ["journal", "year"]
validation.missingOptional // ["volume", "pages"]// Different formatting styles
entry.formatted(style: .standard) // Standard indentation
entry.formatted(style: .compact) // Minimal whitespace
entry.formatted(style: .minimal) // Single line per field
entry.formatted(style: .aligned) // Aligned equals signs
// Citation formatting
entry.citation(style: .apa) // APA format
entry.citation(style: .mla) // MLA format
entry.citation(style: .chicago) // Chicago format
entry.citation(style: .ieee) // IEEE format
entry.citation(style: .harvard) // Harvard format// Create modified copies
let updated = entry
.with(field: "note", value: "Important")
.with(key: "newkey")
.with(type: .book)
.with(fields: ["abstract": "...", "keywords": "..."])BibTeXKit includes comprehensive LaTeX to Unicode conversion:
import BibTeXKit
// Accents
LaTeXConverter.toUnicode("M\\\"uller") // "Müller"
LaTeXConverter.toUnicode("Caf\\'e") // "Café"
LaTeXConverter.toUnicode("\\~nino") // "ñino"
// Special characters
LaTeXConverter.toUnicode("\\ss") // "ß"
LaTeXConverter.toUnicode("\\ae") // "æ"
// Greek letters
LaTeXConverter.toUnicode("\\alpha") // "α"
LaTeXConverter.toUnicode("\\Omega") // "Ω"
// Math symbols
LaTeXConverter.toUnicode("\\infty") // "∞"
LaTeXConverter.toUnicode("\\pm") // "±"
// Reverse conversion
LaTeXConverter.toLaTeX("Müller") // "M\\\"uller"| Platform | Minimum Version |
|---|---|
| iOS | 17.0+ |
| macOS | 14.0+ |
| tvOS | 17.0+ |
| watchOS | 9.0+ |
| visionOS | 1.0+ |
BibTeXKit/
├── Models/
│ ├── BibTeXEntry.swift # Entry model
│ └── BibTeXEntryType.swift # Entry types enum
├── Parsing/
│ ├── BibTeXParser.swift # Main parser
│ ├── BibTeXTokenizer.swift # Tokenizer
│ ├── BibTeXToken.swift # Token types
│ └── LaTeXConverter.swift # LaTeX ↔ Unicode
├── Highlighting/
│ ├── BibTeXTheme.swift # Theme protocol + themes
│ └── BibTeXHighlighter.swift # AttributedString generator
└── Views/
├── BibTeXView.swift # Main view component
├── BibTeXText.swift # Simple inline text
└── BibTeXViewConfiguration.swift # Configuration
BibTeXKit has comprehensive test coverage:
swift testRun with coverage:
swift test --enable-code-coverageBibTeXKit is available under the MIT license. See the LICENSE file for details.
Contributions are welcome! Please read our Contributing Guidelines before submitting a PR.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Write tests for your changes
- Ensure all tests pass
- Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
AI contributions are welcome! When submitting a PR, please add the model you used and the prompt to obtain that code. Like this
For AI agents looking to integrate with BibTeXKit, see the Agent Guide for comprehensive API documentation and usage patterns.
