X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2FBuffer.cpp;h=979b37ed5f27d220bfce3cec9f8954e5a8a4fc5c;hb=86fab2cefa122a5b0c0ee4ade472e41d9a3ff1cf;hp=840de8cd688b9edb5fa3fb5dba7355b5d7120004;hpb=26b1c55e03f61bfd4a2f8135c69ef8f7a0bd0513;p=lyx.git diff --git a/src/Buffer.cpp b/src/Buffer.cpp index 840de8cd68..979b37ed5f 100644 --- a/src/Buffer.cpp +++ b/src/Buffer.cpp @@ -47,6 +47,7 @@ #include "output_docbook.h" #include "output.h" #include "output_latex.h" +#include "output_xhtml.h" #include "output_plaintext.h" #include "paragraph_funcs.h" #include "Paragraph.h" @@ -68,6 +69,7 @@ #include "insets/InsetBibitem.h" #include "insets/InsetBibtex.h" +#include "insets/InsetBranch.h" #include "insets/InsetInclude.h" #include "insets/InsetText.h" @@ -125,7 +127,7 @@ namespace { // Do not remove the comment below, so we get merge conflict in // independent branches. Instead add your own. -int const LYX_FORMAT = 352; // jspitzm: splitindex support +int const LYX_FORMAT = 364; // spitz: branch suffixes for filenames typedef map DepClean; typedef map > RefCache; @@ -438,12 +440,29 @@ Undo & Buffer::undo() string Buffer::latexName(bool const no_path) const { - FileName latex_name = makeLatexName(d->filename); + FileName latex_name = + makeLatexName(exportFileName()); return no_path ? latex_name.onlyFileName() : latex_name.absFilename(); } +FileName Buffer::exportFileName() const +{ + docstring const branch_suffix = + params().branchlist().getFilenameSuffix(); + if (branch_suffix.empty()) + return fileName(); + + string const name = fileName().onlyFileNameWithoutExt() + + to_utf8(branch_suffix); + FileName res(fileName().onlyPath().absFilename() + "/" + name); + res.changeExtension(fileName().extension()); + + return res; +} + + string Buffer::logName(LogType * type) const { string const filename = latexName(false); @@ -459,19 +478,38 @@ string Buffer::logName(LogType * type) const FileName const fname(addName(temppath(), onlyFilename(changeExtension(filename, ".log")))); + + // FIXME: how do we know this is the name of the build log? FileName const bname( addName(path, onlyFilename( changeExtension(filename, - formats.extension("literate") + ".out")))); + formats.extension(bufferFormat()) + ".out")))); - // If no Latex log or Build log is newer, show Build log + // Also consider the master buffer log file + FileName masterfname = fname; + LogType mtype; + if (masterBuffer() != this) { + string const mlogfile = masterBuffer()->logName(&mtype); + masterfname = FileName(mlogfile); + } + // If no Latex log or Build log is newer, show Build log if (bname.exists() && - (!fname.exists() || fname.lastModified() < bname.lastModified())) { + ((!fname.exists() && !masterfname.exists()) + || (fname.lastModified() < bname.lastModified() + && masterfname.lastModified() < bname.lastModified()))) { LYXERR(Debug::FILES, "Log name calculated as: " << bname); if (type) *type = buildlog; return bname.absFilename(); + // If we have a newer master file log or only a master log, show this + } else if (fname != masterfname + && (!fname.exists() && (masterfname.exists() + || fname.lastModified() < masterfname.lastModified()))) { + LYXERR(Debug::FILES, "Log name calculated as: " << masterfname); + if (type) + *type = mtype; + return masterfname.absFilename(); } LYXERR(Debug::FILES, "Log name calculated as: " << fname); if (type) @@ -525,6 +563,7 @@ int Buffer::readHeader(Lexer & lex) params().clearRemovedModules(); params().pdfoptions().clear(); params().indiceslist().clear(); + params().backgroundcolor = lyx::rgbFromHexName("#ffffff"); for (int i = 0; i < 4; ++i) { params().user_defined_bullet(i) = ITEMIZE_DEFAULTS[i]; @@ -1334,6 +1373,65 @@ void Buffer::writeDocBookSource(odocstream & os, string const & fname, } +void Buffer::makeLyXHTMLFile(FileName const & fname, + OutputParams const & runparams, + bool const body_only) const +{ + LYXERR(Debug::LATEX, "makeLYXHTMLFile..."); + + ofdocstream ofs; + if (!openFileWrite(ofs, fname)) + return; + + writeLyXHTMLSource(ofs, runparams, body_only); + + ofs.close(); + if (ofs.fail()) + lyxerr << "File '" << fname << "' was not closed properly." << endl; +} + + +void Buffer::writeLyXHTMLSource(odocstream & os, + OutputParams const & runparams, + bool const only_body) const +{ + LaTeXFeatures features(*this, params(), runparams); + validate(features); + + d->texrow.reset(); + + if (!only_body) { + os << "\n"; + // FIXME Language should be set properly. + os << "\n"; + // FIXME Header + os << "\n"; + // FIXME Presumably need to set this right + os << "\n"; + // FIXME Get this during validation? What about other meta-data? + os << "TBA\n"; + + os << features.getTClassHTMLPreamble(); + + os << '\n'; + + docstring const styleinfo = features.getTClassHTMLStyles(); + if (!styleinfo.empty()) { + os << "\n"; + } + os << "\n\n"; + } + + params().documentClass().counters().reset(); + xhtmlParagraphs(paragraphs(), *this, os, runparams); + if (!only_body) + os << "\n\n"; +} + + // chktex should be run with these flags disabled: 3, 22, 25, 30, 38(?) // Other flags: -wall -v0 -x int Buffer::runChktex() @@ -1541,6 +1639,8 @@ bool Buffer::getStatus(FuncRequest const & cmd, FuncStatus & flag) break; } + case LFUN_BRANCH_ADD: + case LFUN_BRANCHES_RENAME: case LFUN_BUFFER_PRINT: // if no Buffer is present, then of course we won't be called! flag.setEnabled(true); @@ -1577,6 +1677,28 @@ void Buffer::dispatch(FuncRequest const & func, DispatchResult & dr) break; } + case LFUN_BRANCH_ADD: { + BranchList & branchList = params().branchlist(); + docstring const branchName = func.argument(); + if (branchName.empty()) { + dispatched = false; + break; + } + Branch * branch = branchList.find(branchName); + if (branch) { + LYXERR0("Branch " << branchName << " does already exist."); + dr.setError(true); + docstring const msg = + bformat(_("Branch \"%1$s\" does already exist."), branchName); + dr.setMessage(msg); + } else { + branchList.add(branchName); + dr.setError(false); + dr.update(Update::Force); + } + break; + } + case LFUN_BRANCH_ACTIVATE: case LFUN_BRANCH_DEACTIVATE: { BranchList & branchList = params().branchlist(); @@ -1601,6 +1723,41 @@ void Buffer::dispatch(FuncRequest const & func, DispatchResult & dr) break; } + case LFUN_BRANCHES_RENAME: { + if (func.argument().empty()) + break; + + docstring const oldname = from_utf8(func.getArg(0)); + docstring const newname = from_utf8(func.getArg(1)); + InsetIterator it = inset_iterator_begin(inset()); + InsetIterator const end = inset_iterator_end(inset()); + bool success = false; + for (; it != end; ++it) { + if (it->lyxCode() == BRANCH_CODE) { + InsetBranch & ins = static_cast(*it); + if (ins.branch() == oldname) { + undo().recordUndo(it); + ins.rename(newname); + success = true; + continue; + } + } + if (it->lyxCode() == INCLUDE_CODE) { + // get buffer of external file + InsetInclude const & ins = + static_cast(*it); + Buffer * child = ins.getChildBuffer(); + if (!child) + continue; + child->dispatch(func, dr); + } + } + + if (success) + dr.update(Update::Force); + break; + } + case LFUN_BUFFER_PRINT: { // we'll assume there's a problem until we succeed dr.setError(true); @@ -2248,6 +2405,35 @@ void Buffer::updateMacros() const } +void Buffer::getUsedBranches(std::list & result, bool const from_master) const +{ + InsetIterator it = inset_iterator_begin(inset()); + InsetIterator const end = inset_iterator_end(inset()); + for (; it != end; ++it) { + if (it->lyxCode() == BRANCH_CODE) { + InsetBranch & br = static_cast(*it); + docstring const name = br.branch(); + if (!from_master && !params().branchlist().find(name)) + result.push_back(name); + else if (from_master && !masterBuffer()->params().branchlist().find(name)) + result.push_back(name); + continue; + } + if (it->lyxCode() == INCLUDE_CODE) { + // get buffer of external file + InsetInclude const & ins = + static_cast(*it); + Buffer * child = ins.getChildBuffer(); + if (!child) + continue; + child->getUsedBranches(result, true); + } + } + // remove duplicates + result.unique(); +} + + void Buffer::updateMacroInstances() const { LYXERR(Debug::MACROS, "updateMacroInstances for " @@ -2416,9 +2602,9 @@ void Buffer::getSourceCode(odocstream & os, pit_type par_begin, // No side effect of file copying and image conversion runparams.dryrun = true; - d->texrow.reset(); if (full_source) { os << "% " << _("Preview source code") << "\n\n"; + d->texrow.reset(); d->texrow.newline(); d->texrow.newline(); if (isDocBook()) @@ -2440,14 +2626,16 @@ void Buffer::getSourceCode(odocstream & os, pit_type par_begin, convert(par_end - 1)) << "\n\n"; } - d->texrow.newline(); - d->texrow.newline(); + TexRow texrow; + texrow.reset(); + texrow.newline(); + texrow.newline(); // output paragraphs if (isDocBook()) docbookParagraphs(paragraphs(), *this, os, runparams); else // latex or literate - latexParagraphs(*this, text(), os, d->texrow, runparams); + latexParagraphs(*this, text(), os, texrow, runparams); } } @@ -2478,10 +2666,10 @@ void Buffer::structureChanged() const } -void Buffer::errors(string const & err) const +void Buffer::errors(string const & err, bool from_master) const { if (gui_) - gui_->errors(err); + gui_->errors(err, from_master); } @@ -2607,7 +2795,16 @@ int AutoSaveBuffer::generateChild() FileName Buffer::getAutosaveFilename() const { - string const fpath = isUnnamed() ? lyxrc.document_path : filePath(); + // if the document is unnamed try to save in the backup dir, else + // in the default document path, and as a last try in the filePath, + // which will most often be the temporary directory + string fpath; + if (isUnnamed()) + fpath = lyxrc.backupdir_path.empty() ? lyxrc.document_path + : lyxrc.backupdir_path; + if (!isUnnamed() || fpath.empty() || !FileName(fpath).exists()) + fpath = filePath(); + string const fname = "#" + d->filename.onlyFileName() + "#"; return makeAbsPath(fname, fpath); } @@ -2621,6 +2818,14 @@ void Buffer::removeAutosaveFile() const } +void Buffer::moveAutosaveFile(support::FileName const & oldauto) const +{ + FileName const newauto = getAutosaveFilename(); + if (!(oldauto == newauto || oldauto.moveTo(newauto))) + LYXERR0("Unable to remove autosave file `" << oldauto << "'!"); +} + + // Perfect target for a thread... void Buffer::autoSave() const { @@ -2642,15 +2847,14 @@ void Buffer::autoSave() const string Buffer::bufferFormat() const { - if (isDocBook()) - return "docbook"; - if (isLiterate()) - return "literate"; - if (params().useXetex) - return "xetex"; - if (params().encoding().package() == Encoding::japanese) - return "platex"; - return "latex"; + string format = params().documentClass().outputFormat(); + if (format == "latex") { + if (params().useXetex) + return "xetex"; + if (params().encoding().package() == Encoding::japanese) + return "platex"; + } + return format; } @@ -2721,6 +2925,8 @@ bool Buffer::doExport(string const & format, bool put_in_tempdir, if (backend_format == "text") writePlaintextFile(*this, FileName(filename), runparams); // no backend + else if (backend_format == "xhtml") + makeLyXHTMLFile(FileName(filename), runparams); else if (backend_format == "lyx") writeFile(FileName(filename)); // Docbook backend @@ -2753,8 +2959,14 @@ bool Buffer::doExport(string const & format, bool put_in_tempdir, tmp_result_file, FileName(absFileName()), backend_format, format, error_list); // Emit the signal to show the error list. - if (format != backend_format) + if (format != backend_format) { errors(error_type); + // also to the children, in case of master-buffer-view + std::vector clist = getChildren(); + for (vector::const_iterator cit = clist.begin(); + cit != clist.end(); ++cit) + (*cit)->errors(error_type, true); + } if (!success) return false; @@ -2763,7 +2975,7 @@ bool Buffer::doExport(string const & format, bool put_in_tempdir, return true; } - result_file = changeExtension(absFileName(), ext); + result_file = changeExtension(exportFileName().absFilename(), ext); // We need to copy referenced files (e. g. included graphics // if format == "dvi") to the result dir. vector const files = @@ -2850,6 +3062,7 @@ vector Buffer::backends() const v.push_back("pdflatex"); } v.push_back("text"); + v.push_back("xhtml"); v.push_back("lyx"); return v; } @@ -2999,7 +3212,7 @@ void Buffer::updateLabels(UpdateScope scope) const // Do this here in case the master has no gui associated with it. Then, // the TocModel is not updated and TocModel::toc_ is invalid (bug 5699). if (!master->gui_) - structureChanged(); + structureChanged(); // was buf referenced from the master (i.e. not in bufToUpdate anymore)? if (bufToUpdate.find(this) == bufToUpdate.end()) @@ -3124,9 +3337,10 @@ static void setLabel(Buffer const & buf, ParIterator & it) // Compute the item depth of the paragraph par.itemdepth = getItemDepth(it); - if (layout.margintype == MARGIN_MANUAL) { + if (layout.margintype == MARGIN_MANUAL + || layout.latextype == LATEX_BIB_ENVIRONMENT) { if (par.params().labelWidthString().empty()) - par.params().labelWidthString(par.translateIfPossible(layout.labelstring(), bp)); + par.params().labelWidthString(par.expandLabel(layout, bp)); } else { par.params().labelWidthString(docstring()); } @@ -3169,9 +3383,7 @@ static void setLabel(Buffer const & buf, ParIterator & it) } case LABEL_ENUMERATE: { - // FIXME: Yes I know this is a really, really! bad solution - // (Lgb) - docstring enumcounter = from_ascii("enum"); + docstring enumcounter = layout.counter.empty() ? from_ascii("enum") : layout.counter; switch (par.itemdepth) { case 2: @@ -3192,31 +3404,10 @@ static void setLabel(Buffer const & buf, ParIterator & it) // Maybe we have to reset the enumeration counter. if (needEnumCounterReset(it)) counters.reset(enumcounter); - counters.step(enumcounter); - string format; - - switch (par.itemdepth) { - case 0: - format = N_("\\arabic{enumi}."); - break; - case 1: - format = N_("(\\alph{enumii})"); - break; - case 2: - format = N_("\\roman{enumiii}."); - break; - case 3: - format = N_("\\Alph{enumiv}."); - break; - default: - // not a valid enumdepth... - break; - } - - par.params().labelString(counters.counterLabel( - par.translateIfPossible(from_ascii(format), bp))); + string const & lang = par.getParLanguage(bp)->code(); + par.params().labelString(counters.theCounter(enumcounter, lang)); break; } @@ -3229,10 +3420,11 @@ static void setLabel(Buffer const & buf, ParIterator & it) else { docstring name = buf.B_(textclass.floats().getType(type).name()); if (counters.hasCounter(from_utf8(type))) { + string const & lang = par.getParLanguage(bp)->code(); counters.step(from_utf8(type)); full_label = bformat(from_ascii("%1$s %2$s:"), name, - counters.theCounter(from_utf8(type))); + counters.theCounter(from_utf8(type), lang)); } else full_label = bformat(from_ascii("%1$s #:"), name); } @@ -3249,8 +3441,7 @@ static void setLabel(Buffer const & buf, ParIterator & it) case LABEL_CENTERED_TOP_ENVIRONMENT: case LABEL_STATIC: case LABEL_BIBLIO: - par.params().labelString( - par.translateIfPossible(layout.labelstring(), bp)); + par.params().labelString(par.expandLabel(layout, bp)); break; } } @@ -3287,77 +3478,27 @@ void Buffer::updateLabels(ParIterator & parit) const } -bool Buffer::nextWord(DocIterator & from, DocIterator & to, - docstring & word) const -{ - bool inword = false; - bool ignoreword = false; - string lang_code; - // Go backward a bit if needed in order to return the word currently - // pointed by 'from'. - while (from && from.pos() && isLetter(from)) - from.backwardPos(); - // OK, we start from here. - to = from; - while (to.depth()) { - if (isLetter(to)) { - if (!inword) { - inword = true; - ignoreword = false; - from = to; - word.clear(); - lang_code = to.paragraph().getFontSettings(params(), - to.pos()).language()->code(); - } - // Insets like optional hyphens and ligature - // break are part of a word. - if (!to.paragraph().isInset(to.pos())) { - char_type const c = to.paragraph().getChar(to.pos()); - word += c; - if (isDigit(c)) - ignoreword = true; - } - } else { // !isLetter(cur) - if (inword && !word.empty() && !ignoreword) - return true; - inword = false; - } - to.forwardPos(); - } - from = to; - word.clear(); - return false; -} - - int Buffer::spellCheck(DocIterator & from, DocIterator & to, WordLangTuple & word_lang, docstring_list & suggestions) const { int progress = 0; - SpellChecker::Result res = SpellChecker::OK; - SpellChecker * speller = theSpellChecker(); + WordLangTuple wl; suggestions.clear(); - docstring word; - while (nextWord(from, to, word)) { - ++progress; - string lang_code = lyxrc.spellchecker_use_alt_lang - ? lyxrc.spellchecker_alt_lang - : from.paragraph().getFontSettings(params(), from.pos()).language()->code(); - WordLangTuple wl(word, lang_code); - res = speller->check(wl); - // ... just bail out if the spellchecker reports an error. - if (!speller->error().empty()) { - throw ExceptionMessage(WarningException, - _("The spellchecker has failed."), speller->error()); - } - if (res != SpellChecker::OK && res != SpellChecker::IGNORED_WORD) { + word_lang = WordLangTuple(); + // OK, we start from here. + DocIterator const end = doc_iterator_end(this); + for (; from != end; from.forwardPos()) { + // We are only interested in text so remove the math CursorSlice. + while (from.inMathed()) + from.forwardInset(); + to = from; + if (from.paragraph().spellCheck(from.pos(), to.pos(), wl, suggestions)) { word_lang = wl; break; } from = to; + ++progress; } - while (!(word = speller->nextMiss()).empty()) - suggestions.push_back(word); return progress; }