Skip to content

Commit

Permalink
Pretty print individual BibEntry and allow custom key order
Browse files Browse the repository at this point in the history
  • Loading branch information
its-luca committed Jul 18, 2022
1 parent c84f200 commit 3ff4e16
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 26 deletions.
89 changes: 63 additions & 26 deletions bibtex.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,22 @@ import (
"time"
)

//prettyPrintDefaultKeyOrder controls the order in which BibEntry keys are printed
//when using the PrettyString() instead of the PrettyStringCustom(keyOrder []string) variants.
//Index 0 becomes first field and so on.
var prettyPrintDefaultKeyOrder = []string{"title", "author", "url"}

//keyOrderToPriorityMap is a helper function converting the user facing key order slice
//into the map format that is internally used by the sort function
func keyOrderToPriorityMap(keyOrder []string) map[string]int {
priority := make(map[string]int)
offset := len(keyOrder)
for i, v := range keyOrder {
priority[v] = i - offset
}
return priority
}

// BibString is a segment of a bib string.
type BibString interface {
RawString() string // Internal representation.
Expand Down Expand Up @@ -115,6 +131,46 @@ func (entry *BibEntry) AddField(name string, value BibString) {
entry.Fields[strings.TrimSpace(name)] = value
}

//prettyStringAppend appends the pretty print string for BibEntry to buf using priority to order the keys
func (entry *BibEntry) prettyStringAppend(buf *bytes.Buffer, priority map[string]int) {
fmt.Fprintf(buf, "@%s{%s,\n", entry.Type, entry.CiteName)

// Determine key order.
keys := []string{}
for key := range entry.Fields {
keys = append(keys, key)
}

sort.Slice(keys, func(i, j int) bool {
pi, pj := priority[keys[i]], priority[keys[j]]
return pi < pj || (pi == pj && keys[i] < keys[j])
})

// Write fields.
tw := tabwriter.NewWriter(buf, 1, 4, 1, ' ', 0)
for _, key := range keys {
value := entry.Fields[key].String()
format := stringformat(value)
fmt.Fprintf(tw, " %s\t=\t"+format+",\n", key, value)
}
tw.Flush()
buf.WriteString("}\n")

}

//PrettyStringCustomOrder pretty prints BibEntry with fields ordered as they appear
//in keyOrder
func (entry *BibEntry) PrettyStringCustomOrder(keyOrder []string) string {
priority := keyOrderToPriorityMap(keyOrder)
var buf bytes.Buffer
entry.prettyStringAppend(&buf, priority)
return buf.String()
}

func (entry *BibEntry) PrettyString() string {
return entry.PrettyStringCustomOrder(prettyPrintDefaultKeyOrder)
}

// String returns a BibTex entry as a simplified BibTex string.
func (entry *BibEntry) String() string {
var bibtex bytes.Buffer
Expand Down Expand Up @@ -247,41 +303,22 @@ func (bib *BibTex) RawString() string {
return bibtex.String()
}

// PrettyString pretty prints a BibTex.
func (bib *BibTex) PrettyString() string {
//PrettyStringCustomOrder pretty prints a BibTex with each BibEntry's keys ordered as they appear in keyOrder
func (bib *BibTex) PrettyStringCustomOrder(keyOrder []string) string {
var buf bytes.Buffer
for i, entry := range bib.Entries {
if i != 0 {
fmt.Fprint(&buf, "\n")
}
fmt.Fprintf(&buf, "@%s{%s,\n", entry.Type, entry.CiteName)

// Determine key order.
keys := []string{}
for key := range entry.Fields {
keys = append(keys, key)
}

priority := map[string]int{"title": -3, "author": -2, "url": -1}
sort.Slice(keys, func(i, j int) bool {
pi, pj := priority[keys[i]], priority[keys[j]]
return pi < pj || (pi == pj && keys[i] < keys[j])
})

// Write fields.
tw := tabwriter.NewWriter(&buf, 1, 4, 1, ' ', 0)
for _, key := range keys {
value := entry.Fields[key].String()
format := stringformat(value)
fmt.Fprintf(tw, " %s\t=\t"+format+",\n", key, value)
}
tw.Flush()
entry.prettyStringAppend(&buf, keyOrderToPriorityMap(keyOrder))

// Close.
buf.WriteString("}\n")
}
return buf.String()
}

// PrettyString pretty prints a BibTex.
func (bib *BibTex) PrettyString() string {
return bib.PrettyStringCustomOrder(prettyPrintDefaultKeyOrder)
}

// stringformat determines the correct formatting verb for the given BibTeX field value.
Expand Down
24 changes: 24 additions & 0 deletions bibtex_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -205,3 +205,27 @@ func BenchmarkStringPerformance(b *testing.B) {
_ = bib.String()
}
}

func TestBibEntry_PrettyStringCustomOrder(t *testing.T) {
wantPrettyString := `@inproceedings{bibtexKey,
author = "A a and B b and C c",
editor = "D d and E e",
title = "Some title",
booktitle = "Some booktitle",
}
`

entry := NewBibEntry("inproceedings", "bibtexKey")
entry.AddField("author", NewBibConst("A a and B b and C c"))
entry.AddField("editor", NewBibConst("D d and E e"))
entry.AddField("title", NewBibConst("Some title"))
entry.AddField("booktitle", NewBibConst("Some booktitle"))

keyOrder := []string{"author", "editor", "title", "booktitle"}
gotPrettyString := entry.PrettyStringCustomOrder(keyOrder)

if wantPrettyString != gotPrettyString {
t.Errorf("Format error\nWant: %s\nGot:%s\n", wantPrettyString, gotPrettyString)
}

}

0 comments on commit 3ff4e16

Please sign in to comment.