lyx_mirror/src/insets/ExternalTemplate.cpp

608 lines
14 KiB
C++
Raw Normal View History

/**
* \file ExternalTemplate.cpp
* This file is part of LyX, the document processor.
* Licence details can be found in the file COPYING.
*
* \author Asger Alstrup Nielsen
* \author Angus Leeming
*
* Full author contact details are available in file CREDITS.
*/
#include <config.h>
#include "ExternalTemplate.h"
#include "Lexer.h"
#include "support/debug.h"
#include "support/filetools.h"
#include "support/lstrings.h"
Rename files in src/support, step one. src/support/package.h src/support/Package.h Package src/support/package.C.in src/support/Package.C.in Package src/support/path.h src/support/Path.h Path src/support/fs_extras.h src/support/fs_extras.h NOCLASSES src/support/RandomAccessList.h src/support/RandomAccessList.h RandomAccessList src/support/lyxmanip.h src/support/lyxmanip.h NOCLASSES src/support/rename.C src/support/rename.cpp NOCLASSES src/support/abort.C src/support/abort.cpp NOCLASSES src/support/lyxlib.h src/support/lyxlib.h NOCLASSES src/support/ExceptionMessage.h src/support/ExceptionMessage.h ExceptionMessage src/support/copy.C src/support/copy.cpp NOCLASSES src/support/limited_stack.h src/support/limited_stack.h limited_stack src/support/filefilterlist.C src/support/FileFilterList.cpp ['FileFilterList', 'Filter'] src/support/cow_ptr.h src/support/cow_ptr.h cow_ptr src/support/os_unix.C src/support/os_unix.cpp NOCLASSES src/support/socktools.h src/support/socktools.h NOCLASSES src/support/forkedcontr.h src/support/ForkedcallsController.h ForkedcallsController src/support/os.h src/support/os.h NOCLASSES src/support/FileMonitor.h src/support/FileMonitor.h FileMonitor src/support/copied_ptr.h src/support/copied_ptr.h copied_ptr src/support/translator.h src/support/Translator.h Translator src/support/filetools.C src/support/filetools.cpp NOCLASSES src/support/unlink.C src/support/unlink.cpp NOCLASSES src/support/os_win32.C src/support/os_win32.cpp GetFolderPath src/support/lstrings.C src/support/lstrings.cpp NOCLASSES src/support/qstring_helpers.C src/support/qstring_helpers.cpp NOCLASSES src/support/getcwd.C src/support/getcwd.cpp NOCLASSES src/support/systemcall.C src/support/Systemcall.cpp Systemcall src/support/lyxalgo.h src/support/lyxalgo.h NOCLASSES src/support/filefilterlist.h src/support/FileFilterList.h ['FileFilterList', 'Filter'] src/support/unicode.C src/support/unicode.cpp IconvProcessor src/support/userinfo.C src/support/userinfo.cpp NOCLASSES src/support/lyxtime.C src/support/lyxtime.cpp NOCLASSES src/support/kill.C src/support/kill.cpp NOCLASSES src/support/docstring.C src/support/docstring.cpp to_local8bit_failure src/support/os_cygwin.C src/support/os_cygwin.cpp NOCLASSES src/support/lyxsum.C src/support/lyxsum.cpp NOCLASSES src/support/environment.C src/support/environment.cpp NOCLASSES src/support/filetools.h src/support/filetools.h NOCLASSES src/support/textutils.C src/support/textutils.cpp NOCLASSES src/support/mkdir.C src/support/mkdir.cpp NOCLASSES src/support/forkedcall.C src/support/Forkedcall.cpp ['ForkedProcess', 'Forkedcall'] src/support/tempname.C src/support/tempname.cpp NOCLASSES src/support/os_win32.h src/support/os_win32.h GetFolderPath src/support/types.h src/support/types.h NOCLASSES src/support/lstrings.h src/support/lstrings.h NOCLASSES src/support/forkedcallqueue.C src/support/ForkedCallQueue.cpp ForkedCallQueue src/support/qstring_helpers.h src/support/qstring_helpers.h NOCLASSES src/support/convert.C src/support/convert.cpp NOCLASSES src/support/filename.C src/support/FileName.cpp ['FileName', 'DocFileName'] src/support/tests/convert.C src/support/tests/convert.cpp NOCLASSES src/support/tests/filetools.C src/support/tests/filetools.cpp NOCLASSES src/support/tests/lstrings.C src/support/tests/lstrings.cpp NOCLASSES src/support/tests/boost.C src/support/tests/boost.cpp NOCLASSES src/support/docstream.C src/support/docstream.cpp ['iconv_codecvt_facet_exception', 'idocfstream', 'odocfstream'] src/support/std_istream.h src/support/std_istream.h NOCLASSES src/support/systemcall.h src/support/Systemcall.h Systemcall src/support/chdir.C src/support/chdir.cpp NOCLASSES src/support/std_ostream.h src/support/std_ostream.h NOCLASSES src/support/unicode.h src/support/unicode.h IconvProcessor src/support/path.C src/support/Path.cpp Path src/support/fs_extras.C src/support/fs_extras.cpp NOCLASSES src/support/userinfo.h src/support/userinfo.h NOCLASSES src/support/lyxtime.h src/support/lyxtime.h NOCLASSES src/support/docstring.h src/support/docstring.h to_local8bit_failure src/support/debugstream.h src/support/debugstream.h basic_debugstream src/support/environment.h src/support/environment.h NOCLASSES src/support/textutils.h src/support/textutils.h NOCLASSES src/support/forkedcall.h src/support/Forkedcall.h ['ForkedProcess', 'Forkedcall'] src/support/socktools.C src/support/socktools.cpp NOCLASSES src/support/forkedcallqueue.h src/support/ForkedCallQueue.h ForkedCallQueue src/support/forkedcontr.C src/support/ForkedcallsController.cpp ForkedcallsController src/support/os.C src/support/os.cpp NOCLASSES src/support/convert.h src/support/convert.h NOCLASSES src/support/filename.h src/support/FileName.h ['FileName', 'DocFileName'] src/support/docstream.h src/support/docstream.h ['iconv_codecvt_facet_exception', 'idocfstream', 'odocfstream'] src/support/FileMonitor.C src/support/FileMonitor.cpp FileMonitor git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@18024 a592a061-630c-0410-9148-cb99ea01b6c8
2007-04-26 05:12:52 +00:00
#include "support/Package.h"
#include "support/PathChanger.h"
#include "support/Translator.h"
#include <algorithm>
#include <ostream>
using namespace std;
using namespace lyx::support;
namespace lyx {
namespace external {
typedef Translator<TransformID, string> TransformIDTranslator;
static TransformIDTranslator const initIDTranslator()
{
2020-11-24 18:46:49 +00:00
TransformIDTranslator translator(None, "");
translator.addPair(Rotate, "Rotate");
translator.addPair(Resize, "Resize");
translator.addPair(Clip, "Clip");
translator.addPair(Extra, "Extra");
return translator;
}
static TransformIDTranslator const & transformIDTranslator()
{
static TransformIDTranslator const translator = initIDTranslator();
return translator;
}
// We have to have dummy default commands for security reasons!
Template::Template()
: inputFormat("*"), automaticProduction(false), preview_mode(PREVIEW_OFF)
{}
Template::Format::Format()
{}
TemplateManager::TemplateManager()
{
readTemplates(package().user_support());
if (lyxerr.debugging(Debug::EXTERNAL)) {
dumpPreambleDefs(lyxerr);
lyxerr << '\n';
dumpTemplates(lyxerr);
}
}
std::function<void (TemplateManager::PreambleDefs::value_type const &)>
DumpPreambleDef(ostream & os)
{
return [&os](TemplateManager::PreambleDefs::value_type const & vt)
{
os << "PreambleDef " << vt.first << '\n'
<< to_utf8(vt.second)
<< "PreambleDefEnd" << endl;
};
}
std::function<void (TemplateManager::Templates::value_type const &) >
DumpTemplate(ostream & os)
{
return [&os](TemplateManager::Templates::value_type const & vt) {
Template const & et = vt.second;
os << "Template " << et.lyxName << '\n'
<< "\tGuiName " << et.guiName << '\n'
<< "\tHelpText\n"
<< to_utf8(et.helpText)
<< "\tHelpTextEnd\n"
<< "\tInputFormat " << et.inputFormat << '\n'
<< "\tFileFilter " << et.fileRegExp << '\n'
<< "\tAutomaticProduction " << et.automaticProduction << '\n'
<< "\tPreview ";
switch (et.preview_mode) {
case PREVIEW_OFF:
os << "Off\n";
break;
case PREVIEW_GRAPHICS:
os << "Graphics\n";
break;
case PREVIEW_INSTANT:
os << "InstantPreview\n";
break;
}
typedef vector<TransformID> IDs;
IDs::const_iterator it = et.transformIds.begin();
IDs::const_iterator end = et.transformIds.end();
for (; it != end; ++it) {
os << "\tTransform "
<< transformIDTranslator().find(*it) << '\n';
}
et.dumpFormats(os);
os << "TemplateEnd" << endl;
};
}
std::function<void (Template::Formats::value_type const &) >
DumpFormat (ostream & os)
{
return [&os](Template::Formats::value_type const & vt)
{
Template::Format const & ft = vt.second;
os << "\tFormat " << vt.first << '\n'
<< "\t\tProduct " << ft.product << '\n'
<< "\t\tUpdateFormat " << ft.updateFormat << '\n'
<< "\t\tUpdateResult " << ft.updateResult << '\n';
vector<string>::const_iterator qit = ft.requirements.begin();
vector<string>::const_iterator qend = ft.requirements.end();
for (; qit != qend; ++qit) {
lyxerr << "req:" << *qit << endl;
os << "\t\tRequirement " << *qit << '\n';
}
typedef vector<Template::Option> Options;
Options::const_iterator oit = ft.options.begin();
Options::const_iterator oend = ft.options.end();
for (; oit != oend; ++oit) {
os << "\t\tOption "
<< oit->name
<< ": "
<< oit->option
<< '\n';
}
vector<string>::const_iterator pit = ft.preambleNames.begin();
vector<string>::const_iterator pend = ft.preambleNames.end();
for (; pit != pend; ++pit) {
os << "\t\tPreamble " << *pit << '\n';
}
typedef Template::Format::FileMap FileMap;
FileMap::const_iterator rit = ft.referencedFiles.begin();
FileMap::const_iterator rend = ft.referencedFiles.end();
for (; rit != rend; ++rit) {
vector<string>::const_iterator fit = rit->second.begin();
vector<string>::const_iterator fend = rit->second.end();
for (; fit != fend; ++fit) {
os << "\t\tReferencedFile " << rit->first
<< " \"" << *fit << "\"\n";
}
}
os << "\tFormatEnd\n";
};
}
void Template::dumpFormats(ostream & os) const
{
for_each(formats.begin(), formats.end(), DumpFormat(os));
}
void TemplateManager::dumpPreambleDefs(ostream & os) const
{
for_each(preambledefs.begin(), preambledefs.end(), DumpPreambleDef(os));
}
void TemplateManager::dumpTemplates(ostream & os) const
{
for_each(templates.begin(), templates.end(), DumpTemplate(os));
}
TemplateManager & TemplateManager::get()
{
static TemplateManager externalTemplateManager;
return externalTemplateManager;
}
TemplateManager::Templates const & TemplateManager::getTemplates() const
{
return templates;
}
Template const *
TemplateManager::getTemplateByName(string const & name) const
{
Templates::const_iterator it = templates.find(name);
return (it == templates.end()) ? 0 : &it->second;
}
docstring TemplateManager::getPreambleDefByName(string const & name) const
{
string const trimmed_name = trim(name);
if (trimmed_name.empty())
return docstring();
PreambleDefs::const_iterator it = preambledefs.find(trimmed_name);
if (it == preambledefs.end())
return docstring();
return it->second;
}
void TemplateManager::readTemplates(FileName const & path)
{
PathChanger p(path);
enum {
TM_PREAMBLEDEF = 1,
TM_PREAMBLEDEF_END,
TM_TEMPLATE,
TM_TEMPLATE_END
};
LexerKeyword templatetags[] = {
{ "preambledef", TM_PREAMBLEDEF },
{ "preambledefend", TM_PREAMBLEDEF_END },
{ "template", TM_TEMPLATE },
{ "templateend", TM_TEMPLATE_END }
};
// Read the templates list
vector<string> templateslist;
FileName const real_file = libFileSearch("", "xtemplates.lst");
LYXERR(Debug::EXTERNAL, "Reading external templates from `" << real_file << '\'');
if (real_file.empty()) {
LYXERR0("unable to find external templates file `xtemplates.lst'.\n"
<< "No external templates will be available.");
return;
}
Lexer tlex;
if (!tlex.setFile(real_file)) {
LYXERR0("lyxlex was not able to set file: "
<< real_file << ".\nNo external templates will be available.");
return;
}
if (!tlex.isOK()) {
LYXERR0("unable to open external templates file `"
<< to_utf8(makeDisplayPath(real_file.absFileName(), 1000))
<< "'\nNo external templates will be available.");
return;
}
bool finished = false;
// Parse external templates files
LYXERR(Debug::EXTERNAL, "Starting parsing of xtemplates.lst");
while (tlex.isOK() && !finished) {
LYXERR(Debug::EXTERNAL, "\tline by line");
switch (tlex.lex()) {
case Lexer::LEX_FEOF:
finished = true;
break;
default:
string const name = tlex.getString();
LYXERR(Debug::EXTERNAL, "Template name: " << name);
templateslist.push_back(name);
break;
}
}
LYXERR(Debug::EXTERNAL, "End of parsing of xtemplates.lst");
for (vector<string>::const_iterator it = templateslist.begin(); it != templateslist.end(); ++it) {
FileName const filename = libFileSearch("xtemplates", *it);
LYXERR(Debug::EXTERNAL, "Reading template file " << filename.absFileName());
Lexer lex(templatetags);
if (filename.empty() || !lex.setFile(filename)) {
lex.printError("external::TemplateManager::readTemplates: "
"No template file");
return;
}
char const * const preamble_end_tag =
templatetags[TM_PREAMBLEDEF_END-1].tag;
while (lex.isOK()) {
switch (lex.lex()) {
case TM_PREAMBLEDEF: {
lex.next();
string const name = lex.getString();
preambledefs[name] = lex.getLongString(from_ascii(preamble_end_tag));
break;
}
case TM_TEMPLATE: {
lex.next();
string const name = lex.getString();
Template & tmp = templates[name];
tmp.lyxName = name;
tmp.readTemplate(lex);
break;
}
case TM_TEMPLATE_END:
lex.printError("Warning: End outside Template.");
break;
case TM_PREAMBLEDEF_END:
lex.printError("Warning: End outside PreambleDef.");
break;
default:
break;
}
}
}
}
void Template::readTemplate(Lexer & lex)
{
enum {
TO_GUINAME = 1,
TO_HELPTEXT,
TO_INPUTFORMAT,
TO_FILTER,
TO_AUTOMATIC,
TO_PREVIEW,
TO_TRANSFORM,
TO_FORMAT,
TO_END
};
LexerKeyword templateoptiontags[] = {
{ "automaticproduction", TO_AUTOMATIC },
{ "filefilter", TO_FILTER },
{ "format", TO_FORMAT },
{ "guiname", TO_GUINAME },
{ "helptext", TO_HELPTEXT },
{ "inputformat", TO_INPUTFORMAT },
{ "preview", TO_PREVIEW },
{ "templateend", TO_END },
{ "transform", TO_TRANSFORM }
};
PushPopHelper pph(lex, templateoptiontags);
lex.setContext("Template::readTemplate");
string token;
while (lex.isOK()) {
switch (lex.lex()) {
case TO_GUINAME:
lex.next(true);
guiName = lex.getString();
break;
case TO_HELPTEXT:
helpText = lex.getLongString(from_ascii("HelpTextEnd"));
break;
case TO_INPUTFORMAT:
lex.next(true);
inputFormat = lex.getString();
break;
case TO_FILTER:
lex.next(true);
fileRegExp = lex.getString();
break;
case TO_AUTOMATIC:
lex.next();
automaticProduction = lex.getBool();
break;
case TO_PREVIEW:
lex >> token;
if (token == "InstantPreview")
preview_mode = PREVIEW_INSTANT;
else if (token == "Graphics")
preview_mode = PREVIEW_GRAPHICS;
else
preview_mode = PREVIEW_OFF;
break;
case TO_TRANSFORM: {
lex >> token;
TransformID id = transformIDTranslator().find(token);
if (int(id) == -1)
LYXERR0("Transform " << token << " is not recognized");
else
transformIds.push_back(id);
break;
}
case TO_FORMAT:
lex.next(true);
formats[lex.getString()].readFormat(lex);
break;
case TO_END:
return;
}
}
}
namespace {
void transform_not_found(ostream & os, string const & transform)
{
os << "external::Format::readFormat. Transformation \""
<< transform << "\" is unrecognized." << endl;
}
void transform_class_not_found(ostream & os, string const & tclass)
{
os << "external::Format::readFormat. Transformation class \""
<< tclass << "\" is unrecognized." << endl;
}
void setCommandFactory(Template::Format & format, string const & transform,
string const & transformer_class)
{
bool class_found = false;
if (transform == "Resize" && transformer_class == "ResizeLatexCommand") {
class_found = true;
ResizeCommandFactory factory = ResizeLatexCommand::factory;
format.command_transformers[Resize] =
TransformStore(Resize, factory);
} else if (transform == "Rotate" &&
transformer_class == "RotationLatexCommand") {
class_found = true;
RotationCommandFactory factory = RotationLatexCommand::factory;
format.command_transformers[Rotate] =
TransformStore(Rotate, factory);
} else
transform_not_found(lyxerr, transform);
if (!class_found)
transform_class_not_found(lyxerr, transformer_class);
}
void setOptionFactory(Template::Format & format, string const & transform,
string const & transformer_class)
{
bool class_found = false;
if (transform == "Clip" && transformer_class == "ClipLatexOption") {
class_found = true;
ClipOptionFactory factory = ClipLatexOption::factory;
format.option_transformers[Clip] =
TransformStore(Clip, factory);
} else if (transform == "Extra" && transformer_class == "ExtraOption") {
class_found = true;
ExtraOptionFactory factory = ExtraOption::factory;
format.option_transformers[Extra] =
TransformStore(Extra, factory);
} else if (transform == "Resize" &&
transformer_class == "ResizeLatexOption") {
class_found = true;
ResizeOptionFactory factory = ResizeLatexOption::factory;
format.option_transformers[Resize] =
TransformStore(Resize, factory);
} else if (transform == "Rotate" &&
transformer_class == "RotationLatexOption") {
class_found = true;
RotationOptionFactory factory = RotationLatexOption::factory;
format.option_transformers[Rotate] =
TransformStore(Rotate, factory);
} else
transform_not_found(lyxerr, transform);
if (!class_found)
transform_class_not_found(lyxerr, transformer_class);
}
Bulk cleanup/fix incorrect annotation at the end of namespaces. This commit does a bulk fix of incorrect annotations (comments) at the end of namespaces. The commit was generated by initially running clang-format, and then from the diff of the result extracting the hunks corresponding to fixes of namespace comments. The changes being applied and all the results have been manually reviewed. The source code successfully builds on macOS. Further details on the steps below, in case they're of interest to someone else in the future. 1. Checkout a fresh and up to date version of src/ git pull && git checkout -- src && git status src 2. Ensure there's a suitable .clang-format in place, i.e. with options to fix the comment at the end of namespaces, including: FixNamespaceComments: true SpacesBeforeTrailingComments: 1 and that clang-format is >= 5.0.0, by doing e.g.: clang-format -dump-config | grep Comments: clang-format --version 3. Apply clang-format to the source: clang-format -i $(find src -name "*.cpp" -or -name "*.h") 4. Create and filter out hunks related to fixing the namespace git diff -U0 src > tmp.patch grepdiff '^} // namespace' --output-matching=hunk tmp.patch > fix_namespace.patch 5. Filter out hunks corresponding to simple fixes into to a separate patch: pcregrep -M -e '^diff[^\n]+\nindex[^\n]+\n--- [^\n]+\n\+\+\+ [^\n]+\n' \ -e '^@@ -[0-9]+ \+[0-9]+ @@[^\n]*\n-\}[^\n]*\n\+\}[^\n]*\n' \ fix_namespace.patch > fix_namespace_simple.patch 6. Manually review the simple patch and then apply it, after first restoring the source. git checkout -- src patch -p1 < fix_namespace_simple.path 7. Manually review the (simple) changes and then stage the changes git diff src git add src 8. Again apply clang-format and filter out hunks related to any remaining fixes to the namespace, this time filter with more context. There will be fewer hunks as all the simple cases have already been handled: clang-format -i $(find src -name "*.cpp" -or -name "*.h") git diff src > tmp.patch grepdiff '^} // namespace' --output-matching=hunk tmp.patch > fix_namespace2.patch 9. Manually review/edit the resulting patch file to remove hunks for files which need to be dealt with manually, noting the file names and line numbers. Then restore files to as before applying clang-format and apply the patch: git checkout src patch -p1 < fix_namespace2.patch 10. Manually fix the files noted in the previous step. Stage files, review changes and commit.
2017-07-23 11:11:54 +00:00
} // namespace
void Template::Format::readFormat(Lexer & lex)
{
enum {
FO_PRODUCT = 1,
FO_UPDATEFORMAT,
FO_UPDATERESULT,
FO_REQUIREMENT,
FO_OPTION,
FO_PREAMBLE,
FO_TRANSFORMCOMMAND,
FO_TRANSFORMOPTION,
FO_REFERENCEDFILE,
FO_END
};
LexerKeyword formattags[] = {
{ "formatend", FO_END },
{ "option", FO_OPTION },
{ "preamble", FO_PREAMBLE },
{ "product", FO_PRODUCT },
{ "referencedfile", FO_REFERENCEDFILE },
{ "requirement", FO_REQUIREMENT },
{ "transformcommand", FO_TRANSFORMCOMMAND },
{ "transformoption", FO_TRANSFORMOPTION },
{ "updateformat", FO_UPDATEFORMAT },
{ "updateresult", FO_UPDATERESULT }
};
PushPopHelper pph(lex, formattags);
while (lex.isOK()) {
switch (lex.lex()) {
case FO_PRODUCT:
lex.next(true);
product = lex.getString();
break;
case FO_UPDATEFORMAT:
lex.next(true);
updateFormat = lex.getString();
break;
case FO_UPDATERESULT:
lex.next(true);
updateResult = lex.getString();
break;
case FO_REQUIREMENT:
lex.next(true);
requirements.push_back(lex.getString());
break;
case FO_PREAMBLE:
lex.next(true);
preambleNames.push_back(lex.getString());
break;
case FO_TRANSFORMCOMMAND: {
lex.next(true);
string const name = lex.getString();
lex.next(true);
setCommandFactory(*this, name, lex.getString());
break;
}
case FO_TRANSFORMOPTION: {
lex.next(true);
string const name = lex.getString();
lex.next(true);
setOptionFactory(*this, name, lex.getString());
break;
}
case FO_OPTION: {
lex.next(true);
string const name = lex.getString();
lex.next(true);
string const opt = lex.getString();
options.push_back(Option(name, opt));
break;
}
case FO_REFERENCEDFILE: {
lex.next(true);
string const format = lex.getString();
lex.next(true);
string const file = lex.getString();
referencedFiles[format].push_back(file);
break;
}
case FO_END:
return;
}
}
}
} // namespace external
} // namespace lyx