#include "output_latex.h"
+#include "BiblioInfo.h"
#include "Buffer.h"
#include "BufferParams.h"
#include "Encoding.h"
#include "Font.h"
#include "InsetList.h"
#include "Language.h"
-#include "LaTeXFeatures.h"
-#include "Layout.h"
#include "LyXRC.h"
#include "OutputParams.h"
#include "Paragraph.h"
struct OutputState
{
- OutputState() : open_encoding_(none), cjk_inherited_(0),
- prev_env_language_(0), nest_level_(0)
+ OutputState() : prev_env_language_(nullptr), open_encoding_(none),
+ cjk_inherited_(0), nest_level_(0)
{
}
- OpenEncoding open_encoding_;
- int cjk_inherited_;
Language const * prev_env_language_;
- int nest_level_;
stack<int> lang_switch_depth_; // Both are always empty when
stack<string> open_polyglossia_lang_; // not using polyglossia
+ OpenEncoding open_encoding_;
+ int cjk_inherited_;
+ int nest_level_;
};
// commands. Instead, return always true when using babel with
// only a begin command.
- return state->lang_switch_depth_.size() == 0
+ return state->lang_switch_depth_.empty()
? true
: abs(state->lang_switch_depth_.top()) == state->nest_level_;
}
{
// Return true if the language was opened by a local command switch.
- return state->lang_switch_depth_.size()
+ return !state->lang_switch_depth_.empty()
&& state->lang_switch_depth_.top() < 0;
}
{
// Return true if the language was opened at the current nesting level.
- return state->lang_switch_depth_.size()
+ return !state->lang_switch_depth_.empty()
&& abs(state->lang_switch_depth_.top()) == state->nest_level_;
}
struct TeXEnvironmentData
{
- bool cjk_nested;
Layout const * style;
Language const * par_language;
Encoding const * prev_encoding;
+ bool cjk_nested;
bool leftindent_open;
};
pit == paragraphs.begin() ? pit : prev(pit, 1);
OutputState * state = getOutputState();
- bool const use_prev_env_language = state->prev_env_language_ != 0
+ bool const use_prev_env_language = state->prev_env_language_ != nullptr
&& priorpit->layout().isEnvironment()
&& (priorpit->getDepth() > pit->getDepth()
|| (priorpit->getDepth() == pit->getDepth()
// polyglossia or begin/end commands, then the current
// language is the document language.
string const & cur_lang = using_begin_end
- && state->lang_switch_depth_.size()
+ && !state->lang_switch_depth_.empty()
? openLanguageName(state)
: doc_lang;
// in multilingual environments, the CJK tags have to be nested properly
data.cjk_nested = false;
- if (data.par_language->encoding()->package() == Encoding::CJK &&
- state->open_encoding_ != CJK && pit->isMultiLingual(bparams)) {
+ if (!bparams.useNonTeXFonts
+ && (bparams.inputenc == "auto-legacy"
+ || bparams.inputenc == "auto-legacy-plain")
+ && data.par_language->encoding()->package() == Encoding::CJK
+ && state->open_encoding_ != CJK && pit->isMultiLingual(bparams)) {
if (prev_par_language->encoding()->package() == Encoding::CJK) {
- docstring const cjkenc = (bparams.encoding().name() == "utf8-cjk"
- && LaTeXFeatures::isAvailable("CJKutf8")) ?
- from_ascii("UTF8")
- : from_ascii(data.par_language->encoding()->latexName());
- os << "\\begin{CJK}{" << cjkenc
+ os << "\\begin{CJK}{"
+ << from_ascii(data.par_language->encoding()->latexName())
<< "}{" << from_ascii(bparams.fonts_cjk) << "}%\n";
}
state->open_encoding_ = CJK;
pit_type & pit, otexstream & os)
{
ParagraphList const & paragraphs = text.paragraphs();
- ParagraphList::const_iterator ipar = paragraphs.constIterator(pit);
+ ParagraphList::const_iterator ipar = paragraphs.iterator_at(pit);
LYXERR(Debug::LATEX, "TeXEnvironment for paragraph " << pit);
Layout const & current_layout = ipar->layout();
// This is for debugging purpose at the end.
pit_type const par_begin = pit;
for (; pit < runparams.par_end; ++pit) {
- ParagraphList::const_iterator par = paragraphs.constIterator(pit);
+ ParagraphList::const_iterator par = paragraphs.iterator_at(pit);
// check first if this is an higher depth paragraph.
bool go_out = (par->params().depth() < current_depth);
continue;
}
+ // Do not output empty environments if the whole paragraph has
+ // been deleted with ct and changes are not output.
+ if (size_t(pit + 1) < paragraphs.size()) {
+ ParagraphList::const_iterator nextpar = paragraphs.iterator_at(pit + 1);
+ Paragraph const & cpar = paragraphs.at(pit);
+ if ((par->layout() != nextpar->layout()
+ || par->params().depth() == nextpar->params().depth()
+ || par->params().leftIndent() == nextpar->params().leftIndent())
+ && !runparams.for_search && !cpar.empty()
+ && cpar.isDeleted(0, cpar.size()) && !buf.params().output_changes) {
+ if (!buf.params().output_changes && !cpar.parEndChange().deleted())
+ os << '\n' << '\n';
+ continue;
+ }
+ }
+
// This is a new environment.
TeXEnvironmentData const data =
prepareEnvironment(buf, text, par, os, runparams);
void getArgInsets(otexstream & os, OutputParams const & runparams, Layout::LaTeXArgMap const & latexargs,
- map<int, lyx::InsetArgument const *> ilist, vector<string> required, string const & prefix)
+ map<size_t, lyx::InsetArgument const *> ilist, vector<string> required, string const & prefix)
{
- unsigned int const argnr = latexargs.size();
+ size_t const argnr = latexargs.size();
if (argnr == 0)
return;
// other arguments, consider this.
for (auto const & larg : latexargs) {
Layout::latexarg const & arg = larg.second;
- if ((!arg.presetarg.empty() || !arg.defaultarg.empty()) && !arg.requires.empty()) {
- vector<string> req = getVectorFromString(arg.requires);
+ if ((!arg.presetarg.empty() || !arg.defaultarg.empty()) && !arg.required.empty()) {
+ vector<string> req = getVectorFromString(arg.required);
required.insert(required.end(), req.begin(), req.end());
}
}
- for (unsigned int i = 1; i <= argnr; ++i) {
- map<int, InsetArgument const *>::const_iterator lit = ilist.find(i);
+ for (size_t i = 1; i <= argnr; ++i) {
+ map<size_t, InsetArgument const *>::const_iterator lit = ilist.find(i);
bool inserted = false;
if (lit != ilist.end()) {
- InsetArgument const * ins = (*lit).second;
+ InsetArgument const * ins = lit->second;
if (ins) {
Layout::LaTeXArgMap::const_iterator const lait =
latexargs.find(ins->name());
if (lait != latexargs.end()) {
- Layout::latexarg arg = (*lait).second;
+ Layout::latexarg arg = lait->second;
docstring ldelim;
docstring rdelim;
if (!arg.nodelims) {
}
}
}
+ if (runparams.for_search) {
+ // Mark end of arguments for findadv() only
+ os << "\\endarguments{}";
+ }
}
void addArgInsets(Paragraph const & par, string const & prefix,
Layout::LaTeXArgMap const & latexargs,
- map<int, InsetArgument const *> & ilist,
+ map<size_t, InsetArgument const *> & ilist,
vector<string> & required)
{
for (auto const & table : par.insetList()) {
}
string const name = prefix.empty() ?
arg->name() : split(arg->name(), ':');
- // why converting into an integer?
- unsigned int const nr = convert<unsigned int>(name);
- if (ilist.find(nr) == ilist.end())
- ilist[nr] = arg;
+ size_t const nr = convert<size_t>(name);
+ ilist.insert({nr, arg});
Layout::LaTeXArgMap::const_iterator const lit =
latexargs.find(arg->name());
if (lit != latexargs.end()) {
Layout::latexarg const & larg = lit->second;
- vector<string> req = getVectorFromString(larg.requires);
+ vector<string> req = getVectorFromString(larg.required);
move(req.begin(), req.end(), back_inserter(required));
}
}
Layout::LaTeXArgMap const & latexargs,
string const & prefix)
{
- map<int, InsetArgument const *> ilist;
+ map<size_t, InsetArgument const *> ilist;
vector<string> required;
addArgInsets(par, prefix, latexargs, ilist, required);
getArgInsets(os, runparams, latexargs, ilist, required, prefix);
Layout::LaTeXArgMap const & latexargs,
string const & prefix)
{
- map<int, InsetArgument const *> ilist;
+ map<size_t, InsetArgument const *> ilist;
vector<string> required;
depth_type const current_depth = pit->params().depth();
Layout const current_layout = pit->layout();
// get the first paragraph in sequence with this layout and depth
- pit_type offset = 0;
+ ptrdiff_t offset = 0;
while (true) {
- if (lyx::prev(pit, offset) == pars.begin())
+ if (prev(pit, offset) == pars.begin())
break;
- ParagraphList::const_iterator priorpit = lyx::prev(pit, offset + 1);
+ ParagraphList::const_iterator priorpit = prev(pit, offset + 1);
if (priorpit->layout() == current_layout
&& priorpit->params().depth() == current_depth)
++offset;
break;
}
- ParagraphList::const_iterator spit = lyx::prev(pit, offset);
-
+ ParagraphList::const_iterator spit = prev(pit, offset);
for (; spit != pars.end(); ++spit) {
if (spit->layout() != current_layout ||
spit->params().depth() < current_depth)
Layout::LaTeXArgMap const & latexargs,
string const & prefix)
{
- map<int, InsetArgument const *> ilist;
+ map<size_t, InsetArgument const *> ilist;
vector<string> required;
for (Paragraph const & par : pars) {
{
switch (style.latextype) {
case LATEX_COMMAND:
- if (par.needsCProtection(runparams.moving_arg))
+ if (par.needsCProtection(runparams.moving_arg)) {
+ if (contains(runparams.active_chars, '^'))
+ // cprotect relies on ^ being on catcode 7
+ os << "\\begingroup\\catcode`\\^=7";
os << "\\cprotect";
+ }
os << '\\' << from_ascii(style.latexname());
// Command arguments
os << " ";
}
break;
+ case LATEX_ENVIRONMENT:
+ if (runparams.for_search) {
+ os << "\\latexenvironment{" << style.latexname() << "}{";
+ }
+ break;
case LATEX_BIB_ENVIRONMENT:
// ignore this, the inset will write itself
break;
if (style.inpreamble && !force)
return;
+ // Do not output empty commands if the whole paragraph has
+ // been deleted with ct and changes are not output.
+ if (!runparams_in.for_search && style.latextype != LATEX_ENVIRONMENT
+ && !par.empty() && par.isDeleted(0, par.size()) && !bparams.output_changes)
+ return;
+
LYXERR(Debug::LATEX, "TeXOnePar for paragraph " << pit << " ptr " << &par << " '"
<< everypar << "'");
OutputParams runparams = runparams_in;
runparams.isLastPar = (pit == pit_type(paragraphs.size() - 1));
- // We reinitialze par begin and end to be on the safe side
+ // We reinitialize par begin and end to be on the safe side
// with embedded inset as we don't know if they set those
// value correctly.
runparams.par_begin = 0;
state->open_encoding_ = none;
}
+ // This paragraph is merged and we do not show changes in the output
+ bool const merged_par = !bparams.output_changes && par.parEndChange().deleted();
+
if (text.inset().isPassThru()) {
Font const outerfont = text.outerFont(pit);
// No newline before first paragraph in this lyxtext
- if (pit > 0) {
+ if (pit > 0 && !text.inset().getLayout().parbreakIgnored() && !merged_par) {
os << '\n';
if (!text.inset().getLayout().parbreakIsNewline())
os << '\n';
}
Paragraph const * nextpar = runparams.isLastPar
- ? 0 : ¶graphs.at(pit + 1);
+ ? nullptr : ¶graphs.at(pit + 1);
- bool const intitle_command = style.intitle && style.latextype == LATEX_COMMAND;
+ bool const intitle_command = style.intitle && style.isCommand();
+ // Intitle commands switch languages locally, thus increase
+ // language nesting level
+ if (intitle_command)
+ state->nest_level_ += 1;
if (style.pass_thru) {
Font const outerfont = text.outerFont(pit);
parStartCommand(par, os, runparams, style);
+ if (style.isCommand() && style.needprotect)
+ // Due to the moving argument, some fragile
+ // commands (labels, index entries)
+ // are output after this command (#2154)
+ runparams.postpone_fragile_stuff =
+ bparams.postpone_fragile_content;
if (intitle_command)
os << '{';
// I did not create a parEndCommand for this minuscule
// task because in the other user of parStartCommand
// the code is different (JMarc)
- if (style.isCommand())
- os << "}\n";
- else
+ if (style.isCommand()) {
+ os << "}";
+ if (par.needsCProtection(runparams.moving_arg)
+ && contains(runparams.active_chars, '^'))
+ os << "\\endgroup";
+ if (merged_par)
+ os << "{}";
+ else
+ os << "\n";
+ }
+ else if (!merged_par)
os << '\n';
- if (!style.parbreak_is_newline) {
+ if (!style.parbreak_is_newline && !merged_par) {
os << '\n';
} else if (nextpar && !style.isEnvironment()) {
Layout const nextstyle = text.inset().forcePlainLayout()
? bparams.documentClass().plainLayout()
: nextpar->layout();
- if (nextstyle.name() != style.name())
+ if (nextstyle.name() != style.name() && !merged_par)
os << '\n';
}
// This paragraph's language
Language const * const par_language = par.getParLanguage(bparams);
Language const * const nextpar_language = nextpar ?
- nextpar->getParLanguage(bparams) : 0;
+ nextpar->getParLanguage(bparams) : nullptr;
// The document's language
Language const * const doc_language = bparams.language;
// 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 != nullptr) ?
runparams.local_font->language() : doc_language;
- Paragraph const * priorpar = (pit == 0) ? 0 : ¶graphs.at(pit - 1);
+ Paragraph const * priorpar = (pit == 0) ? nullptr : ¶graphs.at(pit - 1);
// The previous language that was in effect is the language of the
// previous paragraph, unless the previous paragraph is inside an
// Note further that we take the outer language also if the prior par
// is PassThru, since in that case it has latex_language, and all secondary
// languages have been closed (#10793).
- bool const use_prev_env_language = state->prev_env_language_ != 0
+ bool const use_prev_env_language = state->prev_env_language_ != nullptr
&& priorpar
&& priorpar->layout().isEnvironment()
&& (priorpar->getDepth() > par.getDepth()
|| (priorpar->getDepth() == par.getDepth()
- && priorpar->layout() != par.layout()));
+ && priorpar->layout() != par.layout()));
+
+ // We need to ignore previous intitle commands since languages
+ // are switched locally there (# 11514)
+ // There might be paragraphs before the title, so we check this.
+ Paragraph * prior_nontitle_par = nullptr;
+ if (!intitle_command) {
+ pit_type ppit = pit;
+ while (ppit > 0) {
+ --ppit;
+ Paragraph const * tmppar = ¶graphs.at(ppit);
+ if (tmppar->layout().intitle && tmppar->layout().isCommand())
+ continue;
+ prior_nontitle_par = const_cast<Paragraph*>(tmppar);
+ break;
+ }
+ }
Language const * const prev_language =
- runparams_in.for_search ?
- languages.getLanguage("ignore")
- :(priorpar && !priorpar->isPassThru())
- ? (use_prev_env_language ? state->prev_env_language_
- : priorpar->getParLanguage(bparams))
- : outer_language;
+ runparams_in.for_search
+ ? languages.getLanguage("ignore")
+ : (prior_nontitle_par && !prior_nontitle_par->isPassThru())
+ ? (use_prev_env_language
+ ? state->prev_env_language_
+ : prior_nontitle_par->getParLanguage(bparams))
+ : outer_language;
bool const use_polyglossia = runparams.use_polyglossia;
string const par_lang = use_polyglossia ?
// (see #10849); thus open the command here.
if (intitle_command) {
parStartCommand(par, os, runparams, style);
+ if (style.isCommand() && style.needprotect)
+ // Due to the moving argument, some fragile
+ // commands (labels, index entries)
+ // are output after this command (#2154)
+ runparams.postpone_fragile_stuff =
+ bparams.postpone_fragile_content;
os << '{';
}
// languages (see # 10111).
bool const in_polyglossia_rtl_env =
use_polyglossia
- && runparams.local_font != 0
+ && runparams.local_font != nullptr
&& outer_language->rightToLeft()
&& !par_language->rightToLeft();
- bool const localswitch = runparams_in.for_search
+ bool const localswitch =
+ (runparams_in.for_search
|| text.inset().forceLocalFontSwitch()
|| (using_begin_end && text.inset().forcePlainLayout())
- || in_polyglossia_rtl_env;
+ || in_polyglossia_rtl_env)
+ && !text.inset().forceParDirectionSwitch();
if (localswitch) {
lang_begin_command = use_polyglossia ?
"\\text$$lang$$opts{" : lyxrc.language_command_local;
&& par_language->lang() != "arabic_arabtex"
&& outer_language->lang() != "arabic_arabtex"
// are we in an inset?
- && runparams.local_font != 0
+ && runparams.local_font != nullptr
// is the inset within an \L or \R?
//
// FIXME: currently, we don't check this; this means that
os << "\\L{";
}
// With CJK, the CJK tag has to be closed first (see below)
- if ((runparams.encoding->package() != Encoding::CJK || runparams.for_search)
- && (par_lang != openLanguageName(state) || localswitch)
+ if ((runparams.encoding->package() != Encoding::CJK
+ || bparams.useNonTeXFonts
+ || runparams.for_search)
+ && (par_lang != openLanguageName(state) || localswitch || intitle_command)
&& !par_lang.empty()) {
string bc = use_polyglossia ?
getPolyglossiaBegin(lang_begin_command, par_lang,
}
}
- // Switch file encoding if necessary; no need to do this for "default"
+ // Switch file encoding if necessary; no need to do this for "auto-legacy-plain"
// encoding, since this only affects the position of the outputted
// \inputencoding command; the encoding switch will occur when necessary
- if (bparams.inputenc == "auto"
+ if (bparams.inputenc == "auto-legacy"
&& !runparams.isFullUnicode() // Xe/LuaTeX use one document-wide encoding (see also switchEncoding())
+ && runparams.encoding->package() != Encoding::japanese
&& runparams.encoding->package() != Encoding::none) {
// Look ahead for future encoding changes.
// We try to output them at the beginning of the paragraph,
// context (nesting issue).
if (par_language->encoding()->package() == Encoding::CJK
&& state->open_encoding_ != CJK && state->cjk_inherited_ == 0) {
- docstring const cjkenc = (bparams.encoding().name() == "utf8-cjk"
- && LaTeXFeatures::isAvailable("CJKutf8")) ?
- from_ascii("UTF8")
- : from_ascii(par_language->encoding()->latexName());
- os << "\\begin{CJK}{" << cjkenc
+ os << "\\begin{CJK}{"
+ << from_ascii(par_language->encoding()->latexName())
<< "}{" << from_ascii(bparams.fonts_cjk) << "}%\n";
state->open_encoding_ = CJK;
}
if (runparams.encoding->package() == Encoding::CJK
&& par_lang != openLanguageName(state)
&& !par_lang.empty()) {
- string bc = use_polyglossia ?
- getPolyglossiaBegin(lang_begin_command, par_lang,
- par_language->polyglossiaOpts(),
- localswitch)
- : subst(lang_begin_command, "$$lang", par_lang);
- os << bc
+ os << subst(lang_begin_command, "$$lang", par_lang)
<< lang_command_termination;
if (using_begin_end)
pushLanguageName(par_lang, localswitch);
}
runparams.moving_arg |= style.needprotect;
+ if (style.needmboxprotect)
+ ++runparams.inulemcmd;
Encoding const * const prev_encoding = runparams.encoding;
bool const useSetSpace = bparams.documentClass().provides("SetSpace");
// For InTitle commands, we already started the command before
// the language switch
- if (!intitle_command)
+ if (!intitle_command) {
parStartCommand(par, os, runparams, style);
+ if (style.isCommand() && style.needprotect)
+ // Due to the moving argument, some fragile
+ // commands (labels, index entries)
+ // are output after this command (#2154)
+ runparams.postpone_fragile_stuff =
+ bparams.postpone_fragile_content;
+ }
Font const outerfont = text.outerFont(pit);
os << '}';
if (!style.postcommandargs().empty())
latexArgInsets(par, os, runparams, style.postcommandargs(), "post:");
+ if (!runparams.post_macro.empty()) {
+ // Output the stored fragile commands (labels, indices etc.)
+ // that need to be output after the command with moving argument.
+ os << runparams.post_macro;
+ runparams.post_macro.clear();
+ }
+ if (par.needsCProtection(runparams.moving_arg)
+ && contains(runparams.active_chars, '^'))
+ os << "\\endgroup";
if (runparams.encoding != prev_encoding) {
runparams.encoding = prev_encoding;
os << setEncoding(prev_encoding->iconvName());
&& nextpar->getDepth() < par.getDepth()))
close_lang_switch = using_begin_end;
if (nextpar && par.params().depth() < nextpar->params().depth())
- pending_newline = true;
+ pending_newline = !text.inset().getLayout().parbreakIgnored() && !merged_par;
break;
case LATEX_ENVIRONMENT: {
- // if its the last paragraph of the current environment
+ // if it's the last paragraph of the current environment
// skip it otherwise fall through
if (nextpar
&& ((nextpar->layout() != par.layout()
default:
// we don't need it for the last paragraph and in InTitle commands!!!
if (nextpar && !intitle_command)
- pending_newline = true;
+ pending_newline = !text.inset().getLayout().parbreakIgnored() && !merged_par;
}
// InTitle commands use switches (not environments) for space settings
&& (par_language->lang() != "arabic_arabtex"
&& outer_language->lang() != "arabic_arabtex")
// have we opened an \L or \R environment?
- && runparams.local_font != 0
+ && runparams.local_font != nullptr
&& runparams.local_font->isRightToLeft() != par_language->rightToLeft()
// are we about to close the language?
&&((nextpar && par_lang != nextpar_lang)
if (localswitch_needed
|| (intitle_command && using_begin_end)
|| closing_rtl_ltr_environment
- || ((runparams.isLastPar || close_lang_switch)
+ || (((runparams.isLastPar && !runparams.inbranch) || close_lang_switch)
&& (par_lang != outer_lang || (using_begin_end
&& style.isEnvironment()
&& par_lang != nextpar_lang)))) {
os << '\n';
// when the paragraph uses CJK, the language has to be closed earlier
- if ((font.language()->encoding()->package() != Encoding::CJK) || runparams_in.for_search) {
+ if ((font.language()->encoding()->package() != Encoding::CJK)
+ || bparams.useNonTeXFonts
+ || runparams_in.for_search) {
if (lang_end_command.empty()) {
// If this is a child, we should restore the
// master language after the last paragraph.
localswitch)
: subst(lang_begin_command, "$$lang", current_lang);
os << bc;
- pending_newline = !localswitch;
+ pending_newline = !localswitch
+ && !text.inset().getLayout().parbreakIgnored();
unskip_newline = !localswitch;
if (using_begin_end)
pushLanguageName(current_lang, localswitch);
&& nextpar
&& style != nextpar->layout())))
|| (atSameLastLangSwitchDepth(state)
- && state->lang_switch_depth_.size()
+ && !state->lang_switch_depth_.empty()
&& cur_lang != par_lang)
|| in_polyglossia_rtl_env)
{
lang_end_command,
"$$lang",
par_lang));
- pending_newline = !localswitch;
+ pending_newline = !localswitch
+ && !text.inset().getLayout().parbreakIgnored();
unskip_newline = !localswitch;
if (using_begin_end)
popLanguageName();
// InTitle commands need to be closed after the language has been closed.
if (intitle_command) {
- if (is_command) {
- os << '}';
- if (!style.postcommandargs().empty())
- latexArgInsets(par, os, runparams, style.postcommandargs(), "post:");
- if (runparams.encoding != prev_encoding) {
- runparams.encoding = prev_encoding;
- os << setEncoding(prev_encoding->iconvName());
- }
+ os << '}';
+ if (!style.postcommandargs().empty())
+ latexArgInsets(par, os, runparams, style.postcommandargs(), "post:");
+ if (!runparams.post_macro.empty()) {
+ // Output the stored fragile commands (labels, indices etc.)
+ // that need to be output after the command with moving argument.
+ os << runparams.post_macro;
+ runparams.post_macro.clear();
+ }
+ if (par.needsCProtection(runparams.moving_arg)
+ && contains(runparams.active_chars, '^'))
+ os << "\\endgroup";
+ if (runparams.encoding != prev_encoding) {
+ runparams.encoding = prev_encoding;
+ os << setEncoding(prev_encoding->iconvName());
}
}
bool const last_was_separator =
- par.size() > 0 && par.isEnvSeparator(par.size() - 1);
+ !par.empty() && par.isEnvSeparator(par.size() - 1);
+
+ // Signify added/deleted par break in output if show changes in output
+ if (nextpar && !os.afterParbreak() && !last_was_separator
+ && bparams.output_changes && par.parEndChange().changed()) {
+ Changes::latexMarkChange(os, bparams, Change(Change::UNCHANGED),
+ par.parEndChange(), runparams);
+ os << bparams.encoding().latexString(docstring(1, 0x00b6)).first << "}";
+ }
if (pending_newline) {
if (unskip_newline)
// if this is a CJK-paragraph and the next isn't, close CJK
// also if the next paragraph is a multilingual environment (because of nesting)
- if (nextpar
- && (state->open_encoding_ == CJK && bparams.encoding().iconvName() != "UTF-8")
- && (nextpar_language->encoding()->package() != Encoding::CJK
- || (nextpar->layout().isEnvironment() && nextpar->isMultiLingual(bparams)))
+ if (nextpar && state->open_encoding_ == CJK
+ && bparams.encoding().iconvName() != "UTF-8"
+ && bparams.encoding().package() != Encoding::CJK
+ && ((nextpar_language &&
+ nextpar_language->encoding()->package() != Encoding::CJK)
+ || (nextpar->layout().isEnvironment() && nextpar->isMultiLingual(bparams)))
// inbetween environments, CJK has to be closed later (nesting!)
&& (!style.isEnvironment() || !nextpar->layout().isEnvironment())) {
os << "\\end{CJK}\n";
break;
}
case inputenc: {
+ // FIXME: If we are in an inset and the switch happened outside this inset,
+ // do not switch back at the end of the inset (bug #8479)
+ // The following attempt does not help with listings-caption in a CJK document:
+ // if (runparams_in.local_font != 0
+ // && runparams_in.encoding == runparams_in.local_font->language()->encoding())
+ // break;
os << "\\egroup";
state->open_encoding_ = none;
break;
}
}
- // If this is the last paragraph, and a local_font was set upon entering
- // the inset, and we're using "auto" or "default" encoding, and not
- // compiling with XeTeX or LuaTeX, the encoding
- // should be set back to that local_font's encoding.
- if (runparams.isLastPar && runparams_in.local_font != 0
+ // Information about local language is stored as a font feature.
+ // If this is the last paragraph of the inset and a local_font was set upon entering
+ // and we are mixing encodings ("auto-legacy" or "auto-legacy-plain" and no XeTeX or LuaTeX),
+ // ensure the encoding is set back to the default encoding of the local language.
+ if (runparams.isLastPar && runparams_in.local_font != nullptr
&& runparams_in.encoding != runparams_in.local_font->language()->encoding()
- && (bparams.inputenc == "auto" || bparams.inputenc == "default")
+ && (bparams.inputenc == "auto-legacy" || bparams.inputenc == "auto-legacy-plain")
&& !runparams.isFullUnicode()
) {
runparams_in.encoding = runparams_in.local_font->language()->encoding();
else
runparams_in.encoding = runparams.encoding;
+ // Also pass the post_macros upstream
+ runparams_in.post_macro = runparams.post_macro;
+ // These need to be passed upstream as well
+ runparams_in.need_maketitle = runparams.need_maketitle;
+ runparams_in.have_maketitle = runparams.have_maketitle;
+
// 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 (nextpar && !os.afterParbreak() && !last_was_separator) {
- // Make sure to start a new line
- os << breakln;
Layout const & next_layout = nextpar->layout();
+ if (!text.inset().getLayout().parbreakIgnored() && !merged_par)
+ // Make sure to start a new line
+ os << breakln;
// A newline '\n' is always output before a command,
// so avoid doubling it.
if (!next_layout.isCommand()) {
if ((style == next_layout
&& !style.parbreak_is_newline
&& !text.inset().getLayout().parbreakIsNewline()
+ && !text.inset().getLayout().parbreakIgnored()
&& style.latextype != LATEX_ITEM_ENVIRONMENT
&& style.latextype != LATEX_LIST_ENVIRONMENT
- && style.align == par.getAlign()
+ && style.align == par.getAlign(bparams)
&& nextpar->getDepth() == par.getDepth()
- && nextpar->getAlign() == par.getAlign())
+ && nextpar->getAlign(bparams) == par.getAlign(bparams))
|| (!next_layout.isEnvironment()
&& nextpar->getDepth() > par.getDepth()
- && nextpar->getAlign() == par.getAlign())
+ && nextpar->getAlign(bparams) == next_layout.align)
|| (!style.isEnvironment()
&& next_layout.latextype == LATEX_ENVIRONMENT
&& nextpar->getDepth() < par.getDepth())
|| (style.isCommand()
&& !next_layout.isEnvironment()
- && style.align == par.getAlign()
- && next_layout.align == nextpar->getAlign())
- || (style.align != par.getAlign()
+ && style.align == par.getAlign(bparams)
+ && next_layout.align == nextpar->getAlign(bparams))
+ || (style.align != par.getAlign(bparams)
&& tclass.isDefaultLayout(next_layout))) {
- os << '\n';
+ // and omit paragraph break if it has been deleted with ct
+ // and changes are not shown in output
+ if (!merged_par)
+ os << '\n';
}
}
}
+ // Reset language nesting level after intitle command
+ if (intitle_command)
+ state->nest_level_ -= 1;
+
LYXERR(Debug::LATEX, "TeXOnePar for paragraph " << pit << " done; ptr "
<< &par << " next " << nextpar);
if (multibib_child && mparams.useBiblatex())
os << "\\newrefsection";
- else if (multibib_child && mparams.useBibtopic()) {
+ else if (multibib_child && mparams.useBibtopic()
+ && !buf.masterBibInfo().empty()) {
os << "\\begin{btUnit}\n";
runparams.openbtUnit = true;
}
// Open a CJK environment at the beginning of the main buffer
- // (but not in child documents or documents using system fonts)
- // if the document's language is a CJK language (with some exceptions)
- // or the document encoding is utf8-cjk:
+ // if the document's main encoding requires the CJK package
+ // or the document encoding is utf8 and the CJK package is required
+ // (but not in child documents or documents using system fonts):
OutputState * state = getOutputState();
if (maintext && !is_child && !bparams.useNonTeXFonts
- && ((bparams.language->encoding()->package() == Encoding::CJK
- && (bparams.encoding().iconvName() != "UTF-8"
- || bparams.encoding().name() == "utf8-cjk"
- || bparams.encoding().name() == "utf8" ))
- || (bparams.encoding().name() == "utf8-cjk"
- && LaTeXFeatures::isAvailable("CJKutf8")))) {
+ && (bparams.encoding().package() == Encoding::CJK
+ || (bparams.encoding().name() == "utf8"
+ && runparams.use_CJK))
+ ) {
docstring const cjkenc = bparams.encoding().iconvName() == "UTF-8"
- ? from_ascii("UTF8") : from_ascii(bparams.encoding().latexName());
+ ? from_ascii("UTF8")
+ : from_ascii(bparams.encoding().latexName());
os << "\\begin{CJK}{" << cjkenc
<< "}{" << from_ascii(bparams.fonts_cjk) << "}%\n";
state->open_encoding_ = CJK;
// The full doc will be exported but it is easier to just rely on
// runparams range parameters that will be passed TeXEnvironment.
runparams.par_begin = 0;
- runparams.par_end = paragraphs.size();
+ runparams.par_end = static_cast<int>(paragraphs.size());
}
pit_type pit = runparams.par_begin;
// lastpit is for the language check after the loop.
pit_type lastpit = pit;
- // variables used in the loop:
- bool was_title = false;
- bool already_title = false;
DocumentClass const & tclass = bparams.documentClass();
// Did we already warn about inTitle layout mixing? (we only warn once)
bool gave_layout_warning = false;
for (; pit < runparams.par_end; ++pit) {
lastpit = pit;
- ParagraphList::const_iterator par = paragraphs.constIterator(pit);
+ ParagraphList::const_iterator par = paragraphs.iterator_at(pit);
// FIXME This check should not be needed. We should
// perhaps issue an error if it is.
tclass.plainLayout() : par->layout();
if (layout.intitle) {
- if (already_title) {
+ if (runparams.have_maketitle) {
if (!gave_layout_warning && !runparams.dryrun) {
gave_layout_warning = true;
frontend::Alert::warning(_("Error in latexParagraphs"),
"could lead to missing or incorrect output."
), layout.name()));
}
- } else if (!was_title) {
- was_title = true;
+ } else if (!runparams.need_maketitle) {
+ runparams.need_maketitle = true;
if (tclass.titletype() == TITLE_ENVIRONMENT) {
os << "\\begin{"
<< from_ascii(tclass.titlename())
<< "}\n";
}
}
- } else if (was_title && !already_title && !layout.inpreamble) {
+ } else if (runparams.need_maketitle && !runparams.have_maketitle
+ && !layout.inpreamble && !text.inset().isInTitle()) {
if (tclass.titletype() == TITLE_ENVIRONMENT) {
os << "\\end{" << from_ascii(tclass.titlename())
<< "}\n";
os << "\\" << from_ascii(tclass.titlename())
<< "\n";
}
- already_title = true;
- was_title = false;
+ runparams.have_maketitle = true;
+ runparams.need_maketitle = false;
}
if (layout.isCommand() && !layout.latexname().empty()
&& layout.latexname() == bparams.multibib) {
if (runparams.openbtUnit)
os << "\\end{btUnit}\n";
- if (!bparams.useBiblatex()) {
+ if (!bparams.useBiblatex()
+ && !buf.masterBibInfo().empty()) {
os << '\n' << "\\begin{btUnit}\n";
runparams.openbtUnit = true;
}
continue;
}
+ // Do not output empty environments if the whole paragraph has
+ // been deleted with ct and changes are not output.
+ if (size_t(pit + 1) < paragraphs.size()) {
+ ParagraphList::const_iterator nextpar = paragraphs.iterator_at(pit + 1);
+ Paragraph const & cpar = paragraphs.at(pit);
+ if ((par->layout() != nextpar->layout()
+ || par->params().depth() == nextpar->params().depth()
+ || par->params().leftIndent() == nextpar->params().leftIndent())
+ && !runparams.for_search && !cpar.empty()
+ && cpar.isDeleted(0, cpar.size()) && !bparams.output_changes) {
+ if (!cpar.parEndChange().deleted())
+ os << '\n' << '\n';
+ continue;
+ }
+ }
+
TeXEnvironmentData const data =
prepareEnvironment(buf, text, par, os, runparams);
// pit can be changed in TeXEnvironment.
finishEnvironment(os, runparams, data);
}
+ // FIXME: uncomment the content or remove this block
if (pit == runparams.par_end) {
// Make sure that the last paragraph is
// correctly terminated (because TeXOnePar does
//os << '\n';
}
- // It might be that we only have a title in this document
- if (was_title && !already_title) {
+ // It might be that we only have a title in this document.
+ // But if we're in an inset, this is not the end of
+ // the document. (There may be some other checks of this
+ // kind that are needed.)
+ if (runparams.need_maketitle && !runparams.have_maketitle && maintext) {
if (tclass.titletype() == TITLE_ENVIRONMENT) {
os << "\\end{" << from_ascii(tclass.titlename())
<< "}\n";
// if "auto end" is switched off, explicitly close the language at the end
// but only if the last par is in a babel or polyglossia language
+ Language const * const lastpar_language =
+ paragraphs.at(lastpit).getParLanguage(bparams);
if (maintext && !lyxrc.language_auto_end && !mainlang.empty() &&
- paragraphs.at(lastpit).getParLanguage(bparams)->encoding()->package() != Encoding::CJK) {
+ lastpar_language->encoding()->package() != Encoding::CJK) {
os << from_utf8(subst(lang_end_command,
"$$lang",
mainlang))
<< '\n';
- if (using_begin_end)
+ // If we have language_auto_begin, the stack will
+ // already be empty, nothing to pop()
+ if (using_begin_end && !lyxrc.language_auto_begin)
popLanguageName();
}
state->open_encoding_ = none;
}
// Likewise for polyglossia or when using begin/end commands
+ // or at the very end of an active branch inset with a language switch
+ Language const * const outer_language = (runparams.local_font != nullptr)
+ ? runparams.local_font->language() : bparams.language;
+ string const & prev_lang = runparams.use_polyglossia
+ ? getPolyglossiaEnvName(outer_language)
+ : outer_language->babel();
+ string const lastpar_lang = runparams.use_polyglossia ?
+ getPolyglossiaEnvName(lastpar_language): lastpar_language->babel();
string const & cur_lang = openLanguageName(state);
- if (maintext && !is_child && !cur_lang.empty()) {
+ if (((runparams.inbranch && langOpenedAtThisLevel(state) && prev_lang != cur_lang)
+ || (maintext && !is_child)) && !cur_lang.empty()) {
os << from_utf8(subst(lang_end_command,
"$$lang",
cur_lang))
<< '\n';
if (using_begin_end)
popLanguageName();
+ } else if (runparams.inbranch && !using_begin_end
+ && prev_lang != lastpar_lang && !lastpar_lang.empty()) {
+ // with !using_begin_end, cur_lang is empty, so we need to
+ // compare against the paragraph language (and we are in the
+ // last paragraph at this point)
+ os << subst(lang_begin_command, "$$lang", prev_lang) << '\n';
}
// reset inherited encoding
}
}
-
+// Switch the input encoding for some part(s) of the document.
pair<bool, int> switchEncoding(odocstream & os, BufferParams const & bparams,
OutputParams const & runparams, Encoding const & newEnc,
bool force, bool noswitchmacro)
{
- // XeTeX/LuaTeX use only one encoding per document:
- // * with useNonTeXFonts: "utf8plain",
- // * with XeTeX and TeX fonts: "ascii" (inputenc fails),
- // * with LuaTeX and TeX fonts: only one encoding accepted by luainputenc.
+ // Never switch encoding with XeTeX/LuaTeX
+ // or if we're in a moving argument or inherit the outer encoding.
if (runparams.isFullUnicode() || newEnc.name() == "inherit")
+ return make_pair(false, 0);
+
+ // Only switch for auto-selected legacy encodings (inputenc setting
+ // "auto-legacy" or "auto-legacy-plain").
+ // The "listings" environment can force a switch also with other
+ // encoding settings (it does not support variable width encodings
+ // (utf8, jis, ...) under 8-bit latex engines).
+ if (!force && ((bparams.inputenc != "auto-legacy" && bparams.inputenc != "auto-legacy-plain")
+ || runparams.moving_arg))
return make_pair(false, 0);
Encoding const & oldEnc = *runparams.encoding;
- bool moving_arg = runparams.moving_arg;
- // If we switch from/to CJK, we need to switch anyway, despite custom inputenc,
- // except if we use CJKutf8
- bool const from_to_cjk =
- ((oldEnc.package() == Encoding::CJK && newEnc.package() != Encoding::CJK)
- || (oldEnc.package() != Encoding::CJK && newEnc.package() == Encoding::CJK))
- && ((bparams.encoding().name() != "utf8-cjk" && bparams.encoding().name() != "utf8")
- || !LaTeXFeatures::isAvailable("CJKutf8"));
- if (!force && !from_to_cjk
- && ((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())
+ // Do not switch, if the encoding is unchanged or switching is not supported.
+ if (oldEnc.name() == newEnc.name()
+ || oldEnc.package() == Encoding::japanese
+ || oldEnc.package() == Encoding::none
+ || newEnc.package() == Encoding::none
+ || runparams.for_search)
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
- //
- // 2019-01-08 Possibly no longer required since tis620-0 is supported
- // by inputenc (but check special encodings "utf8-plain" and "default").
- if (oldEnc.package() == Encoding::none || newEnc.package() == Encoding::none)
- return make_pair(false, 0);
+ // This may fail for characters not supported by "unicodesymbols"
+ // or for non-ASCII characters in "listings"
+ // but it is the best we can do.
- // change encoding (not required with UTF8)
- if (bparams.encoding().iconvName() != "UTF-8") {
- 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);
- }
+ // change encoding
+ LYXERR(Debug::LATEX, "Changing LaTeX encoding from "
+ << oldEnc.name() << " to " << newEnc.name());
+ os << setEncoding(newEnc.iconvName());
+ if (bparams.inputenc == "auto-legacy-plain")
+ return make_pair(true, 0);
docstring const inputenc_arg(from_ascii(newEnc.latexName()));
OutputState * state = getOutputState();
switch (newEnc.package()) {
case Encoding::none:
case Encoding::japanese:
- // shouldn't ever reach here, see above
+ // shouldn't ever reach here (see above) but avoids warning.
return make_pair(true, 0);
case Encoding::inputenc: {
- int count = inputenc_arg.length();
+ size_t count = inputenc_arg.length();
if (oldEnc.package() == Encoding::CJK &&
state->open_encoding_ == CJK) {
os << "\\end{CJK}";
state->open_encoding_ = none;
count += 7;
}
- if (runparams.local_font != 0
+ if (runparams.local_font != nullptr
&& oldEnc.package() == Encoding::CJK) {
// within insets, \inputenc switches need
// to be embraced within \bgroup...\egroup;
count += 7;
state->open_encoding_ = inputenc;
}
- // with the japanese option, inputenc is omitted.
- if (runparams.use_japanese || noswitchmacro)
+ if (noswitchmacro)
return make_pair(true, count);
os << "\\inputencoding{" << inputenc_arg << '}';
return make_pair(true, count + 16);
}
case Encoding::CJK: {
- int count = inputenc_arg.length();
+ size_t count = inputenc_arg.length();
if (oldEnc.package() == Encoding::CJK &&
state->open_encoding_ == CJK) {
os << "\\end{CJK}";
os << "\\egroup";
count += 7;
}
- docstring const cjkenc = (bparams.encoding().iconvName() == "UTF-8"
- && LaTeXFeatures::isAvailable("CJKutf8"))
- ? from_ascii("UTF8") : from_ascii(newEnc.latexName());
- os << "\\begin{CJK}{" << cjkenc << "}{"
+ os << "\\begin{CJK}{"
+ << from_ascii(newEnc.latexName()) << "}{"
<< from_ascii(bparams.fonts_cjk) << "}";
state->open_encoding_ = CJK;
return make_pair(true, count + 15);