#include "Author.h"
#include "LayoutFile.h"
#include "BranchList.h"
+#include "Buffer.h"
#include "buffer_funcs.h"
#include "Bullet.h"
#include "Color.h"
#include "support/filetools.h"
#include "support/gettext.h"
#include "support/Messages.h"
+#include "support/mutex.h"
+#include "support/Package.h"
#include "support/Translator.h"
#include "support/lstrings.h"
};
-static char const * const string_footnotekinds[] = {
- "footnote", "margin", "fig", "tab", "alg", "wide-fig", "wide-tab", ""
-};
-
-
static char const * const tex_graphics[] = {
"default", "dvialw", "dvilaser", "dvipdf", "dvipdfm", "dvipdfmx",
"dvips", "dvipsone", "dvitops", "dviwin", "dviwindo", "dvi2ps", "emtex",
ParSepTranslator const & parseptranslator()
{
- static ParSepTranslator translator = init_parseptranslator();
+ static ParSepTranslator const translator =
+ init_parseptranslator();
return translator;
}
QuotesLangTranslator const & quoteslangtranslator()
{
- static QuotesLangTranslator translator = init_quoteslangtranslator();
+ static QuotesLangTranslator const translator =
+ init_quoteslangtranslator();
return translator;
}
PaperSizeTranslator const & papersizetranslator()
{
- static PaperSizeTranslator translator = initPaperSizeTranslator();
+ static PaperSizeTranslator const translator =
+ initPaperSizeTranslator();
return translator;
}
PaperOrientationTranslator const & paperorientationtranslator()
{
- static PaperOrientationTranslator translator = init_paperorientationtranslator();
+ static PaperOrientationTranslator const translator =
+ init_paperorientationtranslator();
return translator;
}
SidesTranslator const & sidestranslator()
{
- static SidesTranslator translator = init_sidestranslator();
+ static SidesTranslator const translator = init_sidestranslator();
return translator;
}
PackageTranslator const & packagetranslator()
{
- static PackageTranslator translator = init_packagetranslator();
+ static PackageTranslator const translator =
+ init_packagetranslator();
return translator;
}
{
CiteEngineTypeTranslator translator("authoryear", ENGINE_TYPE_AUTHORYEAR);
translator.addPair("numerical", ENGINE_TYPE_NUMERICAL);
+ translator.addPair("default", ENGINE_TYPE_DEFAULT);
return translator;
}
CiteEngineTypeTranslator const & citeenginetypetranslator()
{
- static CiteEngineTypeTranslator translator = init_citeenginetypetranslator();
+ static CiteEngineTypeTranslator const translator =
+ init_citeenginetypetranslator();
return translator;
}
SpaceTranslator const & spacetranslator()
{
- static SpaceTranslator translator = init_spacetranslator();
+ static SpaceTranslator const translator = init_spacetranslator();
return translator;
}
BufferParams::Impl *
BufferParams::MemoryTraits::clone(BufferParams::Impl const * ptr)
{
- LASSERT(ptr, /**/);
-
+ LBUFERR(ptr);
return new BufferParams::Impl(*ptr);
}
: pimpl_(new Impl)
{
setBaseClass(defaultBaseclass());
+ cite_engine_.push_back("basic");
+ cite_engine_type_ = ENGINE_TYPE_DEFAULT;
makeDocumentClass();
paragraph_separation = ParagraphIndentSeparation;
quotes_language = InsetQuotes::EnglishQuotes;
papersize = PAPER_DEFAULT;
orientation = ORIENTATION_PORTRAIT;
use_geometry = false;
- cite_engine_.push_back("basic");
- cite_engine_type_ = ENGINE_TYPE_NUMERICAL;
biblio_style = "plain";
use_bibtopic = false;
use_indices = false;
- trackChanges = false;
- outputChanges = false;
+ save_transient_properties = true;
+ track_changes = false;
+ output_changes = false;
use_default_options = true;
maintain_unincluded_children = false;
secnumdepth = 3;
tocdepth = 3;
language = default_language;
fontenc = "global";
- fonts_roman = "default";
- fonts_sans = "default";
- fonts_typewriter = "default";
- fonts_math = "auto";
+ fonts_roman[0] = "default";
+ fonts_roman[1] = "default";
+ fonts_sans[0] = "default";
+ fonts_sans[1] = "default";
+ fonts_typewriter[0] = "default";
+ fonts_typewriter[1] = "default";
+ fonts_math[0] = "auto";
+ fonts_math[1] = "auto";
fonts_default_family = "default";
useNonTeXFonts = false;
fonts_expert_sc = false;
fonts_old_figures = false;
- fonts_sans_scale = 100;
- fonts_typewriter_scale = 100;
+ fonts_sans_scale[0] = 100;
+ fonts_sans_scale[1] = 100;
+ fonts_typewriter_scale[0] = 100;
+ fonts_typewriter_scale[1] = 100;
inputenc = "auto";
lang_package = "default";
graphics_driver = "default";
html_math_output = MathML;
html_math_img_scale = 1.0;
html_css_as_file = false;
+ display_pixel_ratio = 1.0;
output_sync = false;
use_refstyle = true;
+
+ // map current author
+ author_map_[pimpl_->authorlist.get(0).bufferId()] = 0;
}
docstring BufferParams::B_(string const & l10n) const
{
- LASSERT(language, /**/);
+ LASSERT(language, return from_utf8(l10n));
return getMessages(language->code()).get(l10n);
}
}
-vector<string> const & BufferParams::auto_packages()
+map<string, string> const & BufferParams::auto_packages()
{
- static vector<string> packages;
+ static map<string, string> packages;
if (packages.empty()) {
+ // We could have a race condition here that two threads
+ // discover an empty map at the same time and want to fill
+ // it, but that is no problem, since the same contents is
+ // filled in twice then. Having the locker inside the
+ // packages.empty() condition has the advantage that we
+ // don't need the mutex overhead for simple reading.
+ static Mutex mutex;
+ Mutex::Locker locker(&mutex);
// adding a package here implies a file format change!
- packages.push_back("amsmath");
- packages.push_back("amssymb");
- packages.push_back("esint");
- packages.push_back("mathdots");
- packages.push_back("mathtools");
- packages.push_back("mhchem");
- packages.push_back("undertilde");
+ packages["amsmath"] =
+ N_("The LaTeX package amsmath is only used if AMS formula types or symbols from the AMS math toolbars are inserted into formulas");
+ packages["amssymb"] =
+ N_("The LaTeX package amssymb is only used if symbols from the AMS math toolbars are inserted into formulas");
+ packages["cancel"] =
+ N_("The LaTeX package cancel is only used if \\cancel commands are used in formulas");
+ packages["esint"] =
+ N_("The LaTeX package esint is only used if special integral symbols are inserted into formulas");
+ packages["mathdots"] =
+ N_("The LaTeX package mathdots is only used if the command \\iddots is inserted into formulas");
+ packages["mathtools"] =
+ N_("The LaTeX package mathtools is only used if some mathematical relations are inserted into formulas");
+ packages["mhchem"] =
+ N_("The LaTeX package mhchem is only used if either the command \\ce or \\cf is inserted into formulas");
+ packages["stackrel"] =
+ N_("The LaTeX package stackrel is only used if the command \\stackrel with subscript is inserted into formulas");
+ packages["stmaryrd"] =
+ N_("The LaTeX package stmaryrd is only used if symbols from the St Mary's Road symbol font for theoretical computer science are inserted into formulas");
+ packages["undertilde"] =
+ N_("The LaTeX package undertilde is only used if you use the math frame decoration 'utilde'");
}
return packages;
}
}
+void BufferParams::addAuthor(Author a)
+{
+ author_map_[a.bufferId()] = pimpl_->authorlist.record(a);
+}
+
+
BranchList & BufferParams::branchlist()
{
return pimpl_->branchlist;
Bullet & BufferParams::temp_bullet(lyx::size_type const index)
{
- LASSERT(index < 4, /**/);
+ LASSERT(index < 4, return pimpl_->temp_bullets[0]);
return pimpl_->temp_bullets[index];
}
Bullet const & BufferParams::temp_bullet(lyx::size_type const index) const
{
- LASSERT(index < 4, /**/);
+ LASSERT(index < 4, return pimpl_->temp_bullets[0]);
return pimpl_->temp_bullets[index];
}
Bullet & BufferParams::user_defined_bullet(lyx::size_type const index)
{
- LASSERT(index < 4, /**/);
+ LASSERT(index < 4, return pimpl_->temp_bullets[0]);
return pimpl_->user_defined_bullets[index];
}
Bullet const & BufferParams::user_defined_bullet(lyx::size_type const index) const
{
- LASSERT(index < 4, /**/);
+ LASSERT(index < 4, return pimpl_->temp_bullets[0]);
return pimpl_->user_defined_bullets[index];
}
string BufferParams::readToken(Lexer & lex, string const & token,
FileName const & filepath)
{
+ string result;
+
if (token == "\\textclass") {
lex.next();
string const classname = lex.getString();
// be available.
string tcp;
LayoutFileList & bcl = LayoutFileList::get();
- if (tcp.empty() && !filepath.empty())
- tcp = bcl.addLocalLayout(classname, filepath.absFileName());
- if (!tcp.empty())
- setBaseClass(tcp);
- else
- setBaseClass(classname);
+ if (!filepath.empty()) {
+ // If classname is an absolute path, the document is
+ // using a local layout file which could not be accessed
+ // by a relative path. In this case the path is correct
+ // even if the document was moved to a different
+ // location. However, we will have a problem if the
+ // document was generated on a different platform.
+ bool isabsolute = FileName::isAbsolute(classname);
+ string const classpath = onlyPath(classname);
+ string const path = isabsolute ? classpath
+ : FileName(addPath(filepath.absFileName(),
+ classpath)).realPath();
+ string const oldpath = isabsolute ? string()
+ : FileName(addPath(origin, classpath)).realPath();
+ tcp = bcl.addLocalLayout(onlyFileName(classname), path, oldpath);
+ }
+ // that returns non-empty if a "local" layout file is found.
+ if (!tcp.empty()) {
+ result = to_utf8(makeRelPath(from_utf8(onlyPath(tcp)),
+ from_utf8(filepath.absFileName())));
+ if (result.empty())
+ result = ".";
+ setBaseClass(onlyFileName(tcp));
+ } else
+ setBaseClass(onlyFileName(classname));
// We assume that a tex class exists for local or unknown
// layouts so this warning, will only be given for system layouts.
if (!baseClass()->isTeXClassAvailable()) {
"See section 3.1.2.2 (Class Availability) of the\n"
"User's Guide for more information."), desc, prereqs);
frontend::Alert::warning(_("Document class not available"),
- msg);
+ msg, true);
+ }
+ } else if (token == "\\save_transient_properties") {
+ lex >> save_transient_properties;
+ } else if (token == "\\origin") {
+ lex.eatLine();
+ origin = lex.getString();
+ string const sysdirprefix = "/systemlyxdir/";
+ if (prefixIs(origin, sysdirprefix)) {
+ origin.replace(0, sysdirprefix.length() - 1,
+ package().system_support().absFileName());
}
} else if (token == "\\begin_preamble") {
readPreamble(lex);
} else if (token == "\\begin_local_layout") {
- readLocalLayout(lex);
+ readLocalLayout(lex, false);
+ } else if (token == "\\begin_forced_local_layout") {
+ readLocalLayout(lex, true);
} else if (token == "\\begin_modules") {
readModules(lex);
} else if (token == "\\begin_removed_modules") {
} else if (token == "\\master") {
lex.eatLine();
master = lex.getString();
+ if (!filepath.empty() && FileName::isAbsolute(origin)) {
+ bool const isabs = FileName::isAbsolute(master);
+ FileName const abspath(isabs ? master : origin + master);
+ bool const moved = filepath != FileName(origin);
+ if (moved && abspath.exists()) {
+ docstring const path = isabs
+ ? from_utf8(master)
+ : from_utf8(abspath.realPath());
+ docstring const refpath =
+ from_utf8(filepath.absFileName());
+ master = to_utf8(makeRelPath(path, refpath));
+ }
+ }
} else if (token == "\\suppress_date") {
lex >> suppress_date;
} else if (token == "\\justification") {
lex.eatLine();
fontenc = lex.getString();
} else if (token == "\\font_roman") {
- lex.eatLine();
- fonts_roman = lex.getString();
+ lex >> fonts_roman[0];
+ lex >> fonts_roman[1];
} else if (token == "\\font_sans") {
- lex.eatLine();
- fonts_sans = lex.getString();
+ lex >> fonts_sans[0];
+ lex >> fonts_sans[1];
} else if (token == "\\font_typewriter") {
- lex.eatLine();
- fonts_typewriter = lex.getString();
+ lex >> fonts_typewriter[0];
+ lex >> fonts_typewriter[1];
} else if (token == "\\font_math") {
- lex.eatLine();
- fonts_math = lex.getString();
+ lex >> fonts_math[0];
+ lex >> fonts_math[1];
} else if (token == "\\font_default_family") {
lex >> fonts_default_family;
} else if (token == "\\use_non_tex_fonts") {
} else if (token == "\\font_osf") {
lex >> fonts_old_figures;
} else if (token == "\\font_sf_scale") {
- lex >> fonts_sans_scale;
+ lex >> fonts_sans_scale[0];
+ lex >> fonts_sans_scale[1];
} else if (token == "\\font_tt_scale") {
- lex >> fonts_typewriter_scale;
+ lex >> fonts_typewriter_scale[0];
+ lex >> fonts_typewriter_scale[1];
} else if (token == "\\font_cjk") {
lex >> fonts_cjk;
} else if (token == "\\paragraph_separation") {
} else if (token == "\\use_indices") {
lex >> use_indices;
} else if (token == "\\tracking_changes") {
- lex >> trackChanges;
+ lex >> track_changes;
} else if (token == "\\output_changes") {
- lex >> outputChanges;
+ lex >> output_changes;
} else if (token == "\\branch") {
lex.eatLine();
docstring branch = lex.getDocString();
istringstream ss(lex.getString());
Author a;
ss >> a;
- author_map[a.bufferId()] = pimpl_->authorlist.record(a);
+ addAuthor(a);
} else if (token == "\\paperorientation") {
string orient;
lex >> orient;
lex.eatLine();
string color = lex.getString();
notefontcolor = lyx::rgbFromHexName(color);
+ lcolor.setColor("notefontcolor", color);
} else if (token == "\\boxbgcolor") {
lex.eatLine();
string color = lex.getString();
boxbgcolor = lyx::rgbFromHexName(color);
+ lcolor.setColor("boxbgcolor", color);
} else if (token == "\\paperwidth") {
lex >> paperwidth;
} else if (token == "\\paperheight") {
return token;
}
- return string();
+ return result;
+}
+
+
+namespace {
+ // Quote argument if it contains spaces
+ string quoteIfNeeded(string const & str) {
+ if (contains(str, ' '))
+ return "\"" + str + "\"";
+ return str;
+ }
}
-void BufferParams::writeFile(ostream & os) const
+void BufferParams::writeFile(ostream & os, Buffer const * buf) const
{
// The top of the file is written by the buffer.
// Prints out the buffer info into the .lyx file given by file
+ os << "\\save_transient_properties "
+ << convert<string>(save_transient_properties) << '\n';
+
+ // the document directory (must end with a path separator)
+ // realPath() is used to resolve symlinks, while addPath(..., "")
+ // ensures a trailing path separator.
+ string filepath = addPath(buf->fileName().onlyPath().realPath(), "");
+ string const sysdir = addPath(package().system_support().realPath(), "");
+ string const relpath =
+ to_utf8(makeRelPath(from_utf8(filepath), from_utf8(sysdir)));
+ if (!prefixIs(relpath, "../") && !FileName::isAbsolute(relpath))
+ filepath = addPath("/systemlyxdir", relpath);
+ else if (!save_transient_properties || !lyxrc.save_origin)
+ filepath = "unavailable";
+ os << "\\origin " << quoteIfNeeded(filepath) << '\n';
+
// the textclass
- os << "\\textclass " << baseClass()->name() << '\n';
+ os << "\\textclass "
+ << quoteIfNeeded(buf->includedFilePath(addName(buf->layoutPos(),
+ baseClass()->name()), "layout"))
+ << '\n';
// then the preamble
if (!preamble.empty()) {
<< convert<string>(maintain_unincluded_children) << '\n';
// local layout information
+ string const local_layout = getLocalLayout(false);
if (!local_layout.empty()) {
// remove '\n' from the end
string const tmplocal = rtrim(local_layout, "\n");
<< tmplocal
<< "\n\\end_local_layout\n";
}
+ string const forced_local_layout = getLocalLayout(true);
+ if (!forced_local_layout.empty()) {
+ // remove '\n' from the end
+ string const tmplocal = rtrim(forced_local_layout, "\n");
+ os << "\\begin_forced_local_layout\n"
+ << tmplocal
+ << "\n\\end_forced_local_layout\n";
+ }
// then the text parameters
if (language != ignore_language)
os << "\\language_package " << lang_package
<< "\n\\inputencoding " << inputenc
<< "\n\\fontencoding " << fontenc
- << "\n\\font_roman " << fonts_roman
- << "\n\\font_sans " << fonts_sans
- << "\n\\font_typewriter " << fonts_typewriter
- << "\n\\font_math " << fonts_math
+ << "\n\\font_roman \"" << fonts_roman[0]
+ << "\" \"" << fonts_roman[1] << '"'
+ << "\n\\font_sans \"" << fonts_sans[0]
+ << "\" \"" << fonts_sans[1] << '"'
+ << "\n\\font_typewriter \"" << fonts_typewriter[0]
+ << "\" \"" << fonts_typewriter[1] << '"'
+ << "\n\\font_math \"" << fonts_math[0]
+ << "\" \"" << fonts_math[1] << '"'
<< "\n\\font_default_family " << fonts_default_family
<< "\n\\use_non_tex_fonts " << convert<string>(useNonTeXFonts)
<< "\n\\font_sc " << convert<string>(fonts_expert_sc)
<< "\n\\font_osf " << convert<string>(fonts_old_figures)
- << "\n\\font_sf_scale " << fonts_sans_scale
- << "\n\\font_tt_scale " << fonts_typewriter_scale
+ << "\n\\font_sf_scale " << fonts_sans_scale[0]
+ << ' ' << fonts_sans_scale[1]
+ << "\n\\font_tt_scale " << fonts_typewriter_scale[0]
+ << ' ' << fonts_typewriter_scale[1]
<< '\n';
if (!fonts_cjk.empty()) {
os << "\\font_cjk " << fonts_cjk << '\n';
os << "\\papersize " << string_papersize[papersize]
<< "\n\\use_geometry " << convert<string>(use_geometry);
- vector<string> const & packages = auto_packages();
- for (size_t i = 0; i < packages.size(); ++i)
- os << "\n\\use_package " << packages[i] << ' '
- << use_package(packages[i]);
+ map<string, string> const & packages = auto_packages();
+ for (map<string, string>::const_iterator it = packages.begin();
+ it != packages.end(); ++it)
+ os << "\n\\use_package " << it->first << ' '
+ << use_package(it->first);
os << "\n\\cite_engine ";
}
}
- os << "\\tracking_changes " << convert<string>(trackChanges) << '\n'
- << "\\output_changes " << convert<string>(outputChanges) << '\n'
- << "\\html_math_output " << html_math_output << '\n'
+ os << "\\tracking_changes "
+ << (save_transient_properties ? convert<string>(track_changes) : "false")
+ << '\n';
+
+ os << "\\output_changes "
+ << (save_transient_properties ? convert<string>(output_changes) : "false")
+ << '\n';
+
+ os << "\\html_math_output " << html_math_output << '\n'
<< "\\html_css_as_file " << html_css_as_file << '\n'
<< "\\html_be_strict " << convert<string>(html_be_strict) << '\n';
{
features.require(documentClass().requires());
- if (outputChanges) {
+ if (columns > 1 && language->rightToLeft())
+ features.require("rtloutputdblcol");
+
+ if (output_changes) {
bool dvipost = LaTeXFeatures::isAvailable("dvipost");
bool xcolorulem = LaTeXFeatures::isAvailable("ulem") &&
LaTeXFeatures::isAvailable("xcolor");
if (pdfoptions().colorlinks)
features.require("color");
}
+ if (!listings_params.empty()) {
+ // do not test validity because listings_params is
+ // supposed to be valid
+ string par =
+ InsetListingsParams(listings_params).separatedParams(true);
+ // we can't support all packages, but we should load the color package
+ if (par.find("\\color", 0) != string::npos)
+ features.require("color");
+ }
// some languages are only available via polyglossia
- if (features.runparams().flavor == OutputParams::XETEX
- && (features.hasPolyglossiaExclusiveLanguages()
- || useNonTeXFonts))
- features.require("polyglossia");
+ if (features.hasPolyglossiaExclusiveLanguages())
+ features.require("polyglossia");
+
+ if (useNonTeXFonts && fontsMath() != "auto")
+ features.require("unicode-math");
if (!language->requires().empty())
features.require(language->requires());
// are doing!
if (features.mustProvide("fix-cm"))
os << "\\RequirePackage{fix-cm}\n";
+ // Likewise for fixltx2e. If other packages conflict with this policy,
+ // treat it as a package bug (and report it!)
+ // See http://www.latex-project.org/cgi-bin/ltxbugs2html?pr=latex/4407
+ if (features.mustProvide("fixltx2e"))
+ os << "\\RequirePackage{fixltx2e}\n";
os << "\\documentclass";
os << '{' << from_ascii(tclass.latexname()) << "}\n";
// end of \documentclass defs
- // if we use fontspec, we have to load the AMS packages here
+ // if we use fontspec or newtxmath, we have to load the AMS packages here
string const ams = features.loadAMSPackages();
- if (useNonTeXFonts && !ams.empty())
+ bool const ot1 = (font_encoding() == "default" || font_encoding() == "OT1");
+ bool const use_newtxmath =
+ theLaTeXFonts().getLaTeXFont(from_ascii(fontsMath())).getUsedPackage(
+ ot1, false, false) == "newtxmath";
+ if ((useNonTeXFonts || use_newtxmath) && !ams.empty())
os << from_ascii(ams);
- if (useNonTeXFonts)
- os << "\\usepackage{fontspec}\n";
+ if (useNonTeXFonts) {
+ if (!features.isProvided("fontspec"))
+ os << "\\usepackage{fontspec}\n";
+ if (features.mustProvide("unicode-math")
+ && features.isAvailable("unicode-math"))
+ os << "\\usepackage{unicode-math}\n";
+ }
// font selection must be done before loading fontenc.sty
string const fonts = loadFonts(features);
<< from_ascii(fonts_default_family) << "}\n";
// set font encoding
- // for arabic_arabi and farsi we also need to load the LAE and
- // LFE encoding
- // XeTeX and LuaTeX (with OS fonts) work without fontenc
- if (font_encoding() != "default" && language->lang() != "japanese"
- && !useNonTeXFonts && !features.isProvided("fontenc")) {
- size_t fars = language_options.str().find("farsi");
- size_t arab = language_options.str().find("arabic");
- if (language->lang() == "arabic_arabi"
- || language->lang() == "farsi" || fars != string::npos
- || arab != string::npos) {
- os << "\\usepackage[" << from_ascii(font_encoding())
- << ",LFE,LAE]{fontenc}\n";
- } else {
- os << "\\usepackage[" << from_ascii(font_encoding())
+ // XeTeX and LuaTeX (with OS fonts) do not need fontenc
+ if (!useNonTeXFonts && !features.isProvided("fontenc")
+ && font_encoding() != "default") {
+ // get main font encodings
+ vector<string> fontencs = font_encodings();
+ // get font encodings of secondary languages
+ features.getFontEncodings(fontencs);
+ if (!fontencs.empty()) {
+ os << "\\usepackage["
+ << from_ascii(getStringFromVector(fontencs))
<< "]{fontenc}\n";
}
}
os << "}\n";
}
- if (!listings_params.empty() || features.isRequired("listings"))
- os << "\\usepackage{listings}\n";
-
- if (!listings_params.empty()) {
- os << "\\lstset{";
- // do not test validity because listings_params is
- // supposed to be valid
- string par =
- InsetListingsParams(listings_params).separatedParams(true);
- // we can't support all packages, but we should load the color package
- if (par.find("\\color", 0) != string::npos)
- features.require("color");
- os << from_utf8(par)
- << "}\n";
- }
if (!features.isProvided("geometry")
&& (use_geometry || nonstandard_papersize)) {
odocstringstream ods;
lyxpreamble += "\\synctex=-1\n";
}
+ // The package options (via \PassOptionsToPackage)
+ lyxpreamble += from_ascii(features.getPackageOptions());
+
// due to interferences with babel and hyperref, the color package has to
// be loaded (when it is not already loaded) before babel when hyperref
// is used with the colorlinks option, see
// http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg144349.html
lyxpreamble += from_ascii(features.getColorOptions());
- // If we use hyperref, jurabib, japanese, or vietnamese, we have to call babel before them.
+ // If we use hyperref, jurabib, japanese, varioref or vietnamese,
+ // we have to call babel before
if (use_babel
&& (features.isRequired("jurabib")
|| features.isRequired("hyperref")
+ || features.isRequired("varioref")
|| features.isRequired("vietnamese")
|| features.isRequired("japanese"))) {
// FIXME UNICODE
atlyxpreamble += "\\@ifundefined{date}{}{\\date{}}\n";
/* the user-defined preamble */
- if (!containsOnly(preamble, " \n\t"))
+ if (!containsOnly(preamble, " \n\t")) {
// FIXME UNICODE
atlyxpreamble += "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
- "User specified LaTeX commands.\n"
- + from_utf8(preamble) + '\n';
+ "User specified LaTeX commands.\n";
+
+ // Check if the user preamble contains uncodable glyphs
+ docstring const u_preamble = from_utf8(preamble);
+ odocstringstream user_preamble;
+ docstring uncodable_glyphs;
+ Encoding const * const enc = features.runparams().encoding;
+ if (enc) {
+ for (size_t n = 0; n < u_preamble.size(); ++n) {
+ char_type c = u_preamble[n];
+ if (!enc->encodable(c)) {
+ docstring const glyph(1, c);
+ LYXERR0("Uncodable character '"
+ << glyph
+ << "' in user preamble!");
+ uncodable_glyphs += glyph;
+ if (features.runparams().dryrun) {
+ user_preamble << "<" << _("LyX Warning: ")
+ << _("uncodable character") << " '";
+ user_preamble.put(c);
+ user_preamble << "'>";
+ }
+ } else
+ user_preamble.put(c);
+ }
+ } else
+ user_preamble << u_preamble;
+
+ // On BUFFER_VIEW|UPDATE, warn user if we found uncodable glyphs
+ if (!features.runparams().dryrun && !uncodable_glyphs.empty()) {
+ frontend::Alert::warning(
+ _("Uncodable character in user preamble"),
+ support::bformat(
+ _("The user preamble of your document contains glyphs "
+ "that are unknown in the current document encoding "
+ "(namely %1$s).\nThese glyphs are omitted "
+ " from the output, which may result in "
+ "incomplete output."
+ "\n\nPlease select an appropriate "
+ "document encoding\n"
+ "(such as utf8) or change the "
+ "preamble code accordingly."),
+ uncodable_glyphs));
+ }
+ atlyxpreamble += user_preamble.str() + '\n';
+ }
+
+ // footmisc must be loaded after setspace
+ // Load it here to avoid clashes with footmisc loaded in the user
+ // preamble. For that reason we also pass the options via
+ // \PassOptionsToPackage in getPreamble() and not here.
+ if (features.mustProvide("footmisc"))
+ atlyxpreamble += "\\usepackage{footmisc}\n";
// subfig loads internally the LaTeX package "caption". As
// caption is a very popular package, users will load it in
// 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.isRequired("subfig")) {
+ if (features.mustProvide("subfig")) {
atlyxpreamble += "\\@ifundefined{showcaptionsetup}{}{%\n"
" \\PassOptionsToPackage{caption=false}{subfig}}\n"
"\\usepackage{subfig}\n";
+ atlyxpreamble + "\\makeatother\n\n";
// We try to load babel late, in case it interferes with other packages.
- // Jurabib and Hyperref have to be called after babel, though.
+ // Jurabib, hyperref, varioref, bicaption and listings (bug 8995) have to be
+ // called after babel, though.
if (use_babel && !features.isRequired("jurabib")
&& !features.isRequired("hyperref")
+ && !features.isRequired("varioref")
&& !features.isRequired("vietnamese")
&& !features.isRequired("japanese")) {
// FIXME UNICODE
features.needBabelLangOptions())) + '\n';
lyxpreamble += from_utf8(features.getBabelPostsettings());
}
+ if (features.isRequired("bicaption"))
+ lyxpreamble += "\\usepackage{bicaption}\n";
+ if (!listings_params.empty() || features.mustProvide("listings"))
+ lyxpreamble += "\\usepackage{listings}\n";
+ if (!listings_params.empty()) {
+ lyxpreamble += "\\lstset{";
+ // do not test validity because listings_params is
+ // supposed to be valid
+ string par =
+ InsetListingsParams(listings_params).separatedParams(true);
+ lyxpreamble += from_utf8(par);
+ lyxpreamble += "}\n";
+ }
// xunicode needs to be loaded at least after amsmath, amssymb,
// esint and the other packages that provide special glyphs
- if (features.runparams().flavor == OutputParams::XETEX)
+ if (features.runparams().flavor == OutputParams::XETEX
+ && useNonTeXFonts)
lyxpreamble += "\\usepackage{xunicode}\n";
// Polyglossia must be loaded last
}
-void BufferParams::makeDocumentClass()
+void BufferParams::makeDocumentClass(bool const clone)
{
if (!baseClass())
return;
LayoutModuleList mods;
- LayoutModuleList::iterator it;
- LayoutModuleList::iterator en;
-
- it = layout_modules_.begin();
- en = layout_modules_.end();
+ LayoutModuleList::iterator it = layout_modules_.begin();
+ LayoutModuleList::iterator en = layout_modules_.end();
for (; it != en; ++it)
mods.push_back(*it);
+
it = cite_engine_.begin();
en = cite_engine_.end();
for (; it != en; ++it)
mods.push_back(*it);
- doc_class_ = getDocumentClass(*baseClass(), mods);
- if (!local_layout.empty()) {
- TextClass::ReturnValues success =
- doc_class_->read(local_layout, TextClass::MODULE);
- if (success != TextClass::OK && success != TextClass::OK_OLDFORMAT) {
- docstring const msg = _("Error reading internal layout information");
- frontend::Alert::warning(_("Read Error"), msg);
- }
+ doc_class_ = getDocumentClass(*baseClass(), mods, clone);
+
+ TextClass::ReturnValues success = TextClass::OK;
+ if (!forced_local_layout_.empty())
+ success = doc_class_->read(forced_local_layout_, TextClass::MODULE);
+ if (!local_layout_.empty() &&
+ (success == TextClass::OK || success == TextClass::OK_OLDFORMAT))
+ success = doc_class_->read(local_layout_, TextClass::MODULE);
+ if (success != TextClass::OK && success != TextClass::OK_OLDFORMAT) {
+ docstring const msg = _("Error reading internal layout information");
+ frontend::Alert::warning(_("Read Error"), msg);
}
}
-bool BufferParams::moduleCanBeAdded(string const & modName) const
+bool BufferParams::layoutModuleCanBeAdded(string const & modName) const
+{
+ return layout_modules_.moduleCanBeAdded(modName, baseClass());
+}
+
+
+bool BufferParams::citationModuleCanBeAdded(string const & modName) const
+{
+ return cite_engine_.moduleCanBeAdded(modName, baseClass());
+}
+
+
+std::string BufferParams::getLocalLayout(bool forced) const
+{
+ if (forced)
+ return doc_class_->forcedLayouts();
+ else
+ return local_layout_;
+}
+
+
+void BufferParams::setLocalLayout(string const & layout, bool forced)
{
- return cite_engine_.moduleCanBeAdded(modName, baseClass()) &&
- layout_modules_.moduleCanBeAdded(modName, baseClass());
+ if (forced)
+ forced_local_layout_ = layout;
+ else
+ local_layout_ = layout;
}
string format = documentClass().outputFormat();
if (format == "latex") {
if (useNonTeXFonts)
- return "xetex";
+ return "xetex"; // actually "xetex or luatex"
if (encoding().package() == Encoding::japanese)
return "platex";
}
}
-namespace {
-bool formatSorter(Format const * lhs, Format const * rhs) {
- return _(lhs->prettyname()) < _(rhs->prettyname());
-}
-}
-
-
vector<Format const *> BufferParams::exportableFormats(bool only_viewable) const
{
vector<string> const backs = backends();
theConverters().getReachable(*it, only_viewable, false, excludes);
result.insert(result.end(), r.begin(), r.end());
}
- sort(result.begin(), result.end(), formatSorter);
return result;
}
v.push_back("xetex");
} else if (buffmt == "xetex") {
v.push_back("xetex");
- v.push_back("luatex");
- v.push_back("dviluatex");
+ // FIXME: need to test all languages (bug 8205)
+ if (!language || !language->isPolyglossiaExclusive()) {
+ v.push_back("luatex");
+ v.push_back("dviluatex");
+ }
} else
v.push_back(buffmt);
}
-OutputParams::FLAVOR BufferParams::getOutputFlavor(string const format) const
+OutputParams::FLAVOR BufferParams::getOutputFlavor(string const & format) const
{
string const dformat = (format.empty() || format == "default") ?
getDefaultOutputFormat() : format;
else if (dformat == "lyx")
result = OutputParams::LYX;
else if (dformat == "pdflatex")
- result = OutputParams::PDFLATEX;
+ result = OutputParams::PDFLATEX;
else if (dformat == "xetex")
result = OutputParams::XETEX;
else if (dformat == "luatex")
&& default_output_format != "default")
return default_output_format;
if (isDocBook()
- || useNonTeXFonts
|| encoding().package() == Encoding::japanese) {
vector<Format const *> const formats = exportableFormats(true);
if (formats.empty())
// return the first we find
return formats.front()->name();
}
+ if (useNonTeXFonts)
+ return lyxrc.default_otf_view_format;
return lyxrc.default_view_format;
}
}
-InsetQuotes::QuoteLanguage BufferParams::getQuoteStyle(string const qs) const
+InsetQuotes::QuoteLanguage BufferParams::getQuoteStyle(string const & qs) const
{
return quoteslangtranslator().find(qs);
}
}
-void BufferParams::readLocalLayout(Lexer & lex)
+void BufferParams::readLocalLayout(Lexer & lex, bool forced)
{
- if (lex.getString() != "\\begin_local_layout")
+ string const expected = forced ? "\\begin_forced_local_layout" :
+ "\\begin_local_layout";
+ if (lex.getString() != expected)
lyxerr << "Error (BufferParams::readLocalLayout):"
"consistency check failed." << endl;
- local_layout = lex.getLongString("\\end_local_layout");
+ if (forced)
+ forced_local_layout_ =
+ lex.getLongString("\\end_forced_local_layout");
+ else
+ local_layout_ = lex.getLongString("\\end_local_layout");
}
string const BufferParams::font_encoding() const
{
- return (fontenc == "global") ? lyxrc.fontenc : fontenc;
+ return font_encodings().empty() ? "default" : font_encodings().back();
+}
+
+
+vector<string> const BufferParams::font_encodings() const
+{
+ string doc_fontenc = (fontenc == "global") ? lyxrc.fontenc : fontenc;
+
+ vector<string> fontencs;
+
+ // "default" means "no explicit font encoding"
+ if (doc_fontenc != "default") {
+ fontencs = getVectorFromString(doc_fontenc);
+ if (!language->fontenc().empty()
+ && ascii_lowercase(language->fontenc()) != "none") {
+ vector<string> fencs = getVectorFromString(language->fontenc());
+ vector<string>::const_iterator fit = fencs.begin();
+ for (; fit != fencs.end(); ++fit) {
+ if (find(fontencs.begin(), fontencs.end(), *fit) == fontencs.end())
+ fontencs.push_back(*fit);
+ }
+ }
+ }
+
+ return fontencs;
}
void BufferParams::writeEncodingPreamble(otexstream & os,
LaTeXFeatures & features) const
{
- // XeTeX does not need this
- if (features.runparams().flavor == OutputParams::XETEX)
+ // XeTeX/LuaTeX: (see also #9740)
+ // With Unicode fonts we use utf8-plain without encoding package.
+ // With TeX fonts, we cannot use utf8-plain, but "inputenc" fails.
+ // XeTeX must use ASCII encoding, for LuaTeX, we load
+ // "luainputenc" (see below).
+ if (useNonTeXFonts || features.runparams().flavor == OutputParams::XETEX)
return;
- // LuaTeX neither, but with tex fonts, we need to load
- // the luainputenc package.
- if (features.runparams().flavor == OutputParams::LUATEX
- || features.runparams().flavor == OutputParams::DVILUATEX) {
- if (!useNonTeXFonts && inputenc != "default"
- && ((inputenc == "auto" && language->encoding()->package() == Encoding::inputenc)
- || (inputenc != "auto" && encoding().package() == Encoding::inputenc))) {
- os << "\\usepackage[utf8]{luainputenc}\n";
- }
- return;
- }
+
if (inputenc == "auto") {
string const doc_encoding =
language->encoding()->latexName();
Encoding::Package const package =
language->encoding()->package();
- // Create a list with all the input encodings used
- // in the document
- set<string> encodings =
- features.getEncodingSet(doc_encoding);
+ // Create list of inputenc options:
+ set<string> encodings;
+ // luainputenc fails with more than one encoding
+ if (!features.runparams().isFullUnicode()) // if we reach this point, this means LuaTeX with TeX fonts
+ // list all input encodings used in the document
+ encodings = features.getEncodingSet(doc_encoding);
// If the "japanese" package (i.e. pLaTeX) is used,
// inputenc must be omitted.
// see http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129680.html
if ((!encodings.empty() || package == Encoding::inputenc)
- && !features.isRequired("japanese")) {
+ && !features.isRequired("japanese")
+ && !features.isProvided("inputenc")) {
os << "\\usepackage[";
set<string>::const_iterator it = encodings.begin();
set<string>::const_iterator const end = encodings.end();
os << ',';
os << from_ascii(doc_encoding);
}
- os << "]{inputenc}\n";
+ if (features.runparams().flavor == OutputParams::LUATEX
+ || features.runparams().flavor == OutputParams::DVILUATEX)
+ os << "]{luainputenc}\n";
+ else
+ os << "]{inputenc}\n";
}
if (package == Encoding::CJK || features.mustProvide("CJK")) {
if (language->encoding()->name() == "utf8-cjk"
break;
case Encoding::inputenc:
// do not load inputenc if japanese is used
- if (features.isRequired("japanese"))
+ // or if the class provides inputenc
+ if (features.isRequired("japanese")
+ || features.isProvided("inputenc"))
break;
- os << "\\usepackage[" << from_ascii(inputenc)
- << "]{inputenc}\n";
+ os << "\\usepackage[" << from_ascii(encoding().latexName());
+ if (features.runparams().flavor == OutputParams::LUATEX
+ || features.runparams().flavor == OutputParams::DVILUATEX)
+ os << "]{luainputenc}\n";
+ else
+ os << "]{inputenc}\n";
break;
case Encoding::CJK:
if (encoding().name() == "utf8-cjk"
os << "\\usepackage{CJK}\n";
break;
}
+ // Load the CJK package if needed by a secondary language.
+ // If the main encoding is some variant of UTF8, use CJKutf8.
+ if (encoding().package() != Encoding::CJK && features.mustProvide("CJK")) {
+ if (encoding().iconvName() == "UTF-8"
+ && LaTeXFeatures::isAvailable("CJKutf8"))
+ os << "\\usepackage{CJKutf8}\n";
+ else
+ os << "\\usepackage{CJK}\n";
+ }
}
}
string const BufferParams::loadFonts(LaTeXFeatures & features) const
{
- if (fonts_roman == "default" && fonts_sans == "default"
- && fonts_typewriter == "default"
- && (fonts_math == "default" || fonts_math == "auto"))
+ if (fontsRoman() == "default" && fontsSans() == "default"
+ && fontsTypewriter() == "default"
+ && (fontsMath() == "default" || fontsMath() == "auto"))
//nothing to do
return string();
string const texmapping =
(features.runparams().flavor == OutputParams::XETEX) ?
"Mapping=tex-text" : "Ligatures=TeX";
- if (fonts_roman != "default") {
+ if (fontsRoman() != "default") {
os << "\\setmainfont[" << texmapping;
if (fonts_old_figures)
os << ",Numbers=OldStyle";
- os << "]{" << parseFontName(fonts_roman) << "}\n";
+ os << "]{" << parseFontName(fontsRoman()) << "}\n";
}
- if (fonts_sans != "default") {
- string const sans = parseFontName(fonts_sans);
- if (fonts_sans_scale != 100)
+ if (fontsSans() != "default") {
+ string const sans = parseFontName(fontsSans());
+ if (fontsSansScale() != 100)
os << "\\setsansfont[Scale="
- << float(fonts_sans_scale) / 100
+ << float(fontsSansScale()) / 100
<< "," << texmapping << "]{"
<< sans << "}\n";
else
os << "\\setsansfont[" << texmapping << "]{"
<< sans << "}\n";
}
- if (fonts_typewriter != "default") {
- string const mono = parseFontName(fonts_typewriter);
- if (fonts_typewriter_scale != 100)
+ if (fontsTypewriter() != "default") {
+ string const mono = parseFontName(fontsTypewriter());
+ if (fontsTypewriterScale() != 100)
os << "\\setmonofont[Scale="
- << float(fonts_typewriter_scale) / 100
+ << float(fontsTypewriterScale()) / 100
<< "]{"
<< mono << "}\n";
else
// Tex Fonts
bool const ot1 = (font_encoding() == "default" || font_encoding() == "OT1");
bool const dryrun = features.runparams().dryrun;
- bool const complete = (fonts_sans == "default" && fonts_typewriter == "default");
- bool const nomath = (fonts_math == "default");
+ bool const complete = (fontsSans() == "default" && fontsTypewriter() == "default");
+ bool const nomath = (fontsMath() == "default");
// ROMAN FONTS
- os << theLaTeXFonts().getLaTeXFont(from_ascii(fonts_roman)).getLaTeXCode(
+ os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsRoman())).getLaTeXCode(
dryrun, ot1, complete, fonts_expert_sc, fonts_old_figures,
nomath);
// SANS SERIF
- os << theLaTeXFonts().getLaTeXFont(from_ascii(fonts_sans)).getLaTeXCode(
+ os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsSans())).getLaTeXCode(
dryrun, ot1, complete, fonts_expert_sc, fonts_old_figures,
- nomath, fonts_sans_scale);
+ nomath, fontsSansScale());
// MONOSPACED/TYPEWRITER
- os << theLaTeXFonts().getLaTeXFont(from_ascii(fonts_typewriter)).getLaTeXCode(
+ os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsTypewriter())).getLaTeXCode(
dryrun, ot1, complete, fonts_expert_sc, fonts_old_figures,
- nomath, fonts_typewriter_scale);
+ nomath, fontsTypewriterScale());
// MATH
- os << theLaTeXFonts().getLaTeXFont(from_ascii(fonts_math)).getLaTeXCode(
+ os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsMath())).getLaTeXCode(
dryrun, ot1, complete, fonts_expert_sc, fonts_old_figures,
nomath);
Encoding const & BufferParams::encoding() const
{
- // FIXME: actually, we should check for the flavor
- // or runparams.isFullyUnicode() here:
- // This check will not work with XeTeX/LuaTeX and tex fonts.
- // Thus we have to reset the encoding in Buffer::makeLaTeXFile.
+ // Main encoding for LaTeX output.
+ //
+ // Exception: XeTeX with 8-bit TeX fonts requires ASCII (see #9740).
+ // As the "flavor" is only known once export started, this
+ // cannot be handled here. Instead, runparams.encoding is set
+ // to ASCII in Buffer::makeLaTeXFile (for export)
+ // and Buffer::writeLaTeXSource (for preview).
if (useNonTeXFonts)
- return *(encodings.fromLaTeXName("utf8-plain"));
+ return *(encodings.fromLyXName("utf8-plain"));
if (inputenc == "auto" || inputenc == "default")
return *language->encoding();
- Encoding const * const enc = encodings.fromLaTeXName(inputenc);
+ Encoding const * const enc = encodings.fromLyXName(inputenc);
if (enc)
return *enc;
LYXERR0("Unknown inputenc value `" << inputenc