X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Foutput_latex.cpp;h=cdd42aaf4325222dffc0f18efff4d343bca6e20c;hb=e45427de389bc188f02ebe0de2c052740dcde09c;hp=cc6373ff319ed1afaecd7c07250fda7c5d01c436;hpb=9bfc1c9d46e1865b24c51117b5a05190260d1328;p=lyx.git diff --git a/src/output_latex.cpp b/src/output_latex.cpp index cc6373ff31..cdd42aaf43 100644 --- a/src/output_latex.cpp +++ b/src/output_latex.cpp @@ -3,7 +3,7 @@ * This file is part of LyX, the document processor. * Licence details can be found in the file COPYING. * - * \author Lars Gullik Bjønnes + * \author Lars Gullik Bjønnes * * Full author contact details are available in file CREDITS. */ @@ -21,7 +21,6 @@ #include "LyXRC.h" #include "OutputParams.h" #include "Paragraph.h" -#include "paragraph_funcs.h" #include "ParagraphParameters.h" #include "TextClass.h" #include "TexRow.h" @@ -52,6 +51,7 @@ enum OpenEncoding { static int open_encoding_ = none; static int cjk_inherited_ = 0; +Language const * prev_env_language_ = 0; ParagraphList::const_iterator @@ -61,14 +61,6 @@ TeXEnvironment(Buffer const & buf, odocstream & os, TexRow & texrow, OutputParams const & runparams); -ParagraphList::const_iterator -TeXOnePar(Buffer const & buf, - Text const & text, - ParagraphList::const_iterator pit, - odocstream & os, TexRow & texrow, - OutputParams const & runparams, - string const & everypar = string()); - ParagraphList::const_iterator TeXDeeper(Buffer const & buf, @@ -82,9 +74,14 @@ TeXDeeper(Buffer const & buf, ParagraphList const & paragraphs = text.paragraphs(); + bool const force_plain_layout = text.inset().forcePlainLayout(); while (par != paragraphs.end() && - par->params().depth() == pit->params().depth()) { - if (par->layout().isEnvironment()) { + par->params().depth() == pit->params().depth()) { + // FIXME This test should not be necessary. + // We should perhaps issue an error if it is. + Layout const & style = force_plain_layout + ? buf.params().documentClass().plainLayout() : par->layout(); + if (style.isEnvironment()) { par = TeXEnvironment(buf, text, par, os, texrow, runparams); } else { @@ -109,16 +106,28 @@ TeXEnvironment(Buffer const & buf, BufferParams const & bparams = buf.params(); - Layout const & style = pit->forcePlainLayout() ? + // FIXME This test should not be necessary. + // We should perhaps issue an error if it is. + Layout const & style = text.inset().forcePlainLayout() ? bparams.documentClass().plainLayout() : pit->layout(); ParagraphList const & paragraphs = text.paragraphs(); + ParagraphList::const_iterator const priorpit = + pit == paragraphs.begin() ? pit : boost::prior(pit); + + bool const use_prev_env_language = prev_env_language_ != 0 + && priorpit->layout().isEnvironment() + && (priorpit->getDepth() > pit->getDepth() + || (priorpit->getDepth() == pit->getDepth() + && priorpit->layout() != pit->layout())); + Encoding const * const prev_encoding = runparams.encoding; Language const * const par_language = pit->getParLanguage(bparams); Language const * const doc_language = bparams.language; Language const * const prev_par_language = (pit != paragraphs.begin()) - ? boost::prior(pit)->getParLanguage(bparams) + ? (use_prev_env_language ? prev_env_language_ + : priorpit->getParLanguage(bparams)) : doc_language; if (par_language->babel() != prev_par_language->babel()) { @@ -171,8 +180,12 @@ TeXEnvironment(Buffer const & buf, << pit->params().labelWidthString() << "}\n"; } else if (style.labeltype == LABEL_BIBLIO) { - // ale970405 - os << '{' << bibitemWidest(buf) << "}\n"; + if (pit->params().labelWidthString().empty()) + os << '{' << bibitemWidest(buf, runparams) << "}\n"; + else + os << '{' + << pit->params().labelWidthString() + << "}\n"; } else os << from_ascii(style.latexparam()) << '\n'; texrow.newline(); @@ -182,8 +195,9 @@ TeXEnvironment(Buffer const & buf, bool cjk_nested = false; if (par_language->encoding()->package() == Encoding::CJK && open_encoding_ != CJK && pit->isMultiLingual(bparams)) { - os << "\\begin{CJK}{" << from_ascii(par_language->encoding()->latexName()) - << "}{" << from_ascii(bparams.fontsCJK) << "}%\n"; + if (prev_par_language->encoding()->package() == Encoding::CJK) + os << "\\begin{CJK}{" << from_ascii(par_language->encoding()->latexName()) + << "}{" << from_ascii(bparams.fontsCJK) << "}%\n"; open_encoding_ = CJK; cjk_nested = true; texrow.newline(); @@ -237,11 +251,23 @@ TeXEnvironment(Buffer const & buf, if (style.isEnvironment()) { os << "\\end{" << from_ascii(style.latexname()) << "}\n"; texrow.newline(); + prev_env_language_ = par_language; + if (runparams.encoding != prev_encoding) { + runparams.encoding = prev_encoding; + if (!bparams.useXetex) + os << setEncoding(prev_encoding->iconvName()); + } } if (leftindent_open) { os << "\\end{LyXParagraphLeftIndent}\n"; texrow.newline(); + prev_env_language_ = par_language; + if (runparams.encoding != prev_encoding) { + runparams.encoding = prev_encoding; + if (!bparams.useXetex) + os << setEncoding(prev_encoding->iconvName()); + } } if (par != paragraphs.end()) @@ -271,32 +297,40 @@ int latexOptArgInsets(Paragraph const & par, odocstream & os, return lines; } - -namespace { - -ParagraphList::const_iterator -TeXOnePar(Buffer const & buf, +// FIXME: this should be anonymous +ParagraphList::const_iterator TeXOnePar(Buffer const & buf, Text const & text, ParagraphList::const_iterator const pit, odocstream & os, TexRow & texrow, OutputParams const & runparams_in, - string const & everypar) + string const & everypar, + int start_pos, int end_pos) { LYXERR(Debug::LATEX, "TeXOnePar... " << &*pit << " '" << everypar << "'"); BufferParams const & bparams = buf.params(); ParagraphList const & paragraphs = text.paragraphs(); - ParagraphList::const_iterator priorpit = pit; - if (priorpit != paragraphs.begin()) - --priorpit; - ParagraphList::const_iterator nextpit = pit; - if (nextpit != paragraphs.end()) - ++nextpit; + ParagraphList::const_iterator const priorpit = + pit == paragraphs.begin() ? pit : boost::prior(pit); + ParagraphList::const_iterator const nextpit = + pit == paragraphs.end() ? pit : boost::next(pit); + + OutputParams runparams = runparams_in; + runparams.isLastPar = nextpit == paragraphs.end(); + + bool const maintext = text.isMainText(); + // we are at the beginning of an inset and CJK is already open; + // we count inheritation levels to get the inset nesting right. + if (pit == paragraphs.begin() && !maintext + && (cjk_inherited_ > 0 || open_encoding_ == CJK)) { + cjk_inherited_ += 1; + open_encoding_ = none; + } - if (runparams_in.verbatim) { + if (runparams.verbatim) { int const dist = distance(paragraphs.begin(), pit); - Font const outerfont = outerFont(dist, paragraphs); + Font const outerfont = text.outerFont(dist); // No newline if only one paragraph in this lyxtext if (dist > 0) { @@ -305,40 +339,40 @@ TeXOnePar(Buffer const & buf, } /*bool need_par = */ pit->latex(bparams, outerfont, - os, texrow, runparams_in); + os, texrow, runparams, start_pos, end_pos); return nextpit; } - Layout const style = pit->forcePlainLayout() ? + // FIXME This check should not really be needed. + // Perhaps we should issue an error if it is. + Layout const style = text.inset().forcePlainLayout() ? bparams.documentClass().plainLayout() : pit->layout(); - OutputParams runparams = runparams_in; - runparams.moving_arg |= style.needprotect; - - bool const maintext = text.isMainText(buf); - // we are at the beginning of an inset and CJK is already open; - // we count inheritation levels to get the inset nesting right. - if (pit == paragraphs.begin() && !maintext - && (cjk_inherited_ > 0 || open_encoding_ == CJK)) { - cjk_inherited_ += 1; - open_encoding_ = none; - } - // This paragraph's language Language const * const par_language = pit->getParLanguage(bparams); // The document's language Language const * const doc_language = bparams.language; - // The language that was in effect when the environment this paragraph is + // The language that was in effect when the environment this paragraph is // inside of was opened - Language const * const outer_language = + Language const * const outer_language = (runparams.local_font != 0) ? runparams.local_font->language() : doc_language; - // The previous language that was in effect is either the language of - // the previous paragraph, if there is one, or else the outer language - // if there is no previous paragraph + + // The previous language that was in effect is the language of the + // previous paragraph, unless the previous paragraph is inside an + // environment with nesting depth greater than (or equal to, but with + // a different layout) the current one. If there is no previous + // paragraph, the previous language is the outer language. + bool const use_prev_env_language = prev_env_language_ != 0 + && priorpit->layout().isEnvironment() + && (priorpit->getDepth() > pit->getDepth() + || (priorpit->getDepth() == pit->getDepth() + && priorpit->layout() != pit->layout())); Language const * const prev_language = - (pit != paragraphs.begin()) ? - priorpit->getParLanguage(bparams) : outer_language; + (pit != paragraphs.begin()) + ? (use_prev_env_language ? prev_env_language_ + : priorpit->getParLanguage(bparams)) + : outer_language; if (par_language->babel() != prev_language->babel() // check if we already put language command in TeXEnvironment() @@ -360,7 +394,7 @@ TeXOnePar(Buffer const & buf, texrow.newline(); } - // We need to open a new language if we couldn't close the previous + // We need to open a new language if we couldn't close the previous // one (because there's no language_command_end); and even if we closed // the previous one, if the current language is different than the // outer_language (which is currently in effect once the previous one @@ -379,11 +413,11 @@ TeXOnePar(Buffer const & buf, // are we in an inset? runparams.local_font != 0 && // is the inset within an \L or \R? - // + // // FIXME: currently, we don't check this; this means that - // we'll have unnnecessary \L and \R commands, but that + // we'll have unnnecessary \L and \R commands, but that // doesn't seem to hurt (though latex will complain) - // + // // is this paragraph in the opposite direction? runparams.local_font->isRightToLeft() != par_language->rightToLeft() @@ -426,7 +460,9 @@ TeXOnePar(Buffer const & buf, // Look ahead for future encoding changes. // We try to output them at the beginning of the paragraph, // since the \inputencoding command is not allowed e.g. in - // sections. + // sections. For this reason we only set runparams.moving_arg + // after checking for the encoding change, otherwise the + // change would be always avoided by switchEncoding(). for (pos_type i = 0; i < pit->size(); ++i) { char_type const c = pit->getChar(i); Encoding const * const encoding = @@ -443,11 +479,8 @@ TeXOnePar(Buffer const & buf, // With CJK, only add switch if we have CJK content at the beginning // of the paragraph if (encoding->package() != Encoding::CJK || i == 0) { - OutputParams tmp_rp = runparams; - runparams.moving_arg = false; pair enc_switch = switchEncoding(os, bparams, runparams, *encoding); - runparams = tmp_rp; // the following is necessary after a CJK environment in a multilingual // context (nesting issue). if (par_language->encoding()->package() == Encoding::CJK && @@ -480,6 +513,9 @@ TeXOnePar(Buffer const & buf, } } + runparams.moving_arg |= style.needprotect; + Encoding const * const prev_encoding = runparams.encoding; + bool const useSetSpace = bparams.documentClass().provides("SetSpace"); if (pit->allowParagraphCustomization()) { if (pit->params().startOfAppendix()) { @@ -529,13 +565,12 @@ TeXOnePar(Buffer const & buf, break; } - Font const outerfont = outerFont(distance(paragraphs.begin(), pit), - paragraphs); + Font const outerfont = text.outerFont(distance(paragraphs.begin(), pit)); // FIXME UNICODE os << from_utf8(everypar); bool need_par = pit->latex(bparams, outerfont, - os, texrow, runparams); + os, texrow, runparams, start_pos, end_pos); // Make sure that \\par is done with the font of the last // character if this has another size as the default. @@ -551,7 +586,7 @@ TeXOnePar(Buffer const & buf, ? pit->getLayoutFont(bparams, outerfont) : pit->getFont(bparams, pit->size() - 1, outerfont); - bool is_command = style.isCommand(); + bool const is_command = style.isCommand(); if (style.resfont.size() != font.fontInfo().size() && nextpit != paragraphs.end() @@ -561,8 +596,14 @@ TeXOnePar(Buffer const & buf, os << "\\" << from_ascii(font.latexSize()) << " \\par}"; } else if (need_par) { os << "\\par}"; - } else if (is_command) + } else if (is_command) { os << '}'; + if (runparams.encoding != prev_encoding) { + runparams.encoding = prev_encoding; + if (!bparams.useXetex) + os << setEncoding(prev_encoding->iconvName()); + } + } bool pending_newline = false; switch (style.latextype) { @@ -575,14 +616,13 @@ TeXOnePar(Buffer const & buf, case LATEX_ENVIRONMENT: { // if its the last paragraph of the current environment // skip it otherwise fall through - ParagraphList::const_iterator next = nextpit; - - if (next != paragraphs.end() && (next->layout() != pit->layout() - || next->params().depth() != pit->params().depth())) + if (nextpit != paragraphs.end() && + (nextpit->layout() != pit->layout() + || nextpit->params().depth() != pit->params().depth())) break; } - // fall through possible + // fall through possible default: // we don't need it for the last paragraph!!! if (nextpit != paragraphs.end()) @@ -605,7 +645,7 @@ TeXOnePar(Buffer const & buf, // Closing the language is needed for the last paragraph; it is also // needed if we're within an \L or \R that we may have opened above (not // necessarily in this paragraph) and are about to close. - bool closing_rtl_ltr_environment = + bool closing_rtl_ltr_environment = // not for ArabTeX (par_language->lang() != "arabic_arabtex" && outer_language->lang() != "arabic_arabtex") && @@ -614,10 +654,10 @@ TeXOnePar(Buffer const & buf, runparams.local_font->isRightToLeft() != par_language->rightToLeft() && // are we about to close the language? ((nextpit != paragraphs.end() && - par_language->babel() != - (nextpit->getParLanguage(bparams))->babel()) || - (nextpit == paragraphs.end() && - par_language->babel() != outer_language->babel())); + par_language->babel() != + (nextpit->getParLanguage(bparams))->babel()) || + (nextpit == paragraphs.end() && + par_language->babel() != outer_language->babel())); if (closing_rtl_ltr_environment || (nextpit == paragraphs.end() && par_language->babel() != outer_language->babel())) { @@ -632,11 +672,18 @@ TeXOnePar(Buffer const & buf, // when the paragraph uses CJK, the language has to be closed earlier if (font.language()->encoding()->package() != Encoding::CJK) { if (lyxrc.language_command_end.empty()) { - if (!prev_language->babel().empty()) { + // If this is a child, we should restore the + // master language after the last paragraph. + Language const * const current_language = + (nextpit == paragraphs.end() + && runparams.master_language) + ? runparams.master_language + : outer_language; + if (!current_language->babel().empty()) { os << from_ascii(subst( lyxrc.language_command_begin, "$$lang", - prev_language->babel())); + current_language->babel())); pending_newline = true; } } else if (!par_language->babel().empty()) { @@ -660,9 +707,9 @@ TeXOnePar(Buffer const & buf, // also if the next paragraph is a multilingual environment (because of nesting) if (nextpit != paragraphs.end() && open_encoding_ == CJK && (nextpit->getParLanguage(bparams)->encoding()->package() != Encoding::CJK || - nextpit->layout().isEnvironment() && nextpit->isMultiLingual(bparams)) - // in environments, CJK has to be closed later (nesting!) - && !style.isEnvironment()) { + (nextpit->layout().isEnvironment() && nextpit->isMultiLingual(bparams))) + // inbetween environments, CJK has to be closed later (nesting!) + && (!style.isEnvironment() || !nextpit->layout().isEnvironment())) { os << "\\end{CJK}\n"; open_encoding_ = none; } @@ -672,6 +719,9 @@ TeXOnePar(Buffer const & buf, if (nextpit == paragraphs.end() && !style.isEnvironment()) { switch (open_encoding_) { case CJK: { + // do nothing at the end of child documents + if (maintext && buf.masterBuffer() != &buf) + break; // end of main text if (maintext) { os << '\n'; @@ -699,9 +749,11 @@ TeXOnePar(Buffer const & buf, // If this is the last paragraph, and a local_font was set upon entering // the inset, and we're using "auto" or "default" encoding, the encoding // should be set back to that local_font's encoding. + // However, do not change the encoding when XeTeX is used. if (nextpit == paragraphs.end() && runparams_in.local_font != 0 && runparams_in.encoding != runparams_in.local_font->language()->encoding() - && (bparams.inputenc == "auto" || bparams.inputenc == "default")) { + && (bparams.inputenc == "auto" || bparams.inputenc == "default") + && (!bparams.useXetex)) { runparams_in.encoding = runparams_in.local_font->language()->encoding(); os << setEncoding(runparams_in.encoding->iconvName()); } @@ -710,13 +762,22 @@ TeXOnePar(Buffer const & buf, runparams_in.encoding = runparams.encoding; - // we don't need it for the last paragraph!!! - // Note from JMarc: we will re-add a \n explicitely in + // we don't need a newline for the last paragraph!!! + // Note from JMarc: we will re-add a \n explicitly in // TeXEnvironment, because it is needed in this case if (nextpit != paragraphs.end()) { Layout const & next_layout = nextpit->layout(); - // no blank lines before environments! - if (!next_layout.isEnvironment() || style == next_layout) { + if (style == next_layout + // no blank lines before environments! + || !next_layout.isEnvironment() + // unless there's a depth change + // FIXME What we really want to do here is put every \begin and \end + // tag on a new line (which was not the case with nested environments). + // But in the present state of play, we don't have access to the + // information whether the current TeX row is empty or not. + // For some ideas about how to fix this, see this thread: + // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg145787.html + || nextpit->params().depth() != pit->params().depth()) { os << '\n'; texrow.newline(); } @@ -728,8 +789,6 @@ TeXOnePar(Buffer const & buf, return nextpit; } -} // anon namespace - // LaTeX all paragraphs void latexParagraphs(Buffer const & buf, @@ -758,17 +817,20 @@ void latexParagraphs(Buffer const & buf, const_cast(runparams).par_end = 0; } - bool const maintext = text.isMainText(buf); + bool const maintext = text.isMainText(); + bool const is_child = buf.masterBuffer() != &buf; // Open a CJK environment at the beginning of the main buffer // if the document's language is a CJK language - if (maintext && bparams.encoding().package() == Encoding::CJK) { + // (but not in child documents) + if (maintext && !is_child + && bparams.encoding().package() == Encoding::CJK) { os << "\\begin{CJK}{" << from_ascii(bparams.encoding().latexName()) << "}{" << from_ascii(bparams.fontsCJK) << "}%\n"; texrow.newline(); open_encoding_ = CJK; } - // if "auto begin" is switched off, explicitely switch the + // if "auto begin" is switched off, explicitly switch the // language on at start if (maintext && !lyxrc.language_auto_begin && !bparams.language->babel().empty()) { @@ -784,9 +846,10 @@ void latexParagraphs(Buffer const & buf, // if only_body while (par != endpar) { lastpar = par; - Layout const & layout = par->forcePlainLayout() ? - tclass.plainLayout() : - par->layout(); + // FIXME This check should not be needed. We should + // perhaps issue an error if it is. + Layout const & layout = text.inset().forcePlainLayout() ? + tclass.plainLayout() : par->layout(); if (layout.intitle) { if (already_title) { @@ -841,7 +904,7 @@ void latexParagraphs(Buffer const & buf, texrow.newline(); } - // if "auto end" is switched off, explicitely close the language at the end + // if "auto end" is switched off, explicitly close the language at the end // but only if the last par is in a babel language if (maintext && !lyxrc.language_auto_end && !bparams.language->babel().empty() && lastpar->getParLanguage(bparams)->encoding()->package() != Encoding::CJK) { @@ -854,7 +917,7 @@ void latexParagraphs(Buffer const & buf, // If the last paragraph is an environment, we'll have to close // CJK at the very end to do proper nesting. - if (maintext && open_encoding_ == CJK) { + if (maintext && !is_child && open_encoding_ == CJK) { os << "\\end{CJK}\n"; texrow.newline(); open_encoding_ = none; @@ -873,7 +936,7 @@ pair switchEncoding(odocstream & os, BufferParams const & bparams, OutputParams const & runparams, Encoding const & newEnc, bool force) { - Encoding const oldEnc = *runparams.encoding; + Encoding const & oldEnc = *runparams.encoding; bool moving_arg = runparams.moving_arg; if (!force && ((bparams.inputenc != "auto" && bparams.inputenc != "default") || moving_arg)) @@ -919,7 +982,7 @@ pair switchEncoding(odocstream & os, BufferParams const & bparams, count += 7; } if (runparams.local_font != 0 - && oldEnc.package() == Encoding::CJK) { + && oldEnc.package() == Encoding::CJK) { // within insets, \inputenc switches need // to be embraced within \bgroup...\egroup; // else CJK fails. @@ -935,12 +998,12 @@ pair switchEncoding(odocstream & os, BufferParams const & bparams, } case Encoding::CJK: { int count = inputenc_arg.length(); - if (oldEnc.package() == Encoding::CJK && + if (oldEnc.package() == Encoding::CJK && open_encoding_ == CJK) { os << "\\end{CJK}"; count += 9; } - if (oldEnc.package() == Encoding::inputenc && + if (oldEnc.package() == Encoding::inputenc && open_encoding_ == inputenc) { os << "\\egroup"; count += 7;