#include "LayoutModuleList.h"
#include "ModuleList.h"
#include "Preamble.h"
-#include "TextClass.h"
#include "support/ConsoleApplication.h"
#include "support/convert.h"
+#include "support/debug.h"
#include "support/ExceptionMessage.h"
#include "support/filetools.h"
#include "support/lassert.h"
}
-Layout const * findLayoutWithoutModule(TextClass const & textclass,
- string const & name, bool command)
+Layout const * findLayoutWithoutModule(TextClass const & tc,
+ string const & name, bool command,
+ string const & latexparam)
{
- DocumentClass::const_iterator it = textclass.begin();
- DocumentClass::const_iterator en = textclass.end();
- for (; it != en; ++it) {
- if (it->latexname() == name &&
- ((command && it->isCommand()) || (!command && it->isEnvironment())))
- return &*it;
+ for (auto const & lay : tc) {
+ if (lay.latexname() == name &&
+ (latexparam.empty() ||
+ (!lay.latexparam().empty() && suffixIs(latexparam, lay.latexparam()))) &&
+ ((command && lay.isCommand()) || (!command && lay.isEnvironment())))
+ return &lay;
}
return 0;
}
-InsetLayout const * findInsetLayoutWithoutModule(TextClass const & textclass,
- string const & name, bool command)
+InsetLayout const * findInsetLayoutWithoutModule(TextClass const & tc,
+ string const & name, bool command,
+ string const & latexparam)
{
- DocumentClass::InsetLayouts::const_iterator it = textclass.insetLayouts().begin();
- DocumentClass::InsetLayouts::const_iterator en = textclass.insetLayouts().end();
- for (; it != en; ++it) {
- if (it->second.latexname() == name &&
- ((command && it->second.latextype() == InsetLayout::COMMAND) ||
- (!command && it->second.latextype() == InsetLayout::ENVIRONMENT)))
- return &(it->second);
+ for (auto const & ilay : tc.insetLayouts()) {
+ if (ilay.second.latexname() == name &&
+ (latexparam.empty() ||
+ (!ilay.second.latexparam().empty() && suffixIs(latexparam, ilay.second.latexparam()))) &&
+ ((command && ilay.second.latextype() == InsetLaTeXType::COMMAND) ||
+ (!command && ilay.second.latextype() == InsetLaTeXType::ENVIRONMENT)))
+ return &(ilay.second);
}
return 0;
}
for (; it != end; ++it) {
string const module = it->getID();
LayoutModuleList m;
- LayoutModuleList c;
vector<string> v;
if (!addModule(module, baseClass, m, v))
continue;
- modules[module] = getDocumentClass(baseClass, m, c);
+ modules[module] = getDocumentClass(baseClass, m);
}
init = false;
}
return false;
}
-}
+} // namespace
bool checkModule(string const & name, bool command)
// Cache to avoid slowdown by repated searches
static set<string> failed[2];
- // Only add the module if the command was actually defined in the LyX preamble
+ // Record whether the command was actually defined in the LyX preamble
bool theorem = false;
+ bool preamble_def = true;
if (command) {
if (possible_textclass_commands.find('\\' + name) == possible_textclass_commands.end())
- return false;
+ preamble_def = false;
} else {
if (possible_textclass_environments.find(name) == possible_textclass_environments.end()) {
if (possible_textclass_theorems.find(name) != possible_textclass_theorems.end())
theorem = true;
else
- return false;
+ preamble_def = false;
}
}
if (failed[command].find(name) != failed[command].end())
LayoutFile const & baseClass = LayoutFileList::get()[textclass.name()];
// Try to find a module that defines the command.
- // Only add it if the definition can be found in the preamble of the
- // style that corresponds to the command. This is a heuristic and
- // different from the way how we parse the builtin commands of the
- // text class (in that case we only compare the name), but it is
- // needed since it is not unlikely that two different modules define a
+ // For commands with preamble definitions we prefer modules where the definition
+ // can be found in the preamble of the style that corresponds to the command.
+ // For others we check whether the command or module requires a package that is loaded
+ // in the tex file and use a style with the respective command.
+ // This is a heuristic and different from the way how we parse the builtin
+ // commands of the text class (in that case we only compare the name),
+ // but it is needed since it is not unlikely that two different modules define a
// command with the same name.
+ string found_module;
+ vector<string> potential_modules;
ModuleMap::iterator const end = modules.end();
for (ModuleMap::iterator it = modules.begin(); it != end; ++it) {
string const module = it->first;
continue;
DocumentClassConstPtr c = it->second;
Layout const * layout = findLayoutWithoutModule(*c, name, command);
- InsetLayout const * insetlayout = layout ? 0 :
+ InsetLayout const * insetlayout = layout ? nullptr :
findInsetLayoutWithoutModule(*c, name, command);
- docstring preamble;
- if (layout)
- preamble = layout->preamble();
- else if (insetlayout)
- preamble = insetlayout->preamble();
- if (preamble.empty())
+ docstring dpre;
+ std::set<std::string> cmd_reqs;
+ bool found_style = false;
+ if (layout) {
+ found_style = true;
+ dpre = layout->preamble();
+ std::set<std::string> const & lreqs = layout->required();
+ if (!lreqs.empty())
+ cmd_reqs.insert(lreqs.begin(), lreqs.end());
+ } else if (insetlayout) {
+ found_style = true;
+ dpre = insetlayout->preamble();
+ std::set<std::string> lreqs = insetlayout->required();
+ if (!lreqs.empty())
+ cmd_reqs.insert(lreqs.begin(), lreqs.end());
+ }
+ if (dpre.empty() && preamble_def)
continue;
- bool add = false;
- if (command) {
- FullCommand const & cmd =
- possible_textclass_commands['\\' + name];
- if (preamble.find(cmd.def) != docstring::npos)
- add = true;
- } else if (theorem) {
- FullCommand const & thm =
- possible_textclass_theorems[name];
- if (preamble.find(thm.def) != docstring::npos)
- add = true;
- } else {
- FullEnvironment const & env =
- possible_textclass_environments[name];
- if (preamble.find(env.beg) != docstring::npos &&
- preamble.find(env.end) != docstring::npos)
- add = true;
+ bool const package_cmd = dpre.empty();
+ bool match_req = false;
+ if (package_cmd) {
+ std::set<std::string> mreqs = it->second->required();
+ if (!mreqs.empty())
+ cmd_reqs.insert(mreqs.begin(), mreqs.end());
+ for (auto const & pack : cmd_reqs) {
+ // If a requirement of the module matches a used package
+ // we load the module except if we have an auto-loaded package
+ // which is only required generally by the module, and the module
+ // does not provide the [inset]layout we are looking for.
+ // This heuristics should
+ // * load modules if the provide a style we don't have in the class
+ // * load modules that provide a package support generally (such as fixltx2e)
+ // * not unnecessarily load modules just because they require a package which we
+ // load anyway.
+ if (preamble.isPackageUsed(pack)
+ && (found_style || !preamble.isPackageAutoLoaded(pack))) {
+ if (found_style)
+ match_req = true;
+ else
+ potential_modules.push_back(module);
+ break;
+ }
+ }
+ }
+ bool add = match_req;
+ if (preamble_def) {
+ if (command) {
+ FullCommand const & cmd =
+ possible_textclass_commands['\\' + name];
+ if (dpre.find(cmd.def) != docstring::npos)
+ add = true;
+ } else if (theorem) {
+ FullCommand const & thm =
+ possible_textclass_theorems[name];
+ if (dpre.find(thm.def) != docstring::npos)
+ add = true;
+ } else {
+ FullEnvironment const & env =
+ possible_textclass_environments[name];
+ if (dpre.find(env.beg) != docstring::npos &&
+ dpre.find(env.end) != docstring::npos)
+ add = true;
+ }
}
if (add) {
- FileName layout_file = libFileSearch("layouts", module, "module");
+ found_module = module;
+ break;
+ }
+ }
+ if (found_module.empty()) {
+ // take one of the second row
+ if (!potential_modules.empty())
+ found_module = potential_modules.front();
+ }
+
+ if (!found_module.empty()) {
+ vector<string> v;
+ LayoutModuleList mods;
+ // addModule is necessary in order to catch required modules
+ // as well (see #11156)
+ if (!addModule(found_module, baseClass, mods, v))
+ return false;
+ for (auto const & mod : mods) {
+ if (!used_modules.moduleCanBeAdded(mod, &baseClass))
+ return false;
+ FileName layout_file = libFileSearch("layouts", mod, "module");
if (textclass.read(layout_file, TextClass::MODULE)) {
- used_modules.push_back(module);
+ used_modules.push_back(mod);
// speed up further searches:
// the module does not need to be checked anymore.
- modules.erase(it);
+ ModuleMap::iterator const it = modules.find(mod);
+ if (it != modules.end())
+ modules.erase(it);
return true;
}
}
argc_(argc), argv_(argv)
{
}
- void doExec()
+ void doExec() override
{
try {
int const exit_status = run();
// class may not be known before. It neds to be done before parsing
// body, since otherwise the commands/environments provided by the
// modules would be parsed as ERT.
- for (size_t i = 0; i < preloaded_modules.size(); ++i) {
- if (!addModule(preloaded_modules[i])) {
+ for (auto const & module : preloaded_modules) {
+ if (!addModule(module)) {
cerr << "Error: Could not load module \""
- << preloaded_modules[i] << "\"." << endl;
+ << module << "\"." << endl;
return false;
}
}
context.font.language = preamble.defaultLanguage();
// parse the main text
parse_text(p, ss, FLAG_END, true, context);
+ // check if we need a commented bibtex inset (biblatex)
+ check_comment_bib(ss, context);
if (Context::empty)
// Empty document body. LyX needs at least one paragraph.
context.check_layout(ss);
// actual encoding is different (bug 7509).
if (encoding.empty()) {
Encoding const * enc = 0;
- if (preamble.inputencoding() == "auto") {
+ if (preamble.inputencoding() == "auto-legacy") {
ifdocstream is(setEncoding("ISO-8859-1"));
// forbid buffering on this stream
is.rdbuf()->pubsetbuf(0, 0);
encoding = enc->iconvName();
else
encoding = "ISO-8859-1";
+ // store
+ preamble.docencoding = encoding;
}
ifdocstream is(setEncoding(encoding));
if (configFileNeedsUpdate("lyxrc.defaults") ||
configFileNeedsUpdate("lyxmodules.lst") ||
configFileNeedsUpdate("textclass.lst") ||
- configFileNeedsUpdate("packages.lst"))
+ configFileNeedsUpdate("packages.lst") ||
+ configFileNeedsUpdate("lyxciteengines.lst") ||
+ configFileNeedsUpdate("xtemplates.lst"))
package().reconfigureUserLyXDir("");
fileUnlock(fd, lock_file.c_str());
} else