Support for multiple bibliographies setting "per child"

This adds support for the chapterbib package, but also adds ways to
produce this sort of multibib with biblatex and bibtopic (which are
both incompatible with chapterbib).

File format change.
This commit is contained in:
Juergen Spitzmueller 2017-02-04 19:23:46 +01:00
parent 401961d087
commit bedebfc45a
17 changed files with 227 additions and 12 deletions

View File

@ -7,9 +7,16 @@ changes happened in particular if possible. A good example would be
-----------------------
2017-02-04 Jürgen Spitzmüller <spitz@lyx.org>
* Format incremented to 534: Support for chapterbib
- New buffer param value \multibib child
LaTeX support either via biblatex's \newrefsection at the beginning
of child documents, chapterbib or bibtopic's btUnit environment
embracing the child content (if subdivided bibliography is requested).
2017-02-04 Jürgen Spitzmüller <spitz@lyx.org>
* Format incremented to 533: Support for multiple bibliographies
- New buffer param \multibib {none|part|chapter|section|subsetion}
- New buffer param \multibib {none|part|chapter|section|subsection}
LaTeX support either via biblatex option "refsection" or bibtopic's
btUnit environment.
- New btprint value "bibbysection" of CommandInset bibtex:

View File

@ -294,6 +294,7 @@
\TestPackage{CJKutf8}
\TestPackage{calc}
\TestPackage{cancel}
\TestPackage{chapterbib}
\TestPackage{chemgreek}
\TestPackage{chicago}
\TestPackage{color} % this one should be there if graphics.sty is there.

View File

@ -1,5 +1,5 @@
#LyX 2.3 created this file. For more info see http://www.lyx.org/
\lyxformat 528
\lyxformat 534
\begin_document
\begin_header
\save_transient_properties true
@ -5609,6 +5609,35 @@ bibtopic
created bibliographies into sections.
\end_layout
\begin_layout Subsection
chapterbib
\end_layout
\begin_layout Description
Found:
\begin_inset Info
type "package"
arg "chapterbib"
\end_inset
\end_layout
\begin_layout Description
CTAN:
\family typewriter
macros/latex/contrib/chapterbib/
\end_layout
\begin_layout Description
Notes: The package
\family sans
chapterbib
\family default
is used to generate multiple bibliographies per child with Bib\SpecialChar TeX
.
\end_layout
\begin_layout Subsection
chicago
\end_layout
@ -6049,6 +6078,7 @@ lettrine
LatexCommand href
name "initials"
target "http://en.wikipedia.org/wiki/Initial"
literal "false"
\end_inset

View File

@ -1735,6 +1735,111 @@ def revert_multibib(document):
"end{btUnit}"
"\\end_layout", "", "\\end_inset", "", "",
"\\end_layout", ""]
def revert_chapterbib(document):
" Revert chapterbib support "
# 1. Get cite engine
engine = "basic"
i = find_token(document.header, "\\cite_engine", 0)
if i == -1:
document.warning("Malformed document! Missing \\cite_engine")
else:
engine = get_value(document.header, "\\cite_engine", i)
# 2. Do we use biblatex?
biblatex = False
if engine in ["biblatex", "biblatex-natbib"]:
biblatex = True
# 3. Store multibib document header value
multibib = ""
i = find_token(document.header, "\\multibib", 0)
if i != -1:
multibib = get_value(document.header, "\\multibib", i)
if not multibib or multibib != "child":
# nothing to do
return
# 4. remove multibib header
del document.header[i]
# 5. Biblatex
if biblatex:
# find include insets
i = 0
while (True):
i = find_token(document.body, "\\begin_inset CommandInset include", i)
if i == -1:
break
j = find_end_of_inset(document.body, i)
if j == -1:
document.warning("Can't find end of bibtex inset at line %d!!" %(i))
i += 1
continue
parent = get_containing_layout(document.body, i)
parbeg = parent[1]
# Insert ERT \\newrefsection before inset
beg = ["\\begin_layout Standard",
"\\begin_inset ERT", "status open", "",
"\\begin_layout Plain Layout", "", "",
"\\backslash",
"newrefsection"
"\\end_layout", "", "\\end_inset", "", "",
"\\end_layout", ""]
document.body[parbeg-1:parbeg-1] = beg
j += len(beg)
i = j + 1
return
# 6. Bibtex/Bibtopic
i = find_token(document.header, "\\use_bibtopic", 0)
if i == -1:
# this should not happen
document.warning("Malformed LyX document! No \\use_bibtopic header found!")
return
if get_value(document.header, "\\use_bibtopic", i) == "true":
# find include insets
i = 0
while (True):
i = find_token(document.body, "\\begin_inset CommandInset include", i)
if i == -1:
break
j = find_end_of_inset(document.body, i)
if j == -1:
document.warning("Can't find end of bibtex inset at line %d!!" %(i))
i += 1
continue
parent = get_containing_layout(document.body, i)
parbeg = parent[1]
parend = parent[2]
# Insert wrap inset into \\begin{btUnit}...\\end{btUnit}
beg = ["\\begin_layout Standard",
"\\begin_inset ERT", "status open", "",
"\\begin_layout Plain Layout", "", "",
"\\backslash",
"begin{btUnit}"
"\\end_layout", "", "\\end_inset", "", "",
"\\end_layout", ""]
end = ["\\begin_layout Standard",
"\\begin_inset ERT", "status open", "",
"\\begin_layout Plain Layout", "", "",
"\\backslash",
"end{btUnit}"
"\\end_layout", "", "\\end_inset", "", "",
"\\end_layout", ""]
document.body[parend+1:parend+1] = end
document.body[parbeg-1:parbeg-1] = beg
j += len(beg) + len(end)
i = j + 1
return
# 7. Chapterbib proper
add_to_preamble(document, ["\\usepackage{chapterbib}"])
##
@ -1768,9 +1873,11 @@ convert = [
[531, []],
[532, [convert_literalparam]],
[533, []],
[534, []]
]
revert = [
[533, [revert_chapterbib]],
[532, [revert_multibib]],
[531, [revert_literalparam]],
[530, [revert_qualicites]],

View File

@ -523,6 +523,14 @@ map<string, string> const & BufferParams::auto_packages()
}
bool BufferParams::useBibtopic() const
{
if (useBiblatex())
return false;
return (use_bibtopic || (!multibib.empty() && multibib != "child"));
}
AuthorList & BufferParams::authors()
{
return pimpl_->authorlist;
@ -2218,7 +2226,7 @@ bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features,
delim = ",";
}
}
if (!multibib.empty()) {
if (!multibib.empty() && multibib != "child") {
opts += delim + "refsection=" + multibib;
delim = ",";
}

View File

@ -379,7 +379,7 @@ public:
/// All packages that can be switched on or off
static std::map<std::string, std::string> const & auto_packages();
/// Do we use the bibtopic package?
bool useBibtopic() const { return (use_bibtopic || !multibib.empty()) && !useBiblatex(); }
bool useBibtopic() const;
/// Split bibliography?
bool splitbib() const { return use_bibtopic; }
/// Set split bibliography

View File

@ -402,6 +402,9 @@ bool Converters::convert(Buffer const * buffer,
runparams.index_command = (buffer->params().index_command == "default") ?
string() : buffer->params().index_command;
runparams.document_language = buffer->params().language->babel();
runparams.only_childbibs = !buffer->params().useBiblatex()
&& !buffer->params().useBibtopic()
&& buffer->params().multibib == "child";
}
// Some converters (e.g. lilypond) can only output files to the

View File

@ -237,7 +237,7 @@ int LaTeX::run(TeXErrors & terr)
/// in which case we will not need to run bibtex again.
vector<AuxInfo> bibtex_info_old;
if (!run_bibtex)
bibtex_info_old = scanAuxFiles(aux_file);
bibtex_info_old = scanAuxFiles(aux_file, runparams.only_childbibs);
++count;
LYXERR(Debug::LATEX, "Run #" << count);
@ -253,7 +253,7 @@ int LaTeX::run(TeXErrors & terr)
scanres = scanLogFile(terr);
}
vector<AuxInfo> const bibtex_info = scanAuxFiles(aux_file);
vector<AuxInfo> const bibtex_info = scanAuxFiles(aux_file, runparams.only_childbibs);
if (!run_bibtex && bibtex_info_old != bibtex_info)
run_bibtex = true;
@ -491,12 +491,26 @@ bool LaTeX::runMakeIndexNomencl(FileName const & file,
vector<AuxInfo> const
LaTeX::scanAuxFiles(FileName const & file)
LaTeX::scanAuxFiles(FileName const & file, bool const only_childbibs)
{
vector<AuxInfo> result;
// With chapterbib, we have to bibtex all children's aux files
// but _not_ the master's!
if (only_childbibs) {
for (string const &s: children) {
FileName fn =
makeAbsPath(s, file.onlyPath().realPath());
fn.changeExtension("aux");
if (fn.exists())
result.push_back(scanAuxFile(fn));
}
return result;
}
result.push_back(scanAuxFile(file));
// This is for bibtopic
string const basename = removeExtension(file.absFileName());
for (int i = 1; i < 1000; ++i) {
FileName const file2(basename
@ -647,6 +661,7 @@ int LaTeX::scanLogFile(TeXErrors & terr)
string child_name;
int pnest = 0;
stack <pair<string, int> > child;
children.clear();
string token;
while (getline(ifs, token)) {
@ -675,6 +690,7 @@ int LaTeX::scanLogFile(TeXErrors & terr)
if (regex_match(substr, sub, child_file)) {
string const name = sub.str(1);
child.push(make_pair(name, pnest));
children.push_back(name);
i += len;
}
} else if (token[i] == ')') {

View File

@ -197,7 +197,8 @@ private:
std::string const &, std::string const &);
///
std::vector<AuxInfo> const scanAuxFiles(support::FileName const &);
std::vector<AuxInfo> const scanAuxFiles(support::FileName const &,
bool const only_childbibs = false);
///
AuxInfo const scanAuxFile(support::FileName const &);
@ -242,6 +243,9 @@ private:
/// Do we use biber?
bool biber;
///
std::vector <std::string> children;
};

View File

@ -963,6 +963,7 @@ char const * bibliofeatures[] = {
"authordate1-4",
"babelbib",
"bibgerm",
"chapterbib",
"chicago",
"chscite",
"harvard",

View File

@ -24,7 +24,8 @@ OutputParams::OutputParams(Encoding const * enc)
encoding(enc), free_spacing(false), use_babel(false), use_polyglossia(false),
use_indices(false), use_japanese(false), linelen(0), depth(0),
exportdata(new ExportData), inDisplayMath(false), wasDisplayMath(false),
inComment(false), openbtUnit(false), inTableCell(NO), inFloat(NONFLOAT),
inComment(false), openbtUnit(false), only_childbibs(false),
inTableCell(NO), inFloat(NONFLOAT),
inIndexEntry(false), inIPA(false), inDeletedInset(0),
changeOfDeletedInset(Change::UNCHANGED),
par_begin(0), par_end(0), lastid(-1), lastpos(0), isLastPar(false),

View File

@ -209,6 +209,11 @@ public:
*/
bool openbtUnit;
/** Process only the children's aux files with BibTeX.
* This is necessary with chapterbib.
*/
bool only_childbibs;
/** Whether we are in a table cell.
* For newline, it matters whether its content is aligned or not.
*/

View File

@ -3169,6 +3169,7 @@ void GuiDocument::paramsToDialog()
biblioModule->bibunitsCO->addItem(qt_("per section"), toqstr("section"));
if (documentClass().hasLaTeXLayout("subsection"))
biblioModule->bibunitsCO->addItem(qt_("per subsection"), toqstr("subsection"));
biblioModule->bibunitsCO->addItem(qt_("per child document"), toqstr("child"));
int const mbpos = biblioModule->bibunitsCO->findData(toqstr(bp_.multibib));
if (mbpos != -1)

View File

@ -222,6 +222,12 @@ docstring InsetBibtex::toolTip(BufferView const & /*bv*/, int /*x*/, int /*y*/)
tip += ", ";
tip += _("included in TOC");
}
if (!buffer().parent()
&& buffer().params().multibib == "child") {
tip += "<br />";
tip += _("Note: This bibliography is not output, since bibliographies in the master file "
"are not allowed with the setting 'Multiple bibliographies per child document'");
}
} else {
tip += _("Lists:") + " ";
if (btprint == "bibbysection")
@ -262,6 +268,11 @@ void InsetBibtex::latex(otexstream & os, OutputParams const & runparams) const
// or
// \bibbysection[biblatexopts] - if btprint is "bibbysection"
// chapterbib does not allow bibliographies in the master
if (!usingBiblatex() && !runparams.is_child
&& buffer().params().multibib == "child")
return;
string style = to_utf8(getParam("options")); // maybe empty! and with bibtotoc
string bibtotoc;
if (prefixIs(style, "bibtotoc")) {
@ -876,8 +887,11 @@ bool InsetBibtex::delDatabase(docstring const & db)
void InsetBibtex::validate(LaTeXFeatures & features) const
{
if (features.buffer().masterParams().useBibtopic())
BufferParams const & mparams = features.buffer().masterParams();
if (mparams.useBibtopic())
features.require("bibtopic");
else if (!mparams.useBiblatex() && mparams.multibib == "child")
features.require("chapterbib");
// FIXME XHTML
// It'd be better to be able to get this from an InsetLayout, but at present
// InsetLayouts do not seem really to work for things that aren't InsetTexts.

View File

@ -1267,9 +1267,19 @@ void latexParagraphs(Buffer const & buf,
{ os << "% LaTeX Output Error\n"; return; } );
BufferParams const & bparams = buf.params();
BufferParams const & mparams = buf.masterParams();
bool const maintext = text.isMainText();
bool const is_child = buf.masterBuffer() != &buf;
bool const multibib_child = maintext && is_child
&& mparams.multibib == "child";
if (multibib_child && mparams.useBiblatex())
os << "\\newrefsection";
else if (multibib_child && mparams.useBibtopic()) {
os << "\\begin{btUnit}\n";
runparams.openbtUnit = true;
}
// Open a CJK environment at the beginning of the main buffer
// if the document's language is a CJK language
@ -1443,6 +1453,11 @@ void latexParagraphs(Buffer const & buf,
if (state->cjk_inherited_ == 0)
state->open_encoding_ = CJK;
}
if (multibib_child && mparams.useBibtopic()) {
os << "\\end{btUnit}\n";
runparams.openbtUnit = false;
}
}

View File

@ -154,6 +154,8 @@ Format LaTeX feature LyX feature
\bibbysection[<opts>] \begin_inset CommandInset bibtex
biblatexopts "<opts>"
btprint "bibbysection"
534 Chapterbib support
\usepackage{chapterbib} \multibib child

View File

@ -32,8 +32,8 @@ extern char const * const lyx_version_info;
// Do not remove the comment below, so we get merge conflict in
// independent branches. Instead add your own.
#define LYX_FORMAT_LYX 533 // spitz: multibib
#define LYX_FORMAT_TEX2LYX 533
#define LYX_FORMAT_LYX 534 // spitz: chapterbib support
#define LYX_FORMAT_TEX2LYX 534
#if LYX_FORMAT_TEX2LYX != LYX_FORMAT_LYX
#ifndef _MSC_VER