Skip to content

Commit 3ef7b4d

Browse files
author
Michael Fruth
authored
✨ Add option to adjust alignment of text of multi-line values. (#290)
* Add option to adjust alignment of text of multi-line values. A new option align_multiline_values is added to enable whether the text of multiline values should be aligned on top of each other.
1 parent 006f463 commit 3ef7b4d

3 files changed

Lines changed: 137 additions & 1 deletion

File tree

bibtexparser/bwriter.py

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,9 @@ def __init__(self, write_common_strings=False):
5858
#: Align values. Determines the maximal number of characters used in any fieldname and aligns all values
5959
# according to that by filling up with single spaces. Default: False
6060
self.align_values = False
61+
#: Align multi-line values. Formats a multi-line value such that the text is aligned exactly
62+
# on top of each other. Default: False
63+
self.align_multiline_values = False
6164
#: Characters(s) for separating BibTeX entries. Default: new line.
6265
self.entry_separator = '\n'
6366
#: Tuple of fields for ordering BibTeX entries. Set to `None` to disable sorting. Default: BibTeX key `('ID', )`.
@@ -127,11 +130,31 @@ def _entry_to_bibtex(self, entry):
127130
# Write field = value lines
128131
for field in [i for i in display_order if i not in ['ENTRYTYPE', 'ID']]:
129132
try:
133+
value = _str_or_expr_to_bibtex(entry[field])
134+
135+
if self.align_multiline_values:
136+
# Calculate indent of multi-line values. Text from a multiline string
137+
# should be aligned, i.e., be exactly on top of each other.
138+
# E.g.: title = {Hello
139+
# World}
140+
# Calculate the indent of "World":
141+
# Left of field (whitespaces before e.g. 'title')
142+
value_indent = len(self.indent)
143+
# Field itself (e.g. len('title'))
144+
if self._max_field_width > 0:
145+
value_indent += self._max_field_width
146+
else:
147+
value_indent += len(field)
148+
# Right of field ' = ' (<- 3 chars) + '{' (<- 1 char)
149+
value_indent += 3 + 1
150+
151+
value = value.replace('\n', '\n' + value_indent * ' ')
152+
130153
bibtex += field_fmt.format(
131154
indent=self.indent,
132155
field=field,
133156
field_max_w=self._max_field_width,
134-
value=_str_or_expr_to_bibtex(entry[field]))
157+
value=value)
135158
except TypeError:
136159
raise TypeError(u"The field %s in entry %s must be a string"
137160
% (field, entry['ID']))
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
@ARTICLE{Cesar2013,
2+
author = {Jean César},
3+
title = {A mutline line title is very amazing. It should be
4+
long enough to test multilines... with two lines or should we
5+
even test three lines... What an amazing title.},
6+
year = {2013},
7+
journal = {Nice Journal},
8+
abstract = {This is an abstract. This line should be long enough to test
9+
multilines... and with a french érudit word},
10+
comments = {A comment},
11+
keyword = {keyword1, keyword2,
12+
multiline-keyword1, multiline-keyword2},
13+
}

bibtexparser/tests/test_bibtexwriter.py

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,106 @@ def test_display_order(self):
169169
title = {Optical fiber fusion slicing},
170170
author = {Yablon, A.D.}
171171
}
172+
"""
173+
self.assertEqual(result, expected)
174+
175+
def test_align_multiline_values(self):
176+
with open('bibtexparser/tests/data/article_multilines.bib') as bibtex_file:
177+
bib_database = bibtexparser.load(bibtex_file)
178+
writer = BibTexWriter()
179+
writer.align_multiline_values = True
180+
writer.display_order = ["author", "title", "year", "journal", "abstract", "comments", "keyword"]
181+
result = bibtexparser.dumps(bib_database, writer)
182+
expected = \
183+
"""@article{Cesar2013,
184+
author = {Jean César},
185+
title = {A mutline line title is very amazing. It should be
186+
long enough to test multilines... with two lines or should we
187+
even test three lines... What an amazing title.},
188+
year = {2013},
189+
journal = {Nice Journal},
190+
abstract = {This is an abstract. This line should be long enough to test
191+
multilines... and with a french érudit word},
192+
comments = {A comment},
193+
keyword = {keyword1, keyword2,
194+
multiline-keyword1, multiline-keyword2}
195+
}
196+
"""
197+
self.assertEqual(result, expected)
198+
199+
def test_align_multiline_values_with_align(self):
200+
with open('bibtexparser/tests/data/article_multilines.bib') as bibtex_file:
201+
bib_database = bibtexparser.load(bibtex_file)
202+
writer = BibTexWriter()
203+
writer.align_multiline_values = True
204+
writer.align_values = True
205+
writer.display_order = ["author", "title", "year", "journal", "abstract", "comments", "keyword"]
206+
result = bibtexparser.dumps(bib_database, writer)
207+
expected = \
208+
"""@article{Cesar2013,
209+
author = {Jean César},
210+
title = {A mutline line title is very amazing. It should be
211+
long enough to test multilines... with two lines or should we
212+
even test three lines... What an amazing title.},
213+
year = {2013},
214+
journal = {Nice Journal},
215+
abstract = {This is an abstract. This line should be long enough to test
216+
multilines... and with a french érudit word},
217+
comments = {A comment},
218+
keyword = {keyword1, keyword2,
219+
multiline-keyword1, multiline-keyword2}
220+
}
221+
"""
222+
self.assertEqual(result, expected)
223+
224+
def test_align_multiline_values_with_indent(self):
225+
with open('bibtexparser/tests/data/article_multilines.bib') as bibtex_file:
226+
bib_database = bibtexparser.load(bibtex_file)
227+
writer = BibTexWriter()
228+
writer.align_multiline_values = True
229+
writer.indent = ' ' * 3
230+
writer.display_order = ["author", "title", "year", "journal", "abstract", "comments", "keyword"]
231+
result = bibtexparser.dumps(bib_database, writer)
232+
expected = \
233+
"""@article{Cesar2013,
234+
author = {Jean César},
235+
title = {A mutline line title is very amazing. It should be
236+
long enough to test multilines... with two lines or should we
237+
even test three lines... What an amazing title.},
238+
year = {2013},
239+
journal = {Nice Journal},
240+
abstract = {This is an abstract. This line should be long enough to test
241+
multilines... and with a french érudit word},
242+
comments = {A comment},
243+
keyword = {keyword1, keyword2,
244+
multiline-keyword1, multiline-keyword2}
245+
}
246+
"""
247+
self.assertEqual(result, expected)
248+
249+
def test_align_multiline_values_with_align_with_indent(self):
250+
with open('bibtexparser/tests/data/article_multilines.bib') as bibtex_file:
251+
bib_database = bibtexparser.load(bibtex_file)
252+
writer = BibTexWriter()
253+
writer.align_multiline_values = True
254+
writer.indent = ' ' * 3
255+
writer.align_values = True
256+
writer.display_order = ["author", "title", "year", "journal", "abstract", "comments", "keyword"]
257+
result = bibtexparser.dumps(bib_database, writer)
258+
expected = \
259+
"""@article{Cesar2013,
260+
author = {Jean César},
261+
title = {A mutline line title is very amazing. It should be
262+
long enough to test multilines... with two lines or should we
263+
even test three lines... What an amazing title.},
264+
year = {2013},
265+
journal = {Nice Journal},
266+
abstract = {This is an abstract. This line should be long enough to test
267+
multilines... and with a french érudit word},
268+
comments = {A comment},
269+
keyword = {keyword1, keyword2,
270+
multiline-keyword1, multiline-keyword2}
271+
}
172272
"""
173273
self.assertEqual(result, expected)
174274

0 commit comments

Comments
 (0)