X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Foutput_latex.cpp;h=47ae3f8be74a2dd9fcf3925bac50b581cbd7460e;hb=8c6ac457ecc69f57ab54cd8c9b8b7893607c65d6;hp=55cec5bbb761c8dc15699c4151d010c7885df145;hpb=fc6ce7cd08562fd7bab4427880b46390bb7d2f07;p=lyx.git diff --git a/src/output_latex.cpp b/src/output_latex.cpp index 55cec5bbb7..47ae3f8be7 100644 --- a/src/output_latex.cpp +++ b/src/output_latex.cpp @@ -14,14 +14,17 @@ #include "Buffer.h" #include "BufferParams.h" -#include "debug.h" +#include "support/debug.h" #include "Encoding.h" +#include "InsetList.h" #include "Language.h" +#include "Layout.h" #include "LyXRC.h" #include "OutputParams.h" #include "Paragraph.h" #include "paragraph_funcs.h" #include "ParagraphParameters.h" +#include "TextClass.h" #include "TexRow.h" #include "VSpace.h" @@ -30,6 +33,7 @@ #include "support/lstrings.h" +#include namespace lyx { @@ -37,6 +41,8 @@ using support::subst; using std::endl; using std::string; +using std::pair; +using std::make_pair; namespace { @@ -64,7 +70,7 @@ TeXDeeper(Buffer const & buf, odocstream & os, TexRow & texrow, OutputParams const & runparams) { - LYXERR(Debug::LATEX) << "TeXDeeper... " << &*pit << endl; + LYXERR(Debug::LATEX, "TeXDeeper... " << &*pit); ParagraphList::const_iterator par = pit; while (par != paragraphs.end() && @@ -77,7 +83,7 @@ TeXDeeper(Buffer const & buf, os, texrow, runparams); } } - LYXERR(Debug::LATEX) << "TeXDeeper...done " << endl; + LYXERR(Debug::LATEX, "TeXDeeper...done "); return par; } @@ -90,11 +96,11 @@ TeXEnvironment(Buffer const & buf, odocstream & os, TexRow & texrow, OutputParams const & runparams) { - LYXERR(Debug::LATEX) << "TeXEnvironment... " << &*pit << endl; + LYXERR(Debug::LATEX, "TeXEnvironment... " << &*pit); BufferParams const & bparams = buf.params(); - LyXLayout_ptr const & style = pit->layout(); + LayoutPtr const & style = pit->layout(); Language const * const par_language = pit->getParLanguage(bparams); Language const * const doc_language = bparams.language; @@ -105,22 +111,26 @@ TeXEnvironment(Buffer const & buf, if (par_language->babel() != prev_par_language->babel()) { if (!lyxrc.language_command_end.empty() && - prev_par_language->babel() != doc_language->babel()) { + prev_par_language->babel() != doc_language->babel() && + !prev_par_language->babel().empty()) { os << from_ascii(subst( lyxrc.language_command_end, "$$lang", prev_par_language->babel())) - << '\n'; + // the '%' is necessary to prevent unwanted whitespace + << "%\n"; texrow.newline(); } - if (lyxrc.language_command_end.empty() || - par_language->babel() != doc_language->babel()) { + if ((lyxrc.language_command_end.empty() || + par_language->babel() != doc_language->babel()) && + !par_language->babel().empty()) { os << from_ascii(subst( lyxrc.language_command_begin, "$$lang", par_language->babel())) - << '\n'; + // the '%' is necessary to prevent unwanted whitespace + << "%\n"; texrow.newline(); } } @@ -166,12 +176,12 @@ TeXEnvironment(Buffer const & buf, os << '\n'; texrow.newline(); } else if (par->params().depth() > pit->params().depth()) { - if (par->layout()->isParagraph()) { + if (par->layout()->isParagraph()) { + // Thinko! + // How to handle this? (Lgb) + //&& !suffixIs(os, "\n\n") + //) { - // Thinko! - // How to handle this? (Lgb) - //&& !suffixIs(os, "\n\n") - //) { // There should be at least one '\n' already // but we need there to be two for Standard // paragraphs that are depth-increment'ed to be @@ -204,7 +214,8 @@ TeXEnvironment(Buffer const & buf, } if (par != paragraphs.end()) - LYXERR(Debug::LATEX) << "TeXEnvironment...done " << &*par << endl; + LYXERR(Debug::LATEX, "TeXEnvironment...done " << &*par); + return par; } @@ -216,10 +227,10 @@ int latexOptArgInsets(Buffer const & buf, Paragraph const & par, { int lines = 0; - InsetList::const_iterator it = par.insetlist.begin(); - InsetList::const_iterator end = par.insetlist.end(); + InsetList::const_iterator it = par.insetList().begin(); + InsetList::const_iterator end = par.insetList().end(); for (; it != end && number > 0 ; ++it) { - if (it->inset->lyxCode() == Inset::OPTARG_CODE) { + if (it->inset->lyxCode() == OPTARG_CODE) { InsetOptArg * ins = static_cast(it->inset); lines += ins->latexOptional(buf, os, runparams); @@ -240,29 +251,54 @@ TeXOnePar(Buffer const & buf, OutputParams const & runparams_in, string const & everypar) { - LYXERR(Debug::LATEX) << "TeXOnePar... " << &*pit << " '" - << everypar << "'" << endl; + LYXERR(Debug::LATEX, "TeXOnePar... " << &*pit << " '" + << everypar << "'"); BufferParams const & bparams = buf.params(); - LyXLayout_ptr style; + LayoutPtr style; + + if (runparams_in.verbatim) { + int const dist = std::distance(paragraphs.begin(), pit); + Font const outerfont = outerFont(dist, paragraphs); + + // No newline if only one paragraph in this lyxtext + if (dist > 0) { + os << '\n'; + texrow.newline(); + } + + /*bool need_par = */ pit->latex(buf, bparams, outerfont, + os, texrow, runparams_in); + + return ++pit; + } // In an inset with unlimited length (all in one row), // force layout to default if (!pit->forceDefaultParagraphs()) style = pit->layout(); else - style = bparams.getLyXTextClass().defaultLayout(); + style = bparams.getTextClass().defaultLayout(); OutputParams runparams = runparams_in; runparams.moving_arg |= style->needprotect; + // This paragraph's language Language const * const par_language = pit->getParLanguage(bparams); + // The document's language Language const * const doc_language = bparams.language; - Language const * const prev_par_language = - (pit != paragraphs.begin()) - ? boost::prior(pit)->getParLanguage(bparams) - : doc_language; - - if (par_language->babel() != prev_par_language->babel() + // The language that was in effect when the environment this paragraph is + // inside of was opened + 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 + Language const * const prev_language = + (pit != paragraphs.begin()) ? + boost::prior(pit)->getParLanguage(bparams) : outer_language; + + if (par_language->babel() != prev_language->babel() // check if we already put language command in TeXEnvironment() && !(style->isEnvironment() && (pit == paragraphs.begin() || @@ -271,29 +307,77 @@ TeXOnePar(Buffer const & buf, || boost::prior(pit)->getDepth() < pit->getDepth()))) { if (!lyxrc.language_command_end.empty() && - prev_par_language->babel() != doc_language->babel()) + prev_language->babel() != outer_language->babel() && + !prev_language->babel().empty()) { os << from_ascii(subst(lyxrc.language_command_end, "$$lang", - prev_par_language->babel())) - << '\n'; + prev_language->babel())) + // the '%' is necessary to prevent unwanted whitespace + << "%\n"; texrow.newline(); } - if (lyxrc.language_command_end.empty() || - par_language->babel() != doc_language->babel()) - { + // 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 + // is closed). + if ((lyxrc.language_command_end.empty() || + par_language->babel() != outer_language->babel()) && + !par_language->babel().empty()) { + // If we're inside an inset, and that inset is within an \L or \R + // (or equivalents), then within the inset, too, any opposite + // language paragraph should appear within an \L or \R (in addition + // to, outside of, the normal language switch commands). + // This behavior is not correct for ArabTeX, though. + if ( // not for ArabTeX + (par_language->lang() != "arabic_arabtex" && + outer_language->lang() != "arabic_arabtex") && + // 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 + // doesn't seem to hurt (though latex will complain) + // + // is this paragraph in the opposite direction? + runparams.local_font->isRightToLeft() != + par_language->rightToLeft() + ) { + // FIXME: I don't have a working copy of the Arabi package, so + // I'm not sure if the farsi and arabic_arabi stuff is correct + // or not... + if (par_language->lang() == "farsi") + os << "\\textFR{"; + else if (outer_language->lang() == "farsi") + os << "\\textLR{"; + else if (par_language->lang() == "arabic_arabi") + os << "\\textAR{"; + else if (outer_language->lang() == "arabic_arabi") + os << "\\textLR{"; + // remaining RTL languages currently is hebrew + else if (par_language->rightToLeft()) + os << "\\R{"; + else + os << "\\L{"; + } os << from_ascii(subst( lyxrc.language_command_begin, "$$lang", par_language->babel())) - << '\n'; + // the '%' is necessary to prevent unwanted whitespace + << "%\n"; texrow.newline(); } } - // Switch file encoding if necessary - if (bparams.inputenc == "auto") { + // Switch file encoding if necessary; no need to do this for "default" + // encoding, since this only affects the position of the outputted + // \inputencoding command; the encoding switch will occur when necessary + if (bparams.inputenc == "auto" && + runparams.encoding->package() == Encoding::inputenc) { // 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 @@ -309,11 +393,15 @@ TeXOnePar(Buffer const & buf, // encoding to that required by the language of c. Encoding const * const encoding = pit->getFontSettings(bparams, i).language()->encoding(); - if (switchEncoding(os, bparams, false, - *(runparams.encoding), *encoding) > 0) { + pair enc_switch = switchEncoding(os, bparams, false, + *(runparams.encoding), *encoding); + if (encoding->package() == Encoding::inputenc && enc_switch.first) { runparams.encoding = encoding; - os << '\n'; - texrow.newline(); + if (enc_switch.second > 0) { + // the '%' is necessary to prevent unwanted whitespace + os << "%\n"; + texrow.newline(); + } } break; } @@ -375,7 +463,7 @@ TeXOnePar(Buffer const & buf, // FIXME UNICODE os << from_utf8(everypar); - bool need_par = pit->simpleTeXOnePar(buf, bparams, outerfont, + bool need_par = pit->latex(buf, bparams, outerfont, os, texrow, runparams); // Make sure that \\par is done with the font of the last @@ -395,7 +483,7 @@ TeXOnePar(Buffer const & buf, bool is_command = style->isCommand(); - if (style->resfont.size() != font.size() + if (style->resfont.size() != font.fontInfo().size() && boost::next(pit) != paragraphs.end() && !is_command) { if (!need_par) @@ -446,8 +534,25 @@ TeXOnePar(Buffer const & buf, } } - if (boost::next(pit) == paragraphs.end() - && par_language->babel() != doc_language->babel()) { + // 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 = + // not for ArabTeX + (par_language->lang() != "arabic_arabtex" && + outer_language->lang() != "arabic_arabtex") && + // have we opened and \L or \R environment? + runparams.local_font != 0 && + runparams.local_font->isRightToLeft() != par_language->rightToLeft() && + // are we about to close the language? + ((boost::next(pit) != paragraphs.end() && + par_language->babel() != + (boost::next(pit)->getParLanguage(bparams))->babel()) || + (boost::next(pit) == paragraphs.end() && + par_language->babel() != outer_language->babel())); + + if (closing_rtl_ltr_environment || (boost::next(pit) == paragraphs.end() + && par_language->babel() != outer_language->babel())) { // Since \selectlanguage write the language to the aux file, // we need to reset the language at the end of footnote or // float. @@ -456,24 +561,47 @@ TeXOnePar(Buffer const & buf, os << '\n'; texrow.newline(); } - if (lyxrc.language_command_end.empty()) - os << from_ascii(subst( - lyxrc.language_command_begin, - "$$lang", - doc_language->babel())); - else + if (lyxrc.language_command_end.empty()) { + if (!prev_language->babel().empty()) { + os << from_ascii(subst( + lyxrc.language_command_begin, + "$$lang", + prev_language->babel())); + pending_newline = true; + } + } else if (!par_language->babel().empty()) { os << from_ascii(subst( lyxrc.language_command_end, "$$lang", par_language->babel())); - pending_newline = true; + pending_newline = true; + } } + if (closing_rtl_ltr_environment) + os << "}"; if (pending_newline) { os << '\n'; texrow.newline(); } - runparams_in.encoding = runparams.encoding; + + // If this is the last paragraph, and a local_font was set upon entering + // the inset, the encoding should be set back to that local_font's + // encoding. We don't use switchEncoding(), because no explicit encoding + // switch command is needed, since latex will automatically revert to it + // when this inset closes. + // This switch is only necessary if we're using "auto" or "default" + // encoding. + if (boost::next(pit) == paragraphs.end() && runparams_in.local_font != 0) { + runparams_in.encoding = runparams_in.local_font->language()->encoding(); + if (bparams.inputenc == "auto" || bparams.inputenc == "default") + os << setEncoding(runparams_in.encoding->iconvName()); + + } + // Otherwise, the current encoding should be set for the next paragraph. + else + 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 @@ -484,7 +612,7 @@ TeXOnePar(Buffer const & buf, } if (boost::next(pit) != paragraphs.end()) - LYXERR(Debug::LATEX) << "TeXOnePar...done " << &*boost::next(pit) << endl; + LYXERR(Debug::LATEX, "TeXOnePar...done " << &*boost::next(pit)); return ++pit; } @@ -502,7 +630,7 @@ void latexParagraphs(Buffer const & buf, { bool was_title = false; bool already_title = false; - LyXTextClass const & tclass = buf.params().getLyXTextClass(); + TextClass const & tclass = buf.params().getTextClass(); ParagraphList::const_iterator par = paragraphs.begin(); ParagraphList::const_iterator endpar = paragraphs.end(); @@ -526,7 +654,7 @@ void latexParagraphs(Buffer const & buf, // any environment other than the default layout of the // text class to be valid! if (!par->forceDefaultParagraphs()) { - LyXLayout_ptr const & layout = par->layout(); + LayoutPtr const & layout = par->layout(); if (layout->intitle) { if (already_title) { @@ -560,7 +688,7 @@ void latexParagraphs(Buffer const & buf, par = TeXOnePar(buf, paragraphs, par, os, texrow, runparams, everypar); } else if (layout->isEnvironment() || - !par->params().leftIndent().zero()) { + !par->params().leftIndent().zero()) { par = TeXEnvironment(buf, paragraphs, par, os, texrow, runparams); } else { @@ -589,32 +717,59 @@ void latexParagraphs(Buffer const & buf, } -int switchEncoding(odocstream & os, BufferParams const & bparams, - bool moving_arg, Encoding const & oldEnc, - Encoding const & newEnc) +pair switchEncoding(odocstream & os, BufferParams const & bparams, + bool moving_arg, Encoding const & oldEnc, + Encoding const & newEnc) { - // FIXME thailatex does not support the inputenc package, so we - // ignore switches from/to tis620-0 encoding here. This does of - // course only work as long as the non-thai text contains ASCII - // only, but it is the best we can do. - // Since the \inputencoding command does not work inside sections - // we ignore the encoding switch also in moving arguments. - if (((bparams.inputenc == "auto" && !moving_arg) || - bparams.inputenc == "default") && - oldEnc.name() != newEnc.name() && - oldEnc.name() != "ascii" && newEnc.name() != "ascii" && - oldEnc.name() != "tis620-0" && newEnc.name() != "tis620-0") { - LYXERR(Debug::LATEX) << "Changing LaTeX encoding from " - << oldEnc.name() << " to " - << newEnc.name() << endl; - os << setEncoding(newEnc.iconvName()); - if (bparams.inputenc != "default") { - docstring const inputenc(from_ascii(newEnc.latexName())); + if ((bparams.inputenc != "auto" && bparams.inputenc != "default") + || moving_arg) + return make_pair(false, 0); + + // Do nothing if the encoding is unchanged. + if (oldEnc.name() == newEnc.name()) + return make_pair(false, 0); + + // FIXME We ignore encoding switches from/to encodings that do + // neither support the inputenc package nor the CJK package here. + // This does of course only work in special cases (e.g. switch from + // tis620-0 to latin1, but the text in latin1 contains ASCII only), + // but it is the best we can do + if (oldEnc.package() == Encoding::none + || newEnc.package() == Encoding::none) + return make_pair(false, 0); + + LYXERR(Debug::LATEX, "Changing LaTeX encoding from " + << oldEnc.name() << " to " << newEnc.name()); + os << setEncoding(newEnc.iconvName()); + if (bparams.inputenc == "default") + return make_pair(true, 0); + + docstring const inputenc = from_ascii(newEnc.latexName()); + switch (newEnc.package()) { + case Encoding::none: + // shouldn't ever reach here, see above + return make_pair(true, 0); + case Encoding::inputenc: { + int count = inputenc.length(); + if (oldEnc.package() == Encoding::CJK) { + os << "\\end{CJK}"; + count += 9; + } os << "\\inputencoding{" << inputenc << '}'; - return 16 + inputenc.length(); + return make_pair(true, count + 16); + } + case Encoding::CJK: { + int count = inputenc.length(); + if (oldEnc.package() == Encoding::CJK) { + os << "\\end{CJK}"; + count += 9; + } + os << "\\begin{CJK}{" << inputenc << "}{}"; + return make_pair(true, count + 15); } } - return 0; + // Dead code to avoid a warning: + return make_pair(true, 0); } } // namespace lyx