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

View File

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

View File

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

View File

@ -1386,8 +1386,7 @@ void Paragraph::Private::validate(LaTeXFeatures & features) const
// switching machinery of odocstream. Therefore the // switching machinery of odocstream. Therefore the
// output is wrong if this paragraph contains content // output is wrong if this paragraph contains content
// that needs to switch encoding. // that needs to switch encoding.
odocstringstream ods; otexstringstream os;
otexstream os(ods);
if (is_command) { if (is_command) {
os << '\\' << from_ascii(layout_->latexname()); os << '\\' << from_ascii(layout_->latexname());
// we have to provide all the optional arguments here, even though // 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()); 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 // this will output "{" at the beginning, but not at the end
owner_->latex(bp, f, os, features.runparams(), 0, -1, true); owner_->latex(bp, f, os, features.runparams(), 0, -1, true);
if (ods.str().length() > length) { if (os.length() > length) {
if (is_command) { if (is_command) {
ods << '}'; // FIXME: why does it has to be os.os() (equivalent to ods
// before)?
os.os() << '}';
if (!layout_->postcommandargs().empty()) { if (!layout_->postcommandargs().empty()) {
OutputParams rp = features.runparams(); OutputParams rp = features.runparams();
rp.local_font = &owner_->getFirstFontSettings(bp); rp.local_font = &owner_->getFirstFontSettings(bp);
latexArgInsets(*owner_, os, rp, layout_->postcommandargs(), "post:"); 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 { 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() void TexString::validate()
{ {
size_t lines = 1 + count(str.begin(), str.end(), '\n'); 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. /// 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. /// They can be output to otexrowstreams and otexstreams.
/// A valid TexString has as many newlines in str as in texrow. Be careful not /// 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 /// 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 //for gcc 4.6, nothing to do: it's enough to disable implicit copy during
// dev with more recent versions of gcc. // dev with more recent versions of gcc.
#endif #endif
/// /// Empty TexString
TexString() = default; 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(); void validate();
}; };

View File

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