int const LYX_FORMAT = LYX_FORMAT_LYX;
typedef map<string, bool> DepClean;
-typedef map<docstring, pair<InsetLabel const *, Buffer::References> > RefCache;
+
+// Information about labels and their associated refs
+struct LabelInfo {
+ /// label string
+ docstring label;
+ /// label inset
+ InsetLabel const * inset;
+ /// associated references cache
+ Buffer::References references;
+ /// whether this label is active (i.e., not deleted)
+ bool active;
+};
+
+typedef vector<LabelInfo> LabelCache;
+
+typedef map<docstring, Buffer::References> RefCache;
} // namespace
/// A cache for the bibfiles (including bibfiles of loaded child
/// documents), needed for appropriate update of natbib labels.
- mutable FileNamePairList bibfiles_cache_;
+ mutable docstring_list bibfiles_cache_;
// FIXME The caching mechanism could be improved. At present, we have a
// cache for each Buffer, that caches all the bibliography info for that
/// we ran updateBuffer(), i.e., whether citation labels may need
/// to be updated.
mutable bool cite_labels_valid_;
+ /// Do we have a bibliography environment?
+ mutable bool have_bibitems_;
/// These two hold the file name and format, written to by
/// Buffer::preview and read from by LFUN_BUFFER_VIEW_CACHE.
/// was missing).
bool preview_error_;
+ /// Cache the references associated to a label and their positions
+ /// in the buffer.
mutable RefCache ref_cache_;
+ /// Cache the label insets and their activity status.
+ mutable LabelCache label_cache_;
/// our Text that should be wrapped in an InsetText
InsetText * inset;
file_fully_loaded(false), file_format(LYX_FORMAT), need_format_backup(false),
ignore_parent(false), toc_backend(owner), macro_lock(false),
checksum_(0), wa_(0), gui_(0), undo_(*owner), bibinfo_cache_valid_(false),
- cite_labels_valid_(false), preview_error_(false),
+ cite_labels_valid_(false), have_bibitems_(false), preview_error_(false),
inset(0), preview_loader_(0), cloned_buffer_(cloned_buffer),
clone_list_(0), doing_export(false),
tracked_changes_present_(0), externally_modified_(false), parent_buffer(0),
bibinfo_cache_valid_ = cloned_buffer_->d->bibinfo_cache_valid_;
bibfile_status_ = cloned_buffer_->d->bibfile_status_;
cite_labels_valid_ = cloned_buffer_->d->cite_labels_valid_;
+ have_bibitems_ = cloned_buffer_->d->have_bibitems_;
unnamed = cloned_buffer_->d->unnamed;
internal_buffer = cloned_buffer_->d->internal_buffer;
layout_position = cloned_buffer_->d->layout_position;
}
-Buffer * Buffer::cloneFromMaster() const
+Buffer * Buffer::cloneWithChildren() const
{
BufferMap bufmap;
cloned_buffers.push_back(new CloneList);
CloneList * clones = cloned_buffers.back();
- masterBuffer()->cloneWithChildren(bufmap, clones);
+ cloneWithChildren(bufmap, clones);
// make sure we got cloned
BufferMap::const_iterator bit = bufmap.find(this);
params().options.erase();
params().master.erase();
params().float_placement.erase();
+ params().float_alignment.erase();
params().paperwidth.erase();
params().paperheight.erase();
params().leftmargin.erase();
<< absFileName()
<< ") does not include "
"this document. Ignoring the master assignment.");
+ // If the master has just been created, un-hide it (#11162)
+ if (!master->fileName().exists())
+ lyx::dispatch(FuncRequest(LFUN_BUFFER_SWITCH,
+ master->absFileName()));
}
}
}
return false;
// It is important to use the correct extension here, since some
// converters create a wrong output file otherwise (e.g. html2latex)
- TempFile const tempfile("Buffer_importStringXXXXXX." + fmt->extension());
- FileName const name(tempfile.name());
+ FileName const name = tempFileName("Buffer_importStringXXXXXX." + fmt->extension());
ofdocstream os(name.toFilesystemEncoding().c_str());
// Do not convert os implicitly to bool, since that is forbidden in C++11.
bool const success = !(os << contents).fail();
converted = importFile(format, name, errorList);
}
- if (name.exists())
- name.removeFile();
+ removeTempFile(name);
return converted;
}
if (!theConverters().isReachable(format, "lyx"))
return false;
- TempFile const tempfile("Buffer_importFileXXXXXX.lyx");
- FileName const lyx(tempfile.name());
- if (theConverters().convert(0, name, lyx, name, format, "lyx", errorList))
- return readFile(lyx) == ReadSuccess;
+ FileName const lyx = tempFileName("Buffer_importFileXXXXXX.lyx");
+ Converters::RetVal const retval =
+ theConverters().convert(0, name, lyx, name, format, "lyx", errorList);
+ if (retval == Converters::SUCCESS) {
+ bool const success = readFile(lyx) == ReadSuccess;
+ removeTempFile(lyx);
+ return success;
+ }
return false;
}
FileName Buffer::getBackupName() const {
+ map<int, string> const file_formats = {
+ {544, "23"},
+ {508, "22"},
+ {474, "21"},
+ {413, "20"},
+ {345, "16"},
+ {276, "15"},
+ {245, "14"},
+ {221, "13"},
+ {220, "12"},
+ {218, "1163"},
+ {217, "116"},
+ {216, "115"},
+ {215, "11"},
+ {210, "010"},
+ {200, "006"}
+ };
FileName const & fn = fileName();
string const fname = fn.onlyFileNameWithoutExt();
string const fext = fn.extension() + "~";
string const fpath = lyxrc.backupdir_path.empty() ?
fn.onlyPath().absFileName() :
lyxrc.backupdir_path;
- string const fform = convert<string>(d->file_format);
- string const backname = fname + "-lyxformat-" + fform;
+ string backup_suffix;
+ // If file format is from a stable series use version instead of file format
+ auto const it = file_formats.find(d->file_format);
+ if (it != file_formats.end())
+ backup_suffix = "-lyx" + it->second;
+ else
+ backup_suffix = "-lyxformat-" + convert<string>(d->file_format);
+ string const backname = fname + backup_suffix;
FileName backup(addName(fpath, addExtension(backname, fext)));
// limit recursion, just in case
FileName savefile(tempfile->name());
LYXERR(Debug::FILES, "Saving to " << savefile.absFileName());
+ if (!savefile.clonePermissions(fileName()))
+ LYXERR0("Failed to clone the permission from " << fileName().absFileName() << " to " << savefile.absFileName());
+
if (!writeFile(savefile))
return false;
// Important: Keep the version formatting in sync with lyx2lyx and
// tex2lyx (bug 7951)
ofs << "#LyX " << lyx_version_major << "." << lyx_version_minor
- << " created this file. For more info see http://www.lyx.org/\n"
+ << " created this file. For more info see https://www.lyx.org/\n"
<< "\\lyxformat " << LYX_FORMAT << "\n"
<< "\\begin_document\n";
}
-bool Buffer::makeLaTeXFile(FileName const & fname,
+Buffer::ExportStatus Buffer::makeLaTeXFile(FileName const & fname,
string const & original_path,
OutputParams const & runparams_in,
OutputWhat output) const
Alert::error(_("Iconv software exception Detected"), bformat(_("Please "
"verify that the support software for your encoding (%1$s) is "
"properly installed"), from_ascii(encoding)));
- return false;
+ return ExportError;
}
if (!openFileWrite(ofs, fname))
- return false;
+ return ExportError;
ErrorList & errorList = d->errorLists["Export"];
errorList.clear();
- bool failed_export = false;
+ ExportStatus status = ExportSuccess;
otexstream os(ofs);
// make sure we are ready to export
updateBuffer();
updateMacroInstances(OutputUpdate);
+ ExportStatus retval;
try {
- writeLaTeXSource(os, original_path, runparams, output);
+ retval = writeLaTeXSource(os, original_path, runparams, output);
+ if (retval == ExportKilled)
+ return ExportKilled;
}
catch (EncodingException const & e) {
docstring const failed(1, e.failed_char);
ostringstream oss;
oss << "0x" << hex << e.failed_char << dec;
- docstring msg = bformat(_("Could not find LaTeX command for character '%1$s'"
- " (code point %2$s)"),
- failed, from_utf8(oss.str()));
- errorList.push_back(ErrorItem(msg, _("Some characters of your document are probably not "
- "representable in the chosen encoding.\n"
- "Changing the document encoding to utf8 could help."),
- {e.par_id, e.pos}, {e.par_id, e.pos + 1}));
- failed_export = true;
+ if (getParFromID(e.par_id).paragraph().layout().pass_thru) {
+ docstring msg = bformat(_("Uncodable character '%1$s'"
+ " (code point %2$s)"),
+ failed, from_utf8(oss.str()));
+ errorList.push_back(ErrorItem(msg, _("Some characters of your document are not "
+ "representable in specific verbatim contexts.\n"
+ "Changing the document encoding to utf8 could help."),
+ {e.par_id, e.pos}, {e.par_id, e.pos + 1}));
+ } else {
+ docstring msg = bformat(_("Could not find LaTeX command for character '%1$s'"
+ " (code point %2$s)"),
+ failed, from_utf8(oss.str()));
+ errorList.push_back(ErrorItem(msg, _("Some characters of your document are probably not "
+ "representable in the chosen encoding.\n"
+ "Changing the document encoding to utf8 could help."),
+ {e.par_id, e.pos}, {e.par_id, e.pos + 1}));
+ }
+ status = ExportError;
}
catch (iconv_codecvt_facet_exception const & e) {
errorList.push_back(ErrorItem(_("iconv conversion failed"),
_(e.what())));
- failed_export = true;
+ status = ExportError;
}
catch (exception const & e) {
errorList.push_back(ErrorItem(_("conversion failed"),
_(e.what())));
lyxerr << e.what() << endl;
- failed_export = true;
+ status = ExportError;
}
catch (...) {
lyxerr << "Caught some really weird exception..." << endl;
ofs.close();
if (ofs.fail()) {
- failed_export = true;
+ status = ExportError;
lyxerr << "File '" << fname << "' was not closed properly." << endl;
}
errorList.clear();
else
errors("Export");
- return !failed_export;
+ return status;
}
-void Buffer::writeLaTeXSource(otexstream & os,
+Buffer::ExportStatus Buffer::writeLaTeXSource(otexstream & os,
string const & original_path,
OutputParams const & runparams_in,
OutputWhat output) const
// (or not reached) and characters encodable in the current
// encoding are not converted to ASCII-representation.
+ // Some macros rely on font encoding
+ runparams.main_fontenc = params().main_font_encoding();
+
// If we are compiling a file standalone, even if this is the
// child of some other buffer, let's cut the link here, so the
// file is really independent and no concurring settings from
// first paragraph of the document. (Asger)
if (output_preamble && runparams.nice) {
os << "%% LyX " << lyx_version << " created this file. "
- "For more info, see http://www.lyx.org/.\n"
+ "For more info, see https://www.lyx.org/.\n"
"%% Do not edit unless you really know what "
"you are doing.\n";
}
"file path name."),
inputpath, uncodable_glyphs));
} else {
- string docdir =
- latex_path(original_path);
+ string docdir = os::latex_path(original_path);
if (contains(docdir, '#')) {
docdir = subst(docdir, "#", "\\#");
os << "\\catcode`\\#=11"
os << "\\catcode`\\%=11"
"\\def\\%{%}\\catcode`\\%=14\n";
}
+ bool const detokenize = !isAscii(from_utf8(docdir));
+ bool const quote = contains(docdir, ' ');
os << "\\makeatletter\n"
- << "\\def\\input@path{{"
- << docdir << "}}\n"
+ << "\\def\\input@path{{";
+ if (detokenize)
+ os << "\\detokenize{";
+ if (quote)
+ os << "\"";
+ os << docdir;
+ if (quote)
+ os << "\"";
+ if (detokenize)
+ os << "}";
+ os << "}}\n"
<< "\\makeatother\n";
}
}
// Restore the parenthood if needed
if (!runparams.is_child)
d->ignore_parent = false;
- return;
+ return ExportSuccess;
}
// make the body.
LYXERR(Debug::INFO, "preamble finished, now the body.");
// the real stuff
- latexParagraphs(*this, text(), os, runparams);
+ try {
+ latexParagraphs(*this, text(), os, runparams);
+ }
+ catch (ConversionException const &) { return ExportKilled; }
// Restore the parenthood if needed
if (!runparams.is_child)
LYXERR(Debug::INFO, "Finished making LaTeX file.");
LYXERR(Debug::INFO, "Row count was " << os.texrow().rows() - 1 << '.');
+ return ExportSuccess;
}
-void Buffer::makeDocBookFile(FileName const & fname,
+Buffer::ExportStatus Buffer::makeDocBookFile(FileName const & fname,
OutputParams const & runparams,
OutputWhat output) const
{
ofdocstream ofs;
if (!openFileWrite(ofs, fname))
- return;
+ return ExportError;
// make sure we are ready to export
// this needs to be done before we validate
updateBuffer();
updateMacroInstances(OutputUpdate);
- writeDocBookSource(ofs, fname.absFileName(), runparams, output);
+ ExportStatus const retval =
+ writeDocBookSource(ofs, fname.absFileName(), runparams, output);
+ if (retval == ExportKilled)
+ return ExportKilled;
ofs.close();
if (ofs.fail())
lyxerr << "File '" << fname << "' was not closed properly." << endl;
+ return ExportSuccess;
}
-void Buffer::writeDocBookSource(odocstream & os, string const & fname,
+Buffer::ExportStatus Buffer::writeDocBookSource(odocstream & os, string const & fname,
OutputParams const & runparams,
OutputWhat output) const
{
os << from_ascii(tclass.class_header());
else if (runparams.flavor == OutputParams::XML)
os << "PUBLIC \"-//OASIS//DTD DocBook XML V4.2//EN\" "
- << "\"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd\"";
+ << "\"https://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd\"";
else
os << " PUBLIC \"-//OASIS//DTD DocBook V4.2//EN\"";
os << "<!-- " << ((runparams.flavor == OutputParams::XML)? "XML" : "SGML")
<< " file was created by LyX " << lyx_version
- << "\n See http://www.lyx.org/ for more information -->\n";
+ << "\n See https://www.lyx.org/ for more information -->\n";
params().documentClass().counters().reset();
sgml::openTag(os, top);
os << '\n';
- docbookParagraphs(text(), *this, os, runparams);
+ try {
+ docbookParagraphs(text(), *this, os, runparams);
+ }
+ catch (ConversionException const &) { return ExportKilled; }
sgml::closeTag(os, top_element);
}
+ return ExportSuccess;
}
-void Buffer::makeLyXHTMLFile(FileName const & fname,
+Buffer::ExportStatus Buffer::makeLyXHTMLFile(FileName const & fname,
OutputParams const & runparams) const
{
LYXERR(Debug::LATEX, "makeLyXHTMLFile...");
ofdocstream ofs;
if (!openFileWrite(ofs, fname))
- return;
+ return ExportError;
// make sure we are ready to export
// this has to be done before we validate
updateBuffer(UpdateMaster, OutputUpdate);
updateMacroInstances(OutputUpdate);
- writeLyXHTMLSource(ofs, runparams, FullSource);
+ ExportStatus const retval = writeLyXHTMLSource(ofs, runparams, FullSource);
+ if (retval == ExportKilled)
+ return retval;
ofs.close();
if (ofs.fail())
lyxerr << "File '" << fname << "' was not closed properly." << endl;
+ return retval;
}
-void Buffer::writeLyXHTMLSource(odocstream & os,
+Buffer::ExportStatus Buffer::writeLyXHTMLSource(odocstream & os,
OutputParams const & runparams,
OutputWhat output) const
{
if (output != IncludedFile)
// if we're an included file, the counters are in the master.
params().documentClass().counters().reset();
- xhtmlParagraphs(text(), *this, xs, runparams);
+ try {
+ xhtmlParagraphs(text(), *this, xs, runparams);
+ }
+ catch (ConversionException const &) { return ExportKilled; }
if (output_body_tag)
os << "</body>\n";
}
if (output_preamble)
os << "</html>\n";
+
+ return ExportSuccess;
}
runparams.flavor = OutputParams::LATEX;
runparams.nice = false;
runparams.linelen = lyxrc.plaintext_linelen;
- makeLaTeXFile(FileName(name), org_path, runparams);
+ ExportStatus const retval =
+ makeLaTeXFile(FileName(name), org_path, runparams);
+ if (retval != ExportSuccess) {
+ // error code on failure
+ return -1;
+ }
TeXErrors terr;
Chktex chktex(lyxrc.chktex_command, onlyFileName(name), filePath());
}
-FileNamePairList const & Buffer::getBibfiles(UpdateScope scope) const
+docstring_list const & Buffer::getBibfiles(UpdateScope scope) const
{
// FIXME This is probably unnecessary, given where we call this.
// If this is a child document, use the master instead.
Buffer const * const pbuf = masterBuffer();
if (pbuf != this && scope != UpdateChildOnly)
return pbuf->getBibfiles();
+
+ // In 2.3.x, we have:
+ //if (!d->bibfile_cache_valid_)
+ // this->updateBibfilesCache(scope);
+ // I think that is a leftover, but there have been so many back-
+ // and-forths with this, due to Windows issues, that I am not sure.
+
return d->bibfiles_cache_;
}
}
-void Buffer::registerBibfiles(FileNamePairList const & bf) const {
+BiblioInfo const & Buffer::bibInfo() const
+{
+ return d->bibinfo_;
+}
+
+
+void Buffer::registerBibfiles(const docstring_list & bf) const
+{
+ // We register the bib files in the master buffer,
+ // if there is one, but also in every single buffer,
+ // in case a child is compiled alone.
Buffer const * const tmp = masterBuffer();
if (tmp != this)
- return tmp->registerBibfiles(bf);
+ tmp->registerBibfiles(bf);
for (auto const & p : bf) {
- FileNamePairList::const_iterator temp =
+ docstring_list::const_iterator temp =
find(d->bibfiles_cache_.begin(), d->bibfiles_cache_.end(), p);
if (temp == d->bibfiles_cache_.end())
d->bibfiles_cache_.push_back(p);
}
+static map<docstring, FileName> bibfileCache;
+
+FileName Buffer::getBibfilePath(docstring const & bibid) const
+{
+ map<docstring, FileName>::const_iterator it =
+ bibfileCache.find(bibid);
+ if (it != bibfileCache.end()) {
+ // i.e., bibfileCache[bibid]
+ return it->second;
+ }
+
+ LYXERR(Debug::FILES, "Reading file location for " << bibid);
+ string texfile = changeExtension(to_utf8(bibid), "bib");
+ // note that, if the filename can be found directly from the path,
+ // findtexfile will just return a FileName object for that path.
+ FileName file(findtexfile(texfile, "bib"));
+ if (file.empty())
+ file = FileName(makeAbsPath(texfile, filePath()));
+ LYXERR(Debug::FILES, "Found at: " << file);
+
+ bibfileCache[bibid] = file;
+ return bibfileCache[bibid];
+}
+
+
void Buffer::checkIfBibInfoCacheIsValid() const
{
// use the master's cache
return;
}
- // if we already know the cache is invalid, no need to check
- // the timestamps
+ // If we already know the cache is invalid, stop here.
+ // This is important in the case when the bibliography
+ // environment (rather than Bib[la]TeX) is used.
+ // In that case, the timestamp check below gives no
+ // sensible result. Rather than that, the cache will
+ // be invalidated explicitly via invalidateBibInfoCache()
+ // by the Bibitem inset.
+ // Same applies for bib encoding changes, which trigger
+ // invalidateBibInfoCache() by InsetBibtex.
if (!d->bibinfo_cache_valid_)
return;
+ if (d->have_bibitems_) {
+ // We have a bibliography environment.
+ // Invalidate the bibinfo cache unconditionally.
+ // Cite labels will get invalidated by the inset if needed.
+ d->bibinfo_cache_valid_ = false;
+ return;
+ }
+
+ // OK. This is with Bib(la)tex. We'll assume the cache
+ // is valid and change this if we find changes in the bibs.
+ d->bibinfo_cache_valid_ = true;
+ d->cite_labels_valid_ = true;
+
// compare the cached timestamps with the actual ones.
- FileNamePairList const & bibfiles_cache = getBibfiles();
- FileNamePairList::const_iterator ei = bibfiles_cache.begin();
- FileNamePairList::const_iterator en = bibfiles_cache.end();
- for (; ei != en; ++ ei) {
- FileName const fn = ei->second;
+ docstring_list const & bibfiles_cache = getBibfiles();
+ for (auto const & bf : bibfiles_cache) {
+ FileName const fn = getBibfilePath(bf);
time_t lastw = fn.lastModified();
time_t prevw = d->bibfile_status_[fn];
if (lastw != prevw) {
}
-void Buffer::reloadBibInfoCache() const
+void Buffer::clearBibFileCache() const
+{
+ bibfileCache.clear();
+}
+
+
+void Buffer::reloadBibInfoCache(bool const force) const
{
+ // we should not need to do this for internal buffers
+ if (isInternal())
+ return;
+
// use the master's cache
Buffer const * const tmp = masterBuffer();
if (tmp != this) {
- tmp->reloadBibInfoCache();
+ tmp->reloadBibInfoCache(force);
return;
}
- checkIfBibInfoCacheIsValid();
- if (d->bibinfo_cache_valid_)
- return;
+ if (!force) {
+ checkIfBibInfoCacheIsValid();
+ if (d->bibinfo_cache_valid_)
+ return;
+ }
+ LYXERR(Debug::FILES, "Bibinfo cache was invalid.");
+ // re-read file locations when this info changes
+ // FIXME Is this sufficient? Or should we also force that
+ // in some other cases? If so, then it is easy enough to
+ // add the following line in some other places.
+ clearBibFileCache();
d->bibinfo_.clear();
FileNameList checkedFiles;
+ d->have_bibitems_ = false;
collectBibKeys(checkedFiles);
d->bibinfo_cache_valid_ = true;
}
void Buffer::collectBibKeys(FileNameList & checkedFiles) const
{
- for (InsetIterator it = inset_iterator_begin(inset()); it; ++it)
+ for (InsetIterator it = inset_iterator_begin(inset()); it; ++it) {
it->collectBibKeys(it, checkedFiles);
+ if (it->lyxCode() == BIBITEM_CODE) {
+ if (parent() != 0)
+ parent()->d->have_bibitems_ = true;
+ else
+ d->have_bibitems_ = true;
+ }
+ }
}
-void Buffer::addBiblioInfo(BiblioInfo const & bi) const
+void Buffer::addBiblioInfo(BiblioInfo const & bin) const
{
- Buffer const * tmp = masterBuffer();
- BiblioInfo & masterbi = (tmp == this) ?
- d->bibinfo_ : tmp->d->bibinfo_;
- masterbi.mergeBiblioInfo(bi);
+ // We add the biblio info to the master buffer,
+ // if there is one, but also to every single buffer,
+ // in case a child is compiled alone.
+ BiblioInfo & bi = d->bibinfo_;
+ bi.mergeBiblioInfo(bin);
+
+ if (parent() != 0) {
+ BiblioInfo & masterbi = parent()->d->bibinfo_;
+ masterbi.mergeBiblioInfo(bin);
+ }
}
-void Buffer::addBibTeXInfo(docstring const & key, BibTeXInfo const & bi) const
+void Buffer::addBibTeXInfo(docstring const & key, BibTeXInfo const & bin) const
{
- Buffer const * tmp = masterBuffer();
- BiblioInfo & masterbi = (tmp == this) ?
- d->bibinfo_ : tmp->d->bibinfo_;
- masterbi[key] = bi;
+ // We add the bibtex info to the master buffer,
+ // if there is one, but also to every single buffer,
+ // in case a child is compiled alone.
+ BiblioInfo & bi = d->bibinfo_;
+ bi[key] = bin;
+
+ if (parent() != 0) {
+ BiblioInfo & masterbi = masterBuffer()->d->bibinfo_;
+ masterbi[key] = bin;
+ }
}
}
+void Buffer::invalidateCiteLabels() const
+{
+ masterBuffer()->d->cite_labels_valid_ = false;
+}
+
bool Buffer::citeLabelsValid() const
{
return masterBuffer()->d->cite_labels_valid_;
break;
}
- case LFUN_BUFFER_CHKTEX:
- enable = params().isLatex() && !lyxrc.chktex_command.empty();
- break;
-
case LFUN_BUILD_PROGRAM:
enable = params().isExportable("program", false);
break;
flag.setOnOff(params().output_changes);
break;
- case LFUN_BUFFER_TOGGLE_COMPRESSION: {
+ case LFUN_BUFFER_TOGGLE_COMPRESSION:
flag.setOnOff(params().compressed);
break;
- }
- case LFUN_BUFFER_TOGGLE_OUTPUT_SYNC: {
+ case LFUN_BUFFER_TOGGLE_OUTPUT_SYNC:
flag.setOnOff(params().output_sync);
break;
- }
+
+ case LFUN_BUFFER_ANONYMIZE:
+ break;
default:
return false;
break;
}
- case LFUN_BUFFER_CHKTEX:
- runChktex();
- break;
-
case LFUN_BUFFER_EXPORT_CUSTOM: {
string format_name;
string command = split(argument, format_name, ' ');
params().output_sync = !params().output_sync;
break;
+ case LFUN_BUFFER_ANONYMIZE: {
+ undo().recordUndoFullBuffer(CursorData());
+ CursorData cur(doc_iterator_begin(this));
+ for ( ; cur ; cur.forwardPar())
+ cur.paragraph().anonymize();
+ dr.forceBufferUpdate();
+ dr.screenUpdate(Update::Force);
+ break;
+ }
+
default:
dispatched = false;
break;
vector<docstring> const Buffer::prepareBibFilePaths(OutputParams const & runparams,
- FileNamePairList const bibfilelist,
+ docstring_list const & bibfilelist,
bool const add_extension) const
{
// If we are processing the LaTeX file in a temp directory then
bool found_space = false;
for (auto const & bit : bibfilelist) {
- string utf8input = to_utf8(bit.first);
+ string utf8input = to_utf8(bit);
string database =
prepareFileNameForLaTeX(utf8input, ".bib", runparams.nice);
- FileName const try_in_file =
+ FileName try_in_file =
makeAbsPath(database + ".bib", filePath());
- bool const not_from_texmf = try_in_file.isReadableFile();
+ bool not_from_texmf = try_in_file.isReadableFile();
+ // If the file has not been found, try with the real file name
+ // (it might come from a child in a sub-directory)
+ if (!not_from_texmf) {
+ try_in_file = getBibfilePath(bit);
+ if (try_in_file.isReadableFile()) {
+ // Check if the file is in texmf
+ FileName kpsefile(findtexfile(changeExtension(utf8input, "bib"), "bib", true));
+ not_from_texmf = kpsefile.empty()
+ || kpsefile.absFileName() != try_in_file.absFileName();
+ if (not_from_texmf)
+ // If this exists, make path relative to the master
+ // FIXME Unicode
+ database =
+ removeExtension(prepareFileNameForLaTeX(
+ to_utf8(makeRelPath(from_utf8(try_in_file.absFileName()),
+ from_utf8(filePath()))),
+ ".bib", runparams.nice));
+ }
+ }
if (!runparams.inComment && !runparams.dryrun && !runparams.nice &&
not_from_texmf) {
RefCache::iterator it = d->ref_cache_.find(label);
if (it != d->ref_cache_.end())
- return it->second.second;
+ return it->second;
- static InsetLabel const * dummy_il = 0;
static References const dummy_refs = References();
it = d->ref_cache_.insert(
- make_pair(label, make_pair(dummy_il, dummy_refs))).first;
- return it->second.second;
+ make_pair(label, dummy_refs)).first;
+ return it->second;
}
}
-void Buffer::setInsetLabel(docstring const & label, InsetLabel const * il)
+void Buffer::setInsetLabel(docstring const & label, InsetLabel const * il,
+ bool const active)
{
- masterBuffer()->d->ref_cache_[label].first = il;
+ LabelInfo linfo;
+ linfo.label = label;
+ linfo.inset = il;
+ linfo.active = active;
+ masterBuffer()->d->label_cache_.push_back(linfo);
}
-InsetLabel const * Buffer::insetLabel(docstring const & label) const
+InsetLabel const * Buffer::insetLabel(docstring const & label,
+ bool const active) const
{
- return masterBuffer()->d->ref_cache_[label].first;
+ for (auto & rc : masterBuffer()->d->label_cache_) {
+ if (rc.label == label && (rc.active || !active))
+ return rc.inset;
+ }
+ return nullptr;
+}
+
+
+bool Buffer::activeLabel(docstring const & label) const
+{
+ if (!insetLabel(label, true))
+ return false;
+
+ return true;
}
void Buffer::clearReferenceCache() const
{
- if (!d->parent())
+ if (!d->parent()) {
d->ref_cache_.clear();
+ d->label_cache_.clear();
+ }
}
// No side effect of file copying and image conversion
runparams.dryrun = true;
+ // Some macros rely on font encoding
+ runparams.main_fontenc = params().main_font_encoding();
+
if (output == CurrentParagraph) {
runparams.par_begin = par_begin;
runparams.par_end = par_end;
return ExportNoPathToFormat;
}
runparams.flavor = converters.getFlavor(path, this);
+ runparams.hyperref_driver = converters.getHyperrefDriver(path);
for (auto const & edge : path)
if (theConverters().get(edge).nice()) {
need_nice_file = true;
// Plain text backend
if (backend_format == "text") {
runparams.flavor = OutputParams::TEXT;
- writePlaintextFile(*this, FileName(filename), runparams);
+ try {
+ writePlaintextFile(*this, FileName(filename), runparams);
+ }
+ catch (ConversionException const &) { return ExportCancel; }
}
// HTML backend
else if (backend_format == "xhtml") {
runparams.flavor = OutputParams::HTML;
setMathFlavor(runparams);
- makeLyXHTMLFile(FileName(filename), runparams);
+ if (makeLyXHTMLFile(FileName(filename), runparams) == ExportKilled)
+ return ExportKilled;
} else if (backend_format == "lyx")
writeFile(FileName(filename));
// Docbook backend
else if (params().isDocBook()) {
runparams.nice = !put_in_tempdir;
- makeDocBookFile(FileName(filename), runparams);
+ if (makeDocBookFile(FileName(filename), runparams) == ExportKilled)
+ return ExportKilled;
}
// LaTeX backend
else if (backend_format == format || need_nice_file) {
runparams.nice = true;
- bool const success = makeLaTeXFile(FileName(filename), string(), runparams);
+ ExportStatus const retval =
+ makeLaTeXFile(FileName(filename), string(), runparams);
+ if (retval == ExportKilled)
+ return ExportKilled;
if (d->cloned_buffer_)
d->cloned_buffer_->d->errorLists["Export"] = d->errorLists["Export"];
- if (!success)
- return ExportError;
+ if (retval != ExportSuccess)
+ return retval;
} else if (!lyxrc.tex_allows_spaces
&& contains(filePath(), ' ')) {
Alert::error(_("File name error"),
- _("The directory path to the document cannot contain spaces."));
+ bformat(_("The directory path to the document\n%1$s\n"
+ "contains spaces, but your TeX installation does "
+ "not allow them. You should save the file to a directory "
+ "whose name does not contain spaces."), from_ascii(filePath())));
return ExportTexPathHasSpaces;
} else {
runparams.nice = false;
- bool const success = makeLaTeXFile(
- FileName(filename), filePath(), runparams);
+ ExportStatus const retval =
+ makeLaTeXFile(FileName(filename), filePath(), runparams);
+ if (retval == ExportKilled)
+ return ExportKilled;
if (d->cloned_buffer_)
d->cloned_buffer_->d->errorLists["Export"] = d->errorLists["Export"];
- if (!success)
+ if (retval != ExportSuccess)
return ExportError;
}
ErrorList & error_list = d->errorLists[error_type];
string const ext = theFormats().extension(format);
FileName const tmp_result_file(changeExtension(filename, ext));
- bool const success = converters.convert(this, FileName(filename),
- tmp_result_file, FileName(absFileName()), backend_format, format,
- error_list);
+ Converters::RetVal const retval =
+ converters.convert(this, FileName(filename), tmp_result_file,
+ FileName(absFileName()), backend_format, format, error_list);
+ if (retval == Converters::KILLED)
+ return ExportCancel;
+ bool success = (retval == Converters::SUCCESS);
// Emit the signal to show the error list or copy it back to the
// cloned Buffer so that it can be emitted afterwards.
_("&Remove"), _("&Keep"));
if (del_emerg == 0)
emergencyFile.removeFile();
+ else {
+ // See bug #11464
+ FileName newname;
+ string const ename = emergencyFile.absFileName();
+ bool noname = true;
+ // Surely we can find one in 100 tries?
+ for (int i = 1; i < 100; ++i) {
+ newname.set(ename + to_string(i) + ".lyx");
+ if (!newname.exists()) {
+ noname = false;
+ break;
+ }
+ }
+ if (!noname) {
+ // renameTo returns true on success. So inverting that
+ // will give us true if we fail.
+ noname = !emergencyFile.renameTo(newname);
+ }
+ if (noname) {
+ Alert::warning(_("Can't rename emergency file!"),
+ _("LyX was unable to rename the emergency file. "
+ "You should do so manually. Otherwise, you will be "
+ "asked about it again the next time you try to load "
+ "this file, and may over-write your own work."));
+ }
+ }
return ReadOriginal;
}
Buffer const * const master = masterBuffer();
DocumentClass const & textclass = master->params().documentClass();
- FileNamePairList old_bibfiles;
- // do this only if we are the top-level Buffer
- if (master == this) {
+ docstring_list old_bibfiles;
+ // Do this only if we are the top-level Buffer. We also need to account
+ // for the case of a previewed child with ignored parent here.
+ if (master == this && !d->ignore_parent) {
textclass.counters().reset(from_ascii("bibitem"));
reloadBibInfoCache();
// we will re-read this cache as we go through, but we need
// not updated during the updateBuffer call and TocModel::toc_ is invalid
// (bug 5699). The same happens if the master buffer is open in a different
// window. This test catches both possibilities.
- // See: http://marc.info/?l=lyx-devel&m=138590578911716&w=2
+ // See: https://marc.info/?l=lyx-devel&m=138590578911716&w=2
// There remains a problem here: If there is another child open in yet a third
// window, that TOC is not updated. So some more general solution is needed at
// some point.
return;
// if the bibfiles changed, the cache of bibinfo is invalid
- sort(d->bibfiles_cache_.begin(), d->bibfiles_cache_.end());
- // the old one should already be sorted
- if (old_bibfiles != d->bibfiles_cache_) {
+ docstring_list new_bibfiles = d->bibfiles_cache_;
+ // this is a trick to determine whether the two vectors have
+ // the same elements.
+ sort(new_bibfiles.begin(), new_bibfiles.end());
+ sort(old_bibfiles.begin(), old_bibfiles.end());
+ if (old_bibfiles != new_bibfiles) {
+ LYXERR(Debug::FILES, "Reloading bibinfo cache.");
invalidateBibinfoCache();
reloadBibInfoCache();
// We relied upon the bibinfo cache when recalculating labels. But that
// labels. Nothing else will have changed. So we could create a new
// UpdateType that would signal that fact, if we needed to do so.
parit = cbuf.par_iterator_begin();
+ // we will be re-doing the counters and references and such.
+ textclass.counters().reset();
+ clearReferenceCache();
+ // we should not need to do this again?
+ // updateMacros();
+ setChangesPresent(false);
updateBuffer(parit, utype);
+ // this will already have been done by reloadBibInfoCache();
+ // d->bibinfo_cache_valid_ = true;
}
- else
+ else {
+ LYXERR(Debug::FILES, "Bibfiles unchanged.");
+ // this is also set to true on the other path, by reloadBibInfoCache.
d->bibinfo_cache_valid_ = true;
+ }
d->cite_labels_valid_ = true;
/// FIXME: Perf
cbuf.tocBackend().update(true, utype);
Buffer::ReadStatus Buffer::reload()
{
setBusy(true);
- // c.f. bug http://www.lyx.org/trac/ticket/6587
+ // c.f. bug https://www.lyx.org/trac/ticket/6587
removeAutosaveFile();
// e.g., read-only status could have changed due to version control
d->filename.refresh();
"checksum unchanged: " << filename);
return;
}
- lyx_clean = bak_clean = false;
// If the file has been deleted, only mark the file as dirty since it is
// pointless to prompt for reloading. If later a file is moved into this
// location, then the externally modified warning will appear then.