TexRow for InPreamble

This enables error reporting for the preamble, provided the preamble is written
using the new InPreamble layouts.

In the future, I find it preferable to deprecate the usual preamble in favour of
InPreamble layouts rather than implementing error reporting for the usual
preamble. This requires some improvements to code editing in the buffer view
first (line breaking behaviour, syntax highlighting).
This commit is contained in:
Guillaume Munch 2016-09-25 12:38:53 +02:00
parent 1b4f5970a4
commit 1f6c451ee3
8 changed files with 125 additions and 87 deletions

View File

@ -1902,8 +1902,6 @@ void Buffer::writeLaTeXSource(otexstream & os,
} // output_preamble
os.texrow().start(paragraphs().begin()->id(), 0);
LYXERR(Debug::INFO, "preamble finished, now the body.");
// the real stuff
@ -2088,7 +2086,7 @@ void Buffer::writeLyXHTMLSource(odocstream & os,
if (!styles.empty())
os << "\n<!-- Text Class Preamble -->\n" << styles << '\n';
styles = features.getPreambleSnippets();
styles = features.getPreambleSnippets().str;
if (!styles.empty())
os << "\n<!-- Preamble Snippets -->\n" << styles << '\n';

View File

@ -1994,34 +1994,37 @@ bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features,
os << "\\usepackage[dot]{bibtopic}\n";
// Will be surrounded by \makeatletter and \makeatother when not empty
docstring atlyxpreamble;
otexstringstream atlyxpreamble;
// Some macros LyX will need
docstring tmppreamble(features.getMacros());
if (!tmppreamble.empty())
atlyxpreamble += "\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
"LyX specific LaTeX commands.\n"
+ tmppreamble + '\n';
{
TexString tmppreamble = features.getMacros();
if (!tmppreamble.str.empty())
atlyxpreamble << "\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
"LyX specific LaTeX commands.\n"
<< move(tmppreamble)
<< '\n';
}
// the text class specific preamble
tmppreamble = features.getTClassPreamble();
if (!tmppreamble.empty())
atlyxpreamble += "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
"Textclass specific LaTeX commands.\n"
+ tmppreamble + '\n';
{
docstring tmppreamble = features.getTClassPreamble();
if (!tmppreamble.empty())
atlyxpreamble << "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
"Textclass specific LaTeX commands.\n"
<< tmppreamble
<< '\n';
}
// suppress date if selected
// use \@ifundefined because we cannot be sure that every document class
// has a \date command
if (suppress_date)
atlyxpreamble += "\\@ifundefined{date}{}{\\date{}}\n";
atlyxpreamble << "\\@ifundefined{date}{}{\\date{}}\n";
/* the user-defined preamble */
if (!containsOnly(preamble, " \n\t")) {
// FIXME UNICODE
atlyxpreamble += "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
"User specified LaTeX commands.\n";
atlyxpreamble << "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
"User specified LaTeX commands.\n";
// Check if the user preamble contains uncodable glyphs
odocstringstream user_preamble;
@ -2064,7 +2067,7 @@ bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features,
"preamble code accordingly."),
uncodable_glyphs));
}
atlyxpreamble += user_preamble.str() + '\n';
atlyxpreamble << user_preamble.str() << '\n';
}
// footmisc must be loaded after setspace
@ -2072,7 +2075,7 @@ bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features,
// preamble. For that reason we also pass the options via
// \PassOptionsToPackage in getPreamble() and not here.
if (features.mustProvide("footmisc"))
atlyxpreamble += "\\usepackage{footmisc}\n";
atlyxpreamble << "\\usepackage{footmisc}\n";
// subfig loads internally the LaTeX package "caption". As
// caption is a very popular package, users will load it in
@ -2084,11 +2087,10 @@ bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features,
// koma's own caption commands are used instead of caption. We
// use \PassOptionsToPackage here because the user could have
// already loaded subfig in the preamble.
if (features.mustProvide("subfig")) {
atlyxpreamble += "\\@ifundefined{showcaptionsetup}{}{%\n"
" \\PassOptionsToPackage{caption=false}{subfig}}\n"
"\\usepackage{subfig}\n";
}
if (features.mustProvide("subfig"))
atlyxpreamble << "\\@ifundefined{showcaptionsetup}{}{%\n"
" \\PassOptionsToPackage{caption=false}{subfig}}\n"
"\\usepackage{subfig}\n";
// Itemize bullet settings need to be last in case the user
// defines their own bullets that use a package included
@ -2123,13 +2125,12 @@ bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features,
}
if (!bullets_def.empty())
atlyxpreamble += bullets_def + "}\n\n";
atlyxpreamble << bullets_def << "}\n\n";
if (!atlyxpreamble.empty()) {
if (!atlyxpreamble.empty())
os << "\n\\makeatletter\n"
<< atlyxpreamble
<< atlyxpreamble.release()
<< "\\makeatother\n\n";
}
// We try to load babel late, in case it interferes with other packages.
// Jurabib, hyperref, varioref, bicaption and listings (bug 8995) have to be

View File

@ -30,6 +30,8 @@
#include "Lexer.h"
#include "LyXRC.h"
#include "TextClass.h"
#include "TexRow.h"
#include "texstream.h"
#include "insets/InsetLayout.h"
@ -586,26 +588,62 @@ bool LaTeXFeatures::isAvailable(string const & name)
}
void LaTeXFeatures::addPreambleSnippet(docstring const & preamble,
bool allowdupes)
namespace {
void addSnippet(std::list<TexString> & list, TexString ts, bool allow_dupes)
{
SnippetList::const_iterator begin = preamble_snippets_.begin();
SnippetList::const_iterator end = preamble_snippets_.end();
if (allowdupes || find(begin, end, preamble) == end)
preamble_snippets_.push_back(preamble);
if (allow_dupes ||
// test the absense of duplicates, i.e. elements with same str
none_of(list.begin(), list.end(), [&](TexString const & ts2){
return ts.str == ts2.str;
})
)
list.push_back(move(ts));
}
TexString getSnippets(std::list<TexString> const & list)
{
otexstringstream snip;
for (TexString const & ts : list)
snip << TexString(ts) << '\n';
return snip.release();
}
} //anon namespace
void LaTeXFeatures::addPreambleSnippet(TexString ts, bool allow_dupes)
{
addSnippet(preamble_snippets_, move(ts), allow_dupes);
}
void LaTeXFeatures::addPreambleSnippet(docstring const & str, bool allow_dupes)
{
addSnippet(preamble_snippets_, TexString(str), allow_dupes);
}
void LaTeXFeatures::addCSSSnippet(std::string const & snippet)
{
docstring const u_snippet = from_ascii(snippet);
SnippetList::const_iterator begin = css_snippets_.begin();
SnippetList::const_iterator end = css_snippets_.end();
if (find(begin, end, u_snippet) == end)
css_snippets_.push_back(u_snippet);
addSnippet(css_snippets_, TexString(from_ascii(snippet)), false);
}
TexString LaTeXFeatures::getPreambleSnippets() const
{
return getSnippets(preamble_snippets_);
}
docstring LaTeXFeatures::getCSSSnippets() const
{
return getSnippets(css_snippets_).str;
}
void LaTeXFeatures::useFloat(string const & name, bool subfloat)
{
if (!usedFloats_[name])
@ -1151,31 +1189,9 @@ string const LaTeXFeatures::getPackages() const
}
docstring LaTeXFeatures::getPreambleSnippets() const
TexString LaTeXFeatures::getMacros() const
{
odocstringstream snip;
SnippetList::const_iterator pit = preamble_snippets_.begin();
SnippetList::const_iterator pend = preamble_snippets_.end();
for (; pit != pend; ++pit)
snip << *pit << '\n';
return snip.str();
}
docstring LaTeXFeatures::getCSSSnippets() const
{
odocstringstream snip;
SnippetList::const_iterator pit = css_snippets_.begin();
SnippetList::const_iterator pend = css_snippets_.end();
for (; pit != pend; ++pit)
snip << *pit << '\n';
return snip.str();
}
docstring const LaTeXFeatures::getMacros() const
{
odocstringstream macros;
otexstringstream macros;
if (!preamble_snippets_.empty()) {
macros << '\n';
@ -1319,7 +1335,7 @@ docstring const LaTeXFeatures::getMacros() const
macros << changetracking_dvipost_def;
if (mustProvide("ct-xcolor-ulem")) {
streamsize const prec = macros.precision(2);
streamsize const prec = macros.os().precision(2);
RGBColor cadd = rgbFromHexName(lcolor.getX11Name(Color_addedtext));
macros << "\\providecolor{lyxadded}{rgb}{"
@ -1329,7 +1345,7 @@ docstring const LaTeXFeatures::getMacros() const
macros << "\\providecolor{lyxdeleted}{rgb}{"
<< cdel.r / 255.0 << ',' << cdel.g / 255.0 << ',' << cdel.b / 255.0 << "}\n";
macros.precision(prec);
macros.os().precision(prec);
if (isRequired("hyperref"))
macros << changetracking_xcolor_ulem_hyperref_def;
@ -1343,7 +1359,7 @@ docstring const LaTeXFeatures::getMacros() const
if (mustProvide("rtloutputdblcol"))
macros << rtloutputdblcol_def;
return macros.str();
return macros.release();
}
@ -1755,7 +1771,7 @@ void LaTeXFeatures::showStruct() const
{
lyxerr << "LyX needs the following commands when LaTeXing:"
<< "\n***** Packages:" << getPackages()
<< "\n***** Macros:" << to_utf8(getMacros())
<< "\n***** Macros:" << to_utf8(getMacros().str)
<< "\n***** Textclass stuff:" << to_utf8(getTClassPreamble())
<< "\n***** done." << endl;
}
@ -1779,7 +1795,7 @@ BufferParams const & LaTeXFeatures::bufferParams() const
}
void LaTeXFeatures::getFloatDefinitions(odocstream & os) const
void LaTeXFeatures::getFloatDefinitions(otexstream & os) const
{
FloatList const & floats = params_.documentClass().floats();

View File

@ -27,6 +27,7 @@ class Buffer;
class BufferParams;
class InsetLayout;
class Language;
class TexString;
/** The packages and commands that a buffer needs. This class
* contains a list<string>. Each of the LaTeX packages that a buffer needs
@ -60,7 +61,7 @@ public:
/// The packages needed by the document
std::string const getPackages() const;
/// The macros definitions needed by the document
docstring const getMacros() const;
TexString getMacros() const;
/// Extra preamble code before babel is called
docstring const getBabelPresettings() const;
/// Extra preamble code after babel is called
@ -84,13 +85,15 @@ public:
/// Include a file for use with the SGML entities
void includeFile(docstring const & key, std::string const & name);
/// The float definitions.
void getFloatDefinitions(odocstream & os) const;
void getFloatDefinitions(otexstream & os) const;
/// Print requirements to lyxerr
void showStruct() const;
///
/// Add preamble snippet with TexRow information
void addPreambleSnippet(TexString snippet, bool allowdupes = false);
/// Add preamble snippet without TexRow information
void addPreambleSnippet(docstring const & snippet, bool allowdupes = false);
///
docstring getPreambleSnippets() const;
TexString getPreambleSnippets() const;
///
void addCSSSnippet(std::string const &);
///
@ -174,7 +177,7 @@ private:
///
Features features_;
/// Static preamble bits, from external templates, or anywhere else
typedef std::list<docstring> SnippetList;
typedef std::list<TexString> SnippetList;
///
SnippetList preamble_snippets_;
///

View File

@ -1386,8 +1386,7 @@ void Paragraph::Private::validate(LaTeXFeatures & features) const
// switching machinery of odocstream. Therefore the
// output is wrong if this paragraph contains content
// that needs to switch encoding.
odocstringstream ods;
otexstream os(ods);
otexstringstream os;
if (is_command) {
os << '\\' << from_ascii(layout_->latexname());
// we have to provide all the optional arguments here, even though
@ -1400,19 +1399,21 @@ void Paragraph::Private::validate(LaTeXFeatures & features) const
}
os << from_ascii(layout_->latexparam());
}
docstring::size_type const length = ods.str().length();
size_t const length = os.length();
// this will output "{" at the beginning, but not at the end
owner_->latex(bp, f, os, features.runparams(), 0, -1, true);
if (ods.str().length() > length) {
if (os.length() > length) {
if (is_command) {
ods << '}';
// FIXME: why does it has to be os.os() (equivalent to ods
// before)?
os.os() << '}';
if (!layout_->postcommandargs().empty()) {
OutputParams rp = features.runparams();
rp.local_font = &owner_->getFirstFontSettings(bp);
latexArgInsets(*owner_, os, rp, layout_->postcommandargs(), "post:");
}
}
features.addPreambleSnippet(ods.str(), true);
features.addPreambleSnippet(os.release(), true);
}
}

View File

@ -34,6 +34,20 @@ using namespace std;
namespace lyx {
TexString::TexString(docstring s)
: str(move(s)), texrow(TexRow())
{
texrow.setRows(1 + count(str.begin(), str.end(), '\n'));
}
TexString::TexString(docstring s, TexRow t)
: str(move(s)), texrow(move(t))
{
validate();
}
void TexString::validate()
{
size_t lines = 1 + count(str.begin(), str.end(), '\n');

View File

@ -199,7 +199,7 @@ private:
/// TexString : dumb struct to pass around docstrings with TexRow information.
/// They are best created using oTexStringstream.
/// They are best created using otexstringstream.
/// They can be output to otexrowstreams and otexstreams.
/// A valid TexString has as many newlines in str as in texrow. Be careful not
/// to introduce a mismatch between the line and the row counts, as this will
@ -221,9 +221,13 @@ struct TexString {
//for gcc 4.6, nothing to do: it's enough to disable implicit copy during
// dev with more recent versions of gcc.
#endif
///
/// Empty TexString
TexString() = default;
/// ensure that the string and the TexRow have as many newlines.
/// Texstring containing str and TexRow with enough lines which are empty
explicit TexString(docstring str);
/// Texstring containing str and texrow. Must be valid.
TexString(docstring str, TexRow texrow);
/// Ensure that the string and the TexRow have as many newlines.
void validate();
};

View File

@ -78,8 +78,9 @@ size_t otexstringstream::length()
TexString otexstringstream::release()
{
TexString ts{ods_.str(), TexRow()};
swap(ts.texrow, texrow());
TexString ts(ods_.str(), move(texrow()));
// reset this
texrow() = TexRow();
ods_.clear();
ods_.str(docstring());
return ts;