2003-11-05 12:06:20 +00:00
|
|
|
/**
|
2007-04-26 04:41:58 +00:00
|
|
|
* \file output_latex.cpp
|
2003-11-05 12:06:20 +00:00
|
|
|
* This file is part of LyX, the document processor.
|
|
|
|
* Licence details can be found in the file COPYING.
|
|
|
|
*
|
2008-11-14 15:58:50 +00:00
|
|
|
* \author Lars Gullik Bjønnes
|
2003-11-05 12:06:20 +00:00
|
|
|
*
|
|
|
|
* Full author contact details are available in file CREDITS.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
|
|
|
#include "output_latex.h"
|
|
|
|
|
2019-04-23 06:58:01 +00:00
|
|
|
#include "BiblioInfo.h"
|
2007-04-26 04:41:58 +00:00
|
|
|
#include "Buffer.h"
|
|
|
|
#include "BufferParams.h"
|
|
|
|
#include "Encoding.h"
|
2010-10-31 01:04:03 +00:00
|
|
|
#include "Font.h"
|
2007-10-18 15:29:51 +00:00
|
|
|
#include "InsetList.h"
|
2007-04-26 04:41:58 +00:00
|
|
|
#include "Language.h"
|
|
|
|
#include "LyXRC.h"
|
|
|
|
#include "OutputParams.h"
|
|
|
|
#include "Paragraph.h"
|
2003-11-05 12:06:20 +00:00
|
|
|
#include "ParagraphParameters.h"
|
2016-06-19 02:39:38 +00:00
|
|
|
#include "texstream.h"
|
2007-11-07 23:25:08 +00:00
|
|
|
#include "TextClass.h"
|
2003-11-05 12:06:20 +00:00
|
|
|
|
2007-04-25 01:24:38 +00:00
|
|
|
#include "insets/InsetBibitem.h"
|
2010-06-04 22:44:58 +00:00
|
|
|
#include "insets/InsetArgument.h"
|
2003-11-05 12:06:20 +00:00
|
|
|
|
2016-08-17 02:09:57 +00:00
|
|
|
#include "frontends/alert.h"
|
|
|
|
|
2008-04-30 08:26:40 +00:00
|
|
|
#include "support/lassert.h"
|
2012-11-19 13:21:02 +00:00
|
|
|
#include "support/convert.h"
|
2008-02-18 07:14:42 +00:00
|
|
|
#include "support/debug.h"
|
2003-11-05 12:06:20 +00:00
|
|
|
#include "support/lstrings.h"
|
2012-12-30 10:58:21 +00:00
|
|
|
#include "support/textutils.h"
|
2016-08-17 02:09:57 +00:00
|
|
|
#include "support/gettext.h"
|
2003-11-05 12:06:20 +00:00
|
|
|
|
2014-07-05 12:23:43 +00:00
|
|
|
#include <QThreadStorage>
|
|
|
|
|
2010-06-04 21:50:08 +00:00
|
|
|
#include <list>
|
2016-09-24 01:15:02 +00:00
|
|
|
#include <stack>
|
2006-10-21 00:16:43 +00:00
|
|
|
|
2007-12-12 10:16:00 +00:00
|
|
|
using namespace std;
|
2007-12-12 18:57:56 +00:00
|
|
|
using namespace lyx::support;
|
2007-12-12 10:16:00 +00:00
|
|
|
|
2008-04-10 21:49:34 +00:00
|
|
|
|
2006-10-21 00:16:43 +00:00
|
|
|
namespace lyx {
|
|
|
|
|
2003-11-05 12:06:20 +00:00
|
|
|
namespace {
|
|
|
|
|
2007-12-08 11:21:00 +00:00
|
|
|
enum OpenEncoding {
|
2012-10-27 13:45:27 +00:00
|
|
|
none,
|
|
|
|
inputenc,
|
|
|
|
CJK
|
2008-03-21 22:51:36 +00:00
|
|
|
};
|
2007-12-08 11:21:00 +00:00
|
|
|
|
2014-07-05 12:23:43 +00:00
|
|
|
|
|
|
|
struct OutputState
|
|
|
|
{
|
2020-10-13 21:24:36 +00:00
|
|
|
OutputState() : prev_env_language_(nullptr), open_encoding_(none),
|
|
|
|
cjk_inherited_(0), nest_level_(0)
|
2014-07-05 12:23:43 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
Language const * prev_env_language_;
|
2016-09-24 01:15:02 +00:00
|
|
|
stack<int> lang_switch_depth_; // Both are always empty when
|
|
|
|
stack<string> open_polyglossia_lang_; // not using polyglossia
|
2020-10-13 21:24:36 +00:00
|
|
|
OpenEncoding open_encoding_;
|
|
|
|
int cjk_inherited_;
|
|
|
|
int nest_level_;
|
2014-07-05 12:23:43 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
OutputState * getOutputState()
|
|
|
|
{
|
|
|
|
// FIXME An instance of OutputState should be kept around for each export
|
|
|
|
// instead of using local thread storage
|
|
|
|
static QThreadStorage<OutputState *> outputstate;
|
|
|
|
if (!outputstate.hasLocalData())
|
|
|
|
outputstate.setLocalData(new OutputState);
|
|
|
|
return outputstate.localData();
|
|
|
|
}
|
2007-12-08 11:21:00 +00:00
|
|
|
|
|
|
|
|
2017-05-30 15:49:59 +00:00
|
|
|
string const & openLanguageName(OutputState const * state)
|
2016-09-24 01:15:02 +00:00
|
|
|
{
|
|
|
|
// Return a reference to the last active language opened with
|
2017-05-30 15:49:59 +00:00
|
|
|
// polyglossia or when using begin/end commands. If none or when
|
|
|
|
// using babel with only a begin command, return a reference to
|
|
|
|
// an empty string.
|
2016-09-24 01:15:02 +00:00
|
|
|
|
|
|
|
static string const empty;
|
|
|
|
|
|
|
|
return state->open_polyglossia_lang_.empty()
|
|
|
|
? empty
|
|
|
|
: state->open_polyglossia_lang_.top();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool atSameLastLangSwitchDepth(OutputState const * state)
|
|
|
|
{
|
|
|
|
// Return true if the actual nest level is the same at which the
|
2017-05-30 15:49:59 +00:00
|
|
|
// language was switched when using polyglossia or begin/end
|
|
|
|
// commands. Instead, return always true when using babel with
|
|
|
|
// only a begin command.
|
2016-09-24 01:15:02 +00:00
|
|
|
|
2020-10-05 10:38:09 +00:00
|
|
|
return state->lang_switch_depth_.empty()
|
2016-09-24 01:15:02 +00:00
|
|
|
? true
|
2016-09-27 21:00:29 +00:00
|
|
|
: abs(state->lang_switch_depth_.top()) == state->nest_level_;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool isLocalSwitch(OutputState const * state)
|
|
|
|
{
|
2017-05-30 15:49:59 +00:00
|
|
|
// Return true if the language was opened by a local command switch.
|
2016-09-27 21:00:29 +00:00
|
|
|
|
2020-10-05 10:38:09 +00:00
|
|
|
return !state->lang_switch_depth_.empty()
|
2016-09-27 21:00:29 +00:00
|
|
|
&& state->lang_switch_depth_.top() < 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool langOpenedAtThisLevel(OutputState const * state)
|
|
|
|
{
|
|
|
|
// Return true if the language was opened at the current nesting level.
|
|
|
|
|
2020-10-05 10:38:09 +00:00
|
|
|
return !state->lang_switch_depth_.empty()
|
2016-09-27 21:00:29 +00:00
|
|
|
&& abs(state->lang_switch_depth_.top()) == state->nest_level_;
|
2016-09-24 01:15:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-11-22 12:10:16 +00:00
|
|
|
string const getPolyglossiaEnvName(Language const * lang)
|
|
|
|
{
|
|
|
|
string result = lang->polyglossia();
|
|
|
|
if (result == "arabic")
|
|
|
|
// exceptional spelling; see polyglossia docs.
|
|
|
|
result = "Arabic";
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-05-03 14:08:14 +00:00
|
|
|
string const getPolyglossiaBegin(string const & lang_begin_command,
|
2018-03-06 14:31:43 +00:00
|
|
|
string const & lang, string const & opts,
|
|
|
|
bool const localswitch = false)
|
2015-05-03 14:08:14 +00:00
|
|
|
{
|
|
|
|
string result;
|
2018-03-06 14:31:43 +00:00
|
|
|
if (!lang.empty()) {
|
|
|
|
// we need to revert the upcasing done in getPolyglossiaEnvName()
|
|
|
|
// in case we have a local polyglossia command (\textarabic).
|
|
|
|
string language = localswitch ? ascii_lowercase(lang) : lang;
|
|
|
|
result = subst(lang_begin_command, "$$lang", language);
|
|
|
|
}
|
2015-05-03 14:08:14 +00:00
|
|
|
string options = opts.empty() ?
|
|
|
|
string() : "[" + opts + "]";
|
|
|
|
result = subst(result, "$$opts", options);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-06-02 19:39:44 +00:00
|
|
|
struct TeXEnvironmentData
|
2003-11-05 12:06:20 +00:00
|
|
|
{
|
2010-12-15 23:39:38 +00:00
|
|
|
Layout const * style;
|
|
|
|
Language const * par_language;
|
|
|
|
Encoding const * prev_encoding;
|
2020-10-13 21:24:36 +00:00
|
|
|
bool cjk_nested;
|
2010-12-15 23:39:38 +00:00
|
|
|
bool leftindent_open;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2011-06-02 19:39:44 +00:00
|
|
|
static TeXEnvironmentData prepareEnvironment(Buffer const & buf,
|
2011-02-10 20:02:48 +00:00
|
|
|
Text const & text,
|
|
|
|
ParagraphList::const_iterator pit,
|
|
|
|
otexstream & os,
|
|
|
|
OutputParams const & runparams)
|
2010-12-15 23:39:38 +00:00
|
|
|
{
|
2011-06-02 19:39:44 +00:00
|
|
|
TeXEnvironmentData data;
|
2003-11-05 12:06:20 +00:00
|
|
|
|
|
|
|
BufferParams const & bparams = buf.params();
|
|
|
|
|
2008-10-31 15:33:48 +00:00
|
|
|
// FIXME This test should not be necessary.
|
|
|
|
// We should perhaps issue an error if it is.
|
2009-08-09 16:19:43 +00:00
|
|
|
Layout const & style = text.inset().forcePlainLayout() ?
|
2008-08-01 20:57:27 +00:00
|
|
|
bparams.documentClass().plainLayout() : pit->layout();
|
2003-11-05 12:06:20 +00:00
|
|
|
|
2008-01-25 13:27:08 +00:00
|
|
|
ParagraphList const & paragraphs = text.paragraphs();
|
2021-12-29 15:07:40 +00:00
|
|
|
bool const firstpar = pit == paragraphs.begin();
|
2009-07-30 00:58:37 +00:00
|
|
|
ParagraphList::const_iterator const priorpit =
|
2021-12-29 15:07:40 +00:00
|
|
|
firstpar ? pit : prev(pit, 1);
|
2009-07-30 00:58:37 +00:00
|
|
|
|
2014-07-05 12:23:43 +00:00
|
|
|
OutputState * state = getOutputState();
|
2019-07-06 19:05:16 +00:00
|
|
|
bool const use_prev_env_language = state->prev_env_language_ != nullptr
|
2009-07-30 03:21:04 +00:00
|
|
|
&& priorpit->layout().isEnvironment()
|
2009-07-30 00:58:37 +00:00
|
|
|
&& (priorpit->getDepth() > pit->getDepth()
|
|
|
|
|| (priorpit->getDepth() == pit->getDepth()
|
|
|
|
&& priorpit->layout() != pit->layout()));
|
2008-01-25 13:27:08 +00:00
|
|
|
|
2010-12-15 23:39:38 +00:00
|
|
|
data.prev_encoding = runparams.encoding;
|
|
|
|
data.par_language = pit->getParLanguage(bparams);
|
2007-03-12 17:19:08 +00:00
|
|
|
Language const * const doc_language = bparams.language;
|
|
|
|
Language const * const prev_par_language =
|
2021-12-29 15:07:40 +00:00
|
|
|
// use font at inset or document language in first paragraph
|
|
|
|
firstpar ? (runparams.local_font ?
|
|
|
|
runparams.local_font->language()
|
|
|
|
: doc_language)
|
|
|
|
: (use_prev_env_language ?
|
|
|
|
state->prev_env_language_
|
|
|
|
: priorpit->getParLanguage(bparams));
|
2011-06-02 19:55:08 +00:00
|
|
|
|
2012-06-23 13:41:05 +00:00
|
|
|
bool const use_polyglossia = runparams.use_polyglossia;
|
|
|
|
string const par_lang = use_polyglossia ?
|
2011-06-02 19:55:08 +00:00
|
|
|
getPolyglossiaEnvName(data.par_language) : data.par_language->babel();
|
2012-06-23 13:41:05 +00:00
|
|
|
string const prev_par_lang = use_polyglossia ?
|
2011-06-02 19:55:08 +00:00
|
|
|
getPolyglossiaEnvName(prev_par_language) : prev_par_language->babel();
|
2012-06-23 13:41:05 +00:00
|
|
|
string const doc_lang = use_polyglossia ?
|
2011-06-02 19:55:08 +00:00
|
|
|
getPolyglossiaEnvName(doc_language) : doc_language->babel();
|
2012-06-23 13:41:05 +00:00
|
|
|
string const lang_begin_command = use_polyglossia ?
|
2011-06-02 19:55:08 +00:00
|
|
|
"\\begin{$$lang}" : lyxrc.language_command_begin;
|
2012-06-23 13:41:05 +00:00
|
|
|
string const lang_end_command = use_polyglossia ?
|
2011-06-02 19:55:08 +00:00
|
|
|
"\\end{$$lang}" : lyxrc.language_command_end;
|
2017-05-30 15:49:59 +00:00
|
|
|
bool const using_begin_end = use_polyglossia ||
|
|
|
|
!lang_end_command.empty();
|
2003-11-05 12:06:20 +00:00
|
|
|
|
2016-09-24 01:15:02 +00:00
|
|
|
// For polyglossia, switch language outside of environment, if possible.
|
2021-12-29 15:07:40 +00:00
|
|
|
// However, if we are at the start of an inset, do not close languages
|
|
|
|
// opened outside.
|
2010-11-22 12:10:16 +00:00
|
|
|
if (par_lang != prev_par_lang) {
|
2021-12-29 15:07:40 +00:00
|
|
|
if (!firstpar
|
|
|
|
&& (!using_begin_end || langOpenedAtThisLevel(state))
|
|
|
|
&& !lang_end_command.empty()
|
|
|
|
&& prev_par_lang != doc_lang
|
|
|
|
&& !prev_par_lang.empty()) {
|
2006-10-21 00:16:43 +00:00
|
|
|
os << from_ascii(subst(
|
2010-11-22 12:10:16 +00:00
|
|
|
lang_end_command,
|
2006-10-19 16:51:30 +00:00
|
|
|
"$$lang",
|
2010-11-22 12:10:16 +00:00
|
|
|
prev_par_lang))
|
|
|
|
// the '%' is necessary to prevent unwanted whitespace
|
|
|
|
<< "%\n";
|
2017-05-30 15:49:59 +00:00
|
|
|
if (using_begin_end)
|
|
|
|
popLanguageName();
|
2003-11-05 12:06:20 +00:00
|
|
|
}
|
|
|
|
|
2016-09-27 19:41:13 +00:00
|
|
|
// If no language was explicitly opened and we are using
|
2017-05-30 15:49:59 +00:00
|
|
|
// polyglossia or begin/end commands, then the current
|
|
|
|
// language is the document language.
|
|
|
|
string const & cur_lang = using_begin_end
|
2020-10-05 10:38:09 +00:00
|
|
|
&& !state->lang_switch_depth_.empty()
|
2017-05-30 15:49:59 +00:00
|
|
|
? openLanguageName(state)
|
2016-09-27 19:41:13 +00:00
|
|
|
: doc_lang;
|
|
|
|
|
2010-12-08 18:25:21 +00:00
|
|
|
if ((lang_end_command.empty() ||
|
2016-09-24 01:15:02 +00:00
|
|
|
par_lang != doc_lang ||
|
2017-05-30 15:49:59 +00:00
|
|
|
par_lang != cur_lang) &&
|
2010-11-22 12:10:16 +00:00
|
|
|
!par_lang.empty()) {
|
2015-05-03 14:08:14 +00:00
|
|
|
string bc = use_polyglossia ?
|
|
|
|
getPolyglossiaBegin(lang_begin_command, par_lang,
|
|
|
|
data.par_language->polyglossiaOpts())
|
|
|
|
: subst(lang_begin_command, "$$lang", par_lang);
|
|
|
|
os << bc;
|
|
|
|
// the '%' is necessary to prevent unwanted whitespace
|
|
|
|
os << "%\n";
|
2017-05-30 15:49:59 +00:00
|
|
|
if (using_begin_end)
|
|
|
|
pushLanguageName(par_lang);
|
2003-11-05 12:06:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-12-15 23:39:38 +00:00
|
|
|
data.leftindent_open = false;
|
2003-11-05 12:06:20 +00:00
|
|
|
if (!pit->params().leftIndent().zero()) {
|
2006-10-19 16:51:30 +00:00
|
|
|
os << "\\begin{LyXParagraphLeftIndent}{"
|
2006-10-21 00:16:43 +00:00
|
|
|
<< from_ascii(pit->params().leftIndent().asLatexString())
|
2006-10-19 16:51:30 +00:00
|
|
|
<< "}\n";
|
2010-12-15 23:39:38 +00:00
|
|
|
data.leftindent_open = true;
|
2003-11-05 12:06:20 +00:00
|
|
|
}
|
|
|
|
|
2017-05-05 21:48:20 +00:00
|
|
|
if (style.isEnvironment())
|
2016-09-24 01:15:02 +00:00
|
|
|
state->nest_level_ += 1;
|
2017-05-05 21:48:20 +00:00
|
|
|
|
|
|
|
if (style.isEnvironment() && !style.latexname().empty()) {
|
2008-10-31 01:26:11 +00:00
|
|
|
os << "\\begin{" << from_ascii(style.latexname()) << '}';
|
2012-11-28 18:02:07 +00:00
|
|
|
if (!style.latexargs().empty()) {
|
2012-12-23 16:37:50 +00:00
|
|
|
OutputParams rp = runparams;
|
|
|
|
rp.local_font = &pit->getFirstFontSettings(bparams);
|
|
|
|
latexArgInsets(paragraphs, pit, os, rp, style.latexargs());
|
2012-11-28 18:02:07 +00:00
|
|
|
}
|
2008-03-06 21:31:27 +00:00
|
|
|
if (style.latextype == LATEX_LIST_ENVIRONMENT) {
|
2006-10-19 16:51:30 +00:00
|
|
|
os << '{'
|
2006-10-20 19:26:23 +00:00
|
|
|
<< pit->params().labelWidthString()
|
2006-10-19 16:51:30 +00:00
|
|
|
<< "}\n";
|
2008-03-06 21:31:27 +00:00
|
|
|
} else if (style.labeltype == LABEL_BIBLIO) {
|
2009-05-25 08:13:56 +00:00
|
|
|
if (pit->params().labelWidthString().empty())
|
2010-02-12 16:08:30 +00:00
|
|
|
os << '{' << bibitemWidest(buf, runparams) << "}\n";
|
2009-05-25 08:13:56 +00:00
|
|
|
else
|
|
|
|
os << '{'
|
|
|
|
<< pit->params().labelWidthString()
|
|
|
|
<< "}\n";
|
2003-11-05 12:06:20 +00:00
|
|
|
} else
|
2008-03-06 21:31:27 +00:00
|
|
|
os << from_ascii(style.latexparam()) << '\n';
|
2018-08-17 08:22:32 +00:00
|
|
|
if (style.latextype == LATEX_BIB_ENVIRONMENT
|
|
|
|
|| style.latextype == LATEX_ITEM_ENVIRONMENT
|
|
|
|
|| style.latextype == LATEX_LIST_ENVIRONMENT) {
|
|
|
|
OutputParams rp = runparams;
|
|
|
|
rp.local_font = &pit->getFirstFontSettings(bparams);
|
|
|
|
latexArgInsets(paragraphs, pit, os, rp, style.listpreamble(),
|
|
|
|
"listpreamble:");
|
|
|
|
}
|
2003-11-05 12:06:20 +00:00
|
|
|
}
|
2010-12-15 23:39:38 +00:00
|
|
|
data.style = &style;
|
2007-12-08 11:21:00 +00:00
|
|
|
|
|
|
|
// in multilingual environments, the CJK tags have to be nested properly
|
2010-12-15 23:39:38 +00:00
|
|
|
data.cjk_nested = false;
|
2019-05-11 16:59:42 +00:00
|
|
|
if (!bparams.useNonTeXFonts
|
|
|
|
&& (bparams.inputenc == "auto-legacy"
|
2019-05-25 23:45:35 +00:00
|
|
|
|| bparams.inputenc == "auto-legacy-plain")
|
2019-05-11 16:59:42 +00:00
|
|
|
&& data.par_language->encoding()->package() == Encoding::CJK
|
|
|
|
&& state->open_encoding_ != CJK && pit->isMultiLingual(bparams)) {
|
2019-01-06 13:36:11 +00:00
|
|
|
if (prev_par_language->encoding()->package() == Encoding::CJK) {
|
2019-02-05 10:31:27 +00:00
|
|
|
os << "\\begin{CJK}{"
|
|
|
|
<< from_ascii(data.par_language->encoding()->latexName())
|
2010-11-26 18:32:29 +00:00
|
|
|
<< "}{" << from_ascii(bparams.fonts_cjk) << "}%\n";
|
2019-01-06 13:36:11 +00:00
|
|
|
}
|
2014-07-05 12:23:43 +00:00
|
|
|
state->open_encoding_ = CJK;
|
2010-12-15 23:39:38 +00:00
|
|
|
data.cjk_nested = true;
|
|
|
|
}
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-27 23:07:47 +00:00
|
|
|
static void finishEnvironment(otexstream & os, OutputParams const & runparams,
|
2021-12-29 15:07:40 +00:00
|
|
|
TeXEnvironmentData const & data, bool const maintext,
|
|
|
|
bool const lastpar)
|
2010-12-15 23:39:38 +00:00
|
|
|
{
|
2014-07-05 12:23:43 +00:00
|
|
|
OutputState * state = getOutputState();
|
2021-12-29 15:07:40 +00:00
|
|
|
// BufferParams const & bparams = buf.params();
|
|
|
|
// FIXME: for speedup shortcut below, would require passing of "buf" as argument
|
2014-07-05 12:23:43 +00:00
|
|
|
if (state->open_encoding_ == CJK && data.cjk_nested) {
|
2010-12-15 23:39:38 +00:00
|
|
|
// We need to close the encoding even if it does not change
|
|
|
|
// to do correct environment nesting
|
|
|
|
os << "\\end{CJK}\n";
|
2014-07-05 12:23:43 +00:00
|
|
|
state->open_encoding_ = none;
|
2010-12-15 23:39:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (data.style->isEnvironment()) {
|
2016-09-24 01:15:02 +00:00
|
|
|
os << breakln;
|
2017-05-30 15:49:59 +00:00
|
|
|
bool const using_begin_end =
|
|
|
|
runparams.use_polyglossia ||
|
|
|
|
!lyxrc.language_command_end.empty();
|
|
|
|
// Close any language opened at this nest level
|
|
|
|
if (using_begin_end) {
|
2016-09-27 21:00:29 +00:00
|
|
|
while (langOpenedAtThisLevel(state)) {
|
|
|
|
if (isLocalSwitch(state)) {
|
|
|
|
os << "}";
|
|
|
|
} else {
|
|
|
|
os << "\\end{"
|
2017-05-30 15:49:59 +00:00
|
|
|
<< openLanguageName(state)
|
2016-09-27 21:00:29 +00:00
|
|
|
<< "}%\n";
|
|
|
|
}
|
2017-05-30 15:49:59 +00:00
|
|
|
popLanguageName();
|
2016-09-24 01:15:02 +00:00
|
|
|
}
|
|
|
|
}
|
2020-12-03 06:46:39 +00:00
|
|
|
if (data.style->latextype == LATEX_BIB_ENVIRONMENT)
|
|
|
|
// bibliography needs a blank line after
|
|
|
|
// each item for backref to function properly
|
|
|
|
// (see #12041)
|
|
|
|
os << '\n';
|
2016-09-24 01:15:02 +00:00
|
|
|
state->nest_level_ -= 1;
|
2017-05-05 21:48:20 +00:00
|
|
|
string const & name = data.style->latexname();
|
|
|
|
if (!name.empty())
|
|
|
|
os << "\\end{" << from_ascii(name) << "}\n";
|
2014-07-05 12:23:43 +00:00
|
|
|
state->prev_env_language_ = data.par_language;
|
2010-12-15 23:39:38 +00:00
|
|
|
if (runparams.encoding != data.prev_encoding) {
|
|
|
|
runparams.encoding = data.prev_encoding;
|
2015-11-12 15:55:04 +00:00
|
|
|
os << setEncoding(data.prev_encoding->iconvName());
|
2010-12-15 23:39:38 +00:00
|
|
|
}
|
2021-12-29 15:07:40 +00:00
|
|
|
// If this is the last par of an inset, the language needs
|
|
|
|
// to be closed after the environment
|
|
|
|
if (lastpar && !maintext) {
|
|
|
|
if (using_begin_end && langOpenedAtThisLevel(state)) {
|
|
|
|
if (isLocalSwitch(state)) {
|
|
|
|
os << "}";
|
|
|
|
} else {
|
|
|
|
os << "\\end{"
|
|
|
|
<< openLanguageName(state)
|
|
|
|
<< "}%\n";
|
|
|
|
}
|
|
|
|
popLanguageName();
|
|
|
|
}
|
|
|
|
}
|
2007-12-08 11:21:00 +00:00
|
|
|
}
|
|
|
|
|
2010-12-15 23:39:38 +00:00
|
|
|
if (data.leftindent_open) {
|
Fix bugs #8546 and #9055, and introduce new separator inset.
The algorithm used for breaking a paragraph in LaTeX export is changed
for avoiding spurious blank lines causing too much vertical space.
This change is tied to the introduction of a new inset (with two
different specializations) helping in either outputing LaTeX paragraph
breaks or separating environments in LyX. Both of the above goals were
previously achieved by the ---Separator--- layout and can now be
accomplished by the new inset in a more natural way. As an example,
after leaving an environment by hitting the Return key for two times,
a third return automatically inserts a parbreak inset, which is
equivalent to the old separator layout, i.e., it also introduces a
blank line in the output. If this blank line is not wanted, the
parbreak separator can be changed to a plain separator by a right
click of the mouse. Of course, an environment can still be separated
by the following one by using the Alt+P+Return shortcut (or the
corresponding menu key), but now the plain separator inset is used
instead of the old separator layout, such that no blank line occurs in
the LaTeX output.
Old documents are converted such that the LaTeX output remains unchanged.
As a result of this conversion, the old separator layout is replaced by
the new parbreak inset, which may also appear in places where the old
algorithm was introducing blank lines while the new one is not.
Note that not all blank lines were actually affecting the LaTeX output,
because a blank line is simply ignored by the TeX engine when it occurs
in the so called "vertical mode" (e.g., after an alignment environment).
The old ---Separator--- layout is now gone and old layout files using it
are also automatically converted.
Round trip conversions between old and new format should leave a document
unchanged. This means that the new behavior about paragraph breaking is
not "carried back" to the old format. Indeed, this would need introducing
special LaTeX commands in ERT that would accumulate in roundtrip
conversions, horribly cluttering the document. So, when converting a
modified document to old formats, the LaTeX output may slightly differ in
vertical spacing if the document is processed by an old version of LyX.
In other words, forward compatibility is guaranteed, but not backwards.
2014-05-10 21:25:11 +00:00
|
|
|
os << breakln << "\\end{LyXParagraphLeftIndent}\n";
|
2014-07-05 12:23:43 +00:00
|
|
|
state->prev_env_language_ = data.par_language;
|
2010-12-15 23:39:38 +00:00
|
|
|
if (runparams.encoding != data.prev_encoding) {
|
|
|
|
runparams.encoding = data.prev_encoding;
|
2015-11-12 15:55:04 +00:00
|
|
|
os << setEncoding(data.prev_encoding->iconvName());
|
2010-12-15 23:39:38 +00:00
|
|
|
}
|
|
|
|
}
|
2014-05-16 13:39:33 +00:00
|
|
|
|
|
|
|
// Check whether we should output a blank line after the environment
|
2014-05-27 23:07:47 +00:00
|
|
|
if (!data.style->nextnoindent)
|
2014-05-16 13:39:33 +00:00
|
|
|
os << '\n';
|
2010-12-15 23:39:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-02-10 20:02:48 +00:00
|
|
|
void TeXEnvironment(Buffer const & buf, Text const & text,
|
|
|
|
OutputParams const & runparams,
|
|
|
|
pit_type & pit, otexstream & os)
|
2010-12-15 23:39:38 +00:00
|
|
|
{
|
|
|
|
ParagraphList const & paragraphs = text.paragraphs();
|
2020-05-11 10:31:25 +00:00
|
|
|
ParagraphList::const_iterator ipar = paragraphs.iterator_at(pit);
|
2022-02-27 19:35:58 +00:00
|
|
|
LYXERR(Debug::OUTFILE, "TeXEnvironment for paragraph " << pit);
|
2010-12-15 23:39:38 +00:00
|
|
|
|
2018-02-24 05:35:27 +00:00
|
|
|
Layout const & current_layout = ipar->layout();
|
|
|
|
depth_type const current_depth = ipar->params().depth();
|
|
|
|
Length const & current_left_indent = ipar->params().leftIndent();
|
2003-11-05 12:06:20 +00:00
|
|
|
|
2010-12-18 13:49:39 +00:00
|
|
|
// This is for debugging purpose at the end.
|
|
|
|
pit_type const par_begin = pit;
|
|
|
|
for (; pit < runparams.par_end; ++pit) {
|
2020-05-11 10:31:25 +00:00
|
|
|
ParagraphList::const_iterator par = paragraphs.iterator_at(pit);
|
2010-12-18 13:49:39 +00:00
|
|
|
|
|
|
|
// check first if this is an higher depth paragraph.
|
|
|
|
bool go_out = (par->params().depth() < current_depth);
|
|
|
|
if (par->params().depth() == current_depth) {
|
|
|
|
// This environment is finished.
|
|
|
|
go_out |= (par->layout() != current_layout);
|
|
|
|
go_out |= (par->params().leftIndent() != current_left_indent);
|
|
|
|
}
|
|
|
|
if (go_out) {
|
|
|
|
// nothing to do here, restore pit and go out.
|
|
|
|
pit--;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (par->layout() == current_layout
|
|
|
|
&& par->params().depth() == current_depth
|
|
|
|
&& par->params().leftIndent() == current_left_indent) {
|
|
|
|
// We are still in the same environment so TeXOnePar and continue;
|
2011-02-10 20:02:48 +00:00
|
|
|
TeXOnePar(buf, text, pit, os, runparams);
|
2010-12-18 13:49:39 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// We are now in a deeper environment.
|
|
|
|
// Either par->layout() != current_layout
|
|
|
|
// Or par->params().depth() > current_depth
|
|
|
|
// Or par->params().leftIndent() != current_left_indent)
|
|
|
|
|
|
|
|
// FIXME This test should not be necessary.
|
|
|
|
// We should perhaps issue an error if it is.
|
|
|
|
bool const force_plain_layout = text.inset().forcePlainLayout();
|
|
|
|
Layout const & style = force_plain_layout
|
|
|
|
? buf.params().documentClass().plainLayout()
|
|
|
|
: par->layout();
|
|
|
|
|
|
|
|
if (!style.isEnvironment()) {
|
|
|
|
// This is a standard paragraph, no need to call TeXEnvironment.
|
2011-02-10 20:02:48 +00:00
|
|
|
TeXOnePar(buf, text, pit, os, runparams);
|
2010-12-18 13:49:39 +00:00
|
|
|
continue;
|
2003-11-05 12:06:20 +00:00
|
|
|
}
|
|
|
|
|
2019-12-30 12:25:49 +00:00
|
|
|
// Do not output empty environments if the whole paragraph has
|
|
|
|
// been deleted with ct and changes are not output.
|
2021-01-22 20:11:28 +00:00
|
|
|
bool output_changes;
|
2022-05-09 20:06:02 +00:00
|
|
|
if (!runparams.find_effective())
|
2021-01-22 20:11:28 +00:00
|
|
|
output_changes = buf.params().output_changes;
|
|
|
|
else
|
2022-05-09 20:06:02 +00:00
|
|
|
output_changes = runparams.find_with_deleted();
|
2019-12-30 12:25:49 +00:00
|
|
|
if (size_t(pit + 1) < paragraphs.size()) {
|
2020-05-11 10:31:25 +00:00
|
|
|
ParagraphList::const_iterator nextpar = paragraphs.iterator_at(pit + 1);
|
2019-12-30 12:25:49 +00:00
|
|
|
Paragraph const & cpar = paragraphs.at(pit);
|
|
|
|
if ((par->layout() != nextpar->layout()
|
|
|
|
|| par->params().depth() == nextpar->params().depth()
|
|
|
|
|| par->params().leftIndent() == nextpar->params().leftIndent())
|
2021-01-22 16:03:54 +00:00
|
|
|
&& !cpar.empty()
|
2021-01-22 20:11:28 +00:00
|
|
|
&& cpar.isDeleted(0, cpar.size()) && !output_changes) {
|
|
|
|
if (!output_changes && !cpar.parEndChange().deleted())
|
2019-12-30 12:25:49 +00:00
|
|
|
os << '\n' << '\n';
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-12-18 13:49:39 +00:00
|
|
|
// This is a new environment.
|
2011-06-02 19:39:44 +00:00
|
|
|
TeXEnvironmentData const data =
|
|
|
|
prepareEnvironment(buf, text, par, os, runparams);
|
2010-12-18 13:49:39 +00:00
|
|
|
// Recursive call to TeXEnvironment!
|
2011-02-10 20:02:48 +00:00
|
|
|
TeXEnvironment(buf, text, runparams, pit, os);
|
2021-12-29 15:07:40 +00:00
|
|
|
bool const lastpar = size_t(pit + 1) >= paragraphs.size();
|
|
|
|
finishEnvironment(os, runparams, data, text.isMainText(), lastpar);
|
2010-12-18 13:49:39 +00:00
|
|
|
}
|
2007-11-15 20:04:51 +00:00
|
|
|
|
2010-12-18 13:49:39 +00:00
|
|
|
if (pit != runparams.par_end)
|
2022-02-27 19:35:58 +00:00
|
|
|
LYXERR(Debug::OUTFILE, "TeXEnvironment for paragraph " << par_begin << " done.");
|
2003-11-05 12:06:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-12-23 16:37:50 +00:00
|
|
|
void getArgInsets(otexstream & os, OutputParams const & runparams, Layout::LaTeXArgMap const & latexargs,
|
2020-10-13 21:24:36 +00:00
|
|
|
map<size_t, lyx::InsetArgument const *> ilist, vector<string> required, string const & prefix)
|
2003-11-05 12:06:20 +00:00
|
|
|
{
|
2020-10-13 21:24:36 +00:00
|
|
|
size_t const argnr = latexargs.size();
|
2012-11-19 13:21:02 +00:00
|
|
|
if (argnr == 0)
|
2011-02-10 20:02:48 +00:00
|
|
|
return;
|
2010-06-04 21:50:08 +00:00
|
|
|
|
2014-05-21 11:12:14 +00:00
|
|
|
// Default and preset args are always output, so if they require
|
|
|
|
// other arguments, consider this.
|
2018-02-24 05:35:27 +00:00
|
|
|
for (auto const & larg : latexargs) {
|
|
|
|
Layout::latexarg const & arg = larg.second;
|
2020-05-03 06:18:17 +00:00
|
|
|
if ((!arg.presetarg.empty() || !arg.defaultarg.empty()) && !arg.required.empty()) {
|
|
|
|
vector<string> req = getVectorFromString(arg.required);
|
2014-05-21 11:12:14 +00:00
|
|
|
required.insert(required.end(), req.begin(), req.end());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-13 21:24:36 +00:00
|
|
|
for (size_t i = 1; i <= argnr; ++i) {
|
|
|
|
map<size_t, InsetArgument const *>::const_iterator lit = ilist.find(i);
|
2012-11-19 13:21:02 +00:00
|
|
|
bool inserted = false;
|
|
|
|
if (lit != ilist.end()) {
|
2020-10-13 21:24:36 +00:00
|
|
|
InsetArgument const * ins = lit->second;
|
2012-11-19 13:21:02 +00:00
|
|
|
if (ins) {
|
|
|
|
Layout::LaTeXArgMap::const_iterator const lait =
|
2012-11-29 14:34:20 +00:00
|
|
|
latexargs.find(ins->name());
|
2012-11-19 13:21:02 +00:00
|
|
|
if (lait != latexargs.end()) {
|
2020-10-13 21:24:36 +00:00
|
|
|
Layout::latexarg arg = lait->second;
|
2018-08-17 08:22:32 +00:00
|
|
|
docstring ldelim;
|
|
|
|
docstring rdelim;
|
|
|
|
if (!arg.nodelims) {
|
|
|
|
ldelim = arg.mandatory ?
|
2012-11-19 13:21:02 +00:00
|
|
|
from_ascii("{") : from_ascii("[");
|
2018-08-17 08:22:32 +00:00
|
|
|
rdelim = arg.mandatory ?
|
2012-11-19 13:21:02 +00:00
|
|
|
from_ascii("}") : from_ascii("]");
|
2018-08-17 08:22:32 +00:00
|
|
|
}
|
2012-11-19 13:21:02 +00:00
|
|
|
if (!arg.ldelim.empty())
|
|
|
|
ldelim = arg.ldelim;
|
|
|
|
if (!arg.rdelim.empty())
|
|
|
|
rdelim = arg.rdelim;
|
2012-12-10 13:09:51 +00:00
|
|
|
ins->latexArgument(os, runparams, ldelim, rdelim, arg.presetarg);
|
2018-08-17 08:22:32 +00:00
|
|
|
if (prefix == "listpreamble:")
|
|
|
|
os << breakln;
|
2012-11-19 13:21:02 +00:00
|
|
|
inserted = true;
|
|
|
|
}
|
|
|
|
}
|
2010-06-04 21:50:08 +00:00
|
|
|
}
|
2012-11-19 13:21:02 +00:00
|
|
|
if (!inserted) {
|
|
|
|
Layout::LaTeXArgMap::const_iterator lait = latexargs.begin();
|
|
|
|
Layout::LaTeXArgMap::const_iterator const laend = latexargs.end();
|
|
|
|
for (; lait != laend; ++lait) {
|
2012-12-28 10:21:24 +00:00
|
|
|
string const name = prefix + convert<string>(i);
|
2012-11-29 14:34:20 +00:00
|
|
|
if ((*lait).first == name) {
|
2012-11-19 13:21:02 +00:00
|
|
|
Layout::latexarg arg = (*lait).second;
|
2013-02-24 10:29:21 +00:00
|
|
|
docstring preset = arg.presetarg;
|
|
|
|
if (!arg.defaultarg.empty()) {
|
|
|
|
if (!preset.empty())
|
|
|
|
preset += ",";
|
|
|
|
preset += arg.defaultarg;
|
|
|
|
}
|
2012-11-19 13:21:02 +00:00
|
|
|
if (arg.mandatory) {
|
|
|
|
docstring ldelim = arg.ldelim.empty() ?
|
|
|
|
from_ascii("{") : arg.ldelim;
|
|
|
|
docstring rdelim = arg.rdelim.empty() ?
|
|
|
|
from_ascii("}") : arg.rdelim;
|
2013-02-24 10:29:21 +00:00
|
|
|
os << ldelim << preset << rdelim;
|
|
|
|
} else if (!preset.empty()) {
|
|
|
|
docstring ldelim = arg.ldelim.empty() ?
|
|
|
|
from_ascii("[") : arg.ldelim;
|
|
|
|
docstring rdelim = arg.rdelim.empty() ?
|
|
|
|
from_ascii("]") : arg.rdelim;
|
|
|
|
os << ldelim << preset << rdelim;
|
2012-11-19 13:21:02 +00:00
|
|
|
} else if (find(required.begin(), required.end(),
|
2012-11-29 14:34:20 +00:00
|
|
|
(*lait).first) != required.end()) {
|
2012-11-19 13:21:02 +00:00
|
|
|
docstring ldelim = arg.ldelim.empty() ?
|
|
|
|
from_ascii("[") : arg.ldelim;
|
|
|
|
docstring rdelim = arg.rdelim.empty() ?
|
|
|
|
from_ascii("]") : arg.rdelim;
|
|
|
|
os << ldelim << rdelim;
|
|
|
|
} else
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2003-11-05 12:06:20 +00:00
|
|
|
}
|
|
|
|
}
|
2022-05-09 20:06:02 +00:00
|
|
|
if (runparams.find_effective() && argnr > 1) {
|
2019-02-05 07:04:47 +00:00
|
|
|
// Mark end of arguments for findadv() only
|
|
|
|
os << "\\endarguments{}";
|
|
|
|
}
|
2003-11-05 12:06:20 +00:00
|
|
|
}
|
|
|
|
|
2012-12-23 16:37:50 +00:00
|
|
|
|
2017-07-23 11:11:54 +00:00
|
|
|
} // namespace
|
2012-12-23 16:37:50 +00:00
|
|
|
|
|
|
|
|
2017-05-30 15:49:59 +00:00
|
|
|
void pushLanguageName(string const & lang_name, bool localswitch)
|
2016-09-25 06:20:34 +00:00
|
|
|
{
|
|
|
|
OutputState * state = getOutputState();
|
|
|
|
|
2016-09-27 21:00:29 +00:00
|
|
|
int nest_level = localswitch ? -state->nest_level_ : state->nest_level_;
|
|
|
|
state->lang_switch_depth_.push(nest_level);
|
2016-09-25 06:20:34 +00:00
|
|
|
state->open_polyglossia_lang_.push(lang_name);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-05-30 15:49:59 +00:00
|
|
|
void popLanguageName()
|
2016-09-25 06:20:34 +00:00
|
|
|
{
|
|
|
|
OutputState * state = getOutputState();
|
|
|
|
|
|
|
|
state->lang_switch_depth_.pop();
|
|
|
|
state->open_polyglossia_lang_.pop();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-02-04 16:23:52 +00:00
|
|
|
bool languageStackEmpty()
|
|
|
|
{
|
|
|
|
OutputState * state = getOutputState();
|
|
|
|
|
|
|
|
return state->lang_switch_depth_.empty();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-11-02 09:35:58 +00:00
|
|
|
string const & openLanguageName()
|
|
|
|
{
|
|
|
|
OutputState * state = getOutputState();
|
|
|
|
|
|
|
|
return openLanguageName(state);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-05-12 22:41:23 +00:00
|
|
|
namespace {
|
|
|
|
|
|
|
|
void addArgInsets(Paragraph const & par, string const & prefix,
|
|
|
|
Layout::LaTeXArgMap const & latexargs,
|
2020-10-13 22:26:13 +00:00
|
|
|
map<size_t, InsetArgument const *> & ilist,
|
2017-05-12 22:41:23 +00:00
|
|
|
vector<string> & required)
|
|
|
|
{
|
|
|
|
for (auto const & table : par.insetList()) {
|
|
|
|
InsetArgument const * arg = table.inset->asInsetArgument();
|
|
|
|
if (!arg)
|
|
|
|
continue;
|
|
|
|
if (arg->name().empty()) {
|
|
|
|
LYXERR0("Error: Unnamed argument inset!");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
string const name = prefix.empty() ?
|
|
|
|
arg->name() : split(arg->name(), ':');
|
2020-10-13 21:24:36 +00:00
|
|
|
size_t const nr = convert<size_t>(name);
|
2020-11-02 16:38:52 +00:00
|
|
|
ilist.insert({nr, arg});
|
2017-05-12 22:41:23 +00:00
|
|
|
Layout::LaTeXArgMap::const_iterator const lit =
|
|
|
|
latexargs.find(arg->name());
|
|
|
|
if (lit != latexargs.end()) {
|
|
|
|
Layout::latexarg const & larg = lit->second;
|
2020-05-03 06:18:17 +00:00
|
|
|
vector<string> req = getVectorFromString(larg.required);
|
2017-05-12 22:41:23 +00:00
|
|
|
move(req.begin(), req.end(), back_inserter(required));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-23 11:11:54 +00:00
|
|
|
} // namespace
|
2017-05-12 22:41:23 +00:00
|
|
|
|
|
|
|
|
2012-12-23 16:37:50 +00:00
|
|
|
void latexArgInsets(Paragraph const & par, otexstream & os,
|
2017-05-12 22:41:23 +00:00
|
|
|
OutputParams const & runparams,
|
|
|
|
Layout::LaTeXArgMap const & latexargs,
|
|
|
|
string const & prefix)
|
2012-12-23 16:37:50 +00:00
|
|
|
{
|
2020-10-13 21:24:36 +00:00
|
|
|
map<size_t, InsetArgument const *> ilist;
|
2012-12-23 16:37:50 +00:00
|
|
|
vector<string> required;
|
2017-05-12 22:41:23 +00:00
|
|
|
addArgInsets(par, prefix, latexargs, ilist, required);
|
2012-12-28 10:21:24 +00:00
|
|
|
getArgInsets(os, runparams, latexargs, ilist, required, prefix);
|
2012-12-23 16:37:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-05-12 22:41:23 +00:00
|
|
|
void latexArgInsets(ParagraphList const & pars,
|
|
|
|
ParagraphList::const_iterator pit,
|
|
|
|
otexstream & os, OutputParams const & runparams,
|
|
|
|
Layout::LaTeXArgMap const & latexargs,
|
|
|
|
string const & prefix)
|
2012-12-23 16:37:50 +00:00
|
|
|
{
|
2020-10-13 21:24:36 +00:00
|
|
|
map<size_t, InsetArgument const *> ilist;
|
2012-12-23 16:37:50 +00:00
|
|
|
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
|
2020-05-11 10:31:25 +00:00
|
|
|
ptrdiff_t offset = 0;
|
2012-12-23 16:37:50 +00:00
|
|
|
while (true) {
|
2020-05-11 10:31:25 +00:00
|
|
|
if (prev(pit, offset) == pars.begin())
|
2012-12-23 16:37:50 +00:00
|
|
|
break;
|
2020-05-11 10:31:25 +00:00
|
|
|
ParagraphList::const_iterator priorpit = prev(pit, offset + 1);
|
2012-12-23 16:37:50 +00:00
|
|
|
if (priorpit->layout() == current_layout
|
|
|
|
&& priorpit->params().depth() == current_depth)
|
|
|
|
++offset;
|
|
|
|
else
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2020-05-11 10:31:25 +00:00
|
|
|
ParagraphList::const_iterator spit = prev(pit, offset);
|
2012-12-23 16:37:50 +00:00
|
|
|
for (; spit != pars.end(); ++spit) {
|
2017-05-12 22:41:23 +00:00
|
|
|
if (spit->layout() != current_layout ||
|
|
|
|
spit->params().depth() < current_depth)
|
2012-12-23 16:37:50 +00:00
|
|
|
break;
|
2012-12-24 12:02:24 +00:00
|
|
|
if (spit->params().depth() > current_depth)
|
|
|
|
continue;
|
2017-05-12 22:41:23 +00:00
|
|
|
addArgInsets(*spit, prefix, latexargs, ilist, required);
|
2012-12-23 16:37:50 +00:00
|
|
|
}
|
2012-12-28 10:21:24 +00:00
|
|
|
getArgInsets(os, runparams, latexargs, ilist, required, prefix);
|
2012-12-23 16:37:50 +00:00
|
|
|
}
|
|
|
|
|
2017-05-12 21:13:38 +00:00
|
|
|
|
2017-05-12 22:51:21 +00:00
|
|
|
void latexArgInsetsForParent(ParagraphList const & pars, otexstream & os,
|
|
|
|
OutputParams const & runparams,
|
|
|
|
Layout::LaTeXArgMap const & latexargs,
|
|
|
|
string const & prefix)
|
|
|
|
{
|
2020-10-13 21:24:36 +00:00
|
|
|
map<size_t, InsetArgument const *> ilist;
|
2017-05-12 22:51:21 +00:00
|
|
|
vector<string> required;
|
|
|
|
|
|
|
|
for (Paragraph const & par : pars) {
|
|
|
|
if (par.layout().hasArgs())
|
|
|
|
// The InsetArguments inside this paragraph refer to this paragraph
|
|
|
|
continue;
|
|
|
|
addArgInsets(par, prefix, latexargs, ilist, required);
|
|
|
|
}
|
|
|
|
getArgInsets(os, runparams, latexargs, ilist, required, prefix);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-01-25 11:22:47 +00:00
|
|
|
namespace {
|
|
|
|
|
|
|
|
// output the proper paragraph start according to latextype.
|
2011-02-10 20:02:48 +00:00
|
|
|
void parStartCommand(Paragraph const & par, otexstream & os,
|
2017-07-03 17:53:14 +00:00
|
|
|
OutputParams const & runparams, Layout const & style)
|
2011-01-25 11:22:47 +00:00
|
|
|
{
|
|
|
|
switch (style.latextype) {
|
|
|
|
case LATEX_COMMAND:
|
2019-08-14 12:00:29 +00:00
|
|
|
if (par.needsCProtection(runparams.moving_arg)) {
|
|
|
|
if (contains(runparams.active_chars, '^'))
|
2019-08-14 16:32:34 +00:00
|
|
|
// cprotect relies on ^ being on catcode 7
|
|
|
|
os << "\\begingroup\\catcode`\\^=7";
|
2018-04-13 15:46:37 +00:00
|
|
|
os << "\\cprotect";
|
2019-08-14 12:00:29 +00:00
|
|
|
}
|
2011-01-25 11:22:47 +00:00
|
|
|
os << '\\' << from_ascii(style.latexname());
|
|
|
|
|
2012-11-29 14:34:20 +00:00
|
|
|
// Command arguments
|
2012-11-24 01:40:38 +00:00
|
|
|
if (!style.latexargs().empty())
|
2012-11-19 13:21:02 +00:00
|
|
|
latexArgInsets(par, os, runparams, style.latexargs());
|
2012-11-26 12:09:54 +00:00
|
|
|
os << from_ascii(style.latexparam());
|
2011-01-25 11:22:47 +00:00
|
|
|
break;
|
|
|
|
case LATEX_ITEM_ENVIRONMENT:
|
|
|
|
case LATEX_LIST_ENVIRONMENT:
|
2022-05-09 20:06:02 +00:00
|
|
|
if (runparams.find_effective()) {
|
2018-11-03 14:00:58 +00:00
|
|
|
os << "\\" + style.itemcommand() << "{" << style.latexname() << "}";
|
2018-11-03 10:15:12 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
os << "\\" + style.itemcommand();
|
|
|
|
// Item arguments
|
|
|
|
if (!style.itemargs().empty())
|
|
|
|
latexArgInsets(par, os, runparams, style.itemargs(), "item:");
|
|
|
|
os << " ";
|
|
|
|
}
|
2011-01-25 11:22:47 +00:00
|
|
|
break;
|
2019-02-20 13:14:50 +00:00
|
|
|
case LATEX_ENVIRONMENT:
|
2022-05-09 20:06:02 +00:00
|
|
|
if (runparams.find_effective()) {
|
2019-02-20 13:14:50 +00:00
|
|
|
os << "\\latexenvironment{" << style.latexname() << "}{";
|
|
|
|
}
|
|
|
|
break;
|
2011-01-25 11:22:47 +00:00
|
|
|
case LATEX_BIB_ENVIRONMENT:
|
|
|
|
// ignore this, the inset will write itself
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-23 11:11:54 +00:00
|
|
|
} // namespace
|
2010-06-04 21:50:08 +00:00
|
|
|
|
2008-11-16 00:12:21 +00:00
|
|
|
// FIXME: this should be anonymous
|
2010-12-15 20:51:25 +00:00
|
|
|
void TeXOnePar(Buffer const & buf,
|
2011-02-10 20:02:48 +00:00
|
|
|
Text const & text,
|
|
|
|
pit_type pit,
|
|
|
|
otexstream & os,
|
|
|
|
OutputParams const & runparams_in,
|
|
|
|
string const & everypar,
|
2017-12-26 12:11:00 +00:00
|
|
|
int start_pos, int end_pos,
|
|
|
|
bool const force)
|
2003-11-05 12:06:20 +00:00
|
|
|
{
|
2013-11-18 07:46:50 +00:00
|
|
|
BufferParams const & bparams = runparams_in.is_child
|
2014-03-13 05:43:38 +00:00
|
|
|
? buf.masterParams() : buf.params();
|
2010-12-18 15:57:27 +00:00
|
|
|
ParagraphList const & paragraphs = text.paragraphs();
|
|
|
|
Paragraph const & par = paragraphs.at(pit);
|
2010-06-15 15:37:39 +00:00
|
|
|
// FIXME This check should not really be needed.
|
|
|
|
// Perhaps we should issue an error if it is.
|
2014-08-12 16:32:01 +00:00
|
|
|
Layout const & style = text.inset().forcePlainLayout() ?
|
2010-12-18 15:57:27 +00:00
|
|
|
bparams.documentClass().plainLayout() : par.layout();
|
2008-03-21 22:51:36 +00:00
|
|
|
|
2017-12-26 12:11:00 +00:00
|
|
|
if (style.inpreamble && !force)
|
2010-12-15 20:51:25 +00:00
|
|
|
return;
|
2010-06-15 15:37:39 +00:00
|
|
|
|
2019-12-26 11:26:32 +00:00
|
|
|
// Do not output empty commands if the whole paragraph has
|
|
|
|
// been deleted with ct and changes are not output.
|
2022-05-09 20:06:02 +00:00
|
|
|
if (!runparams_in.find_with_deleted() && style.latextype != LATEX_ENVIRONMENT
|
2020-10-05 10:38:09 +00:00
|
|
|
&& !par.empty() && par.isDeleted(0, par.size()) && !bparams.output_changes)
|
2019-12-26 11:26:32 +00:00
|
|
|
return;
|
|
|
|
|
2022-02-27 19:35:58 +00:00
|
|
|
LYXERR(Debug::OUTFILE, "TeXOnePar for paragraph " << pit << " ptr " << &par << " '"
|
|
|
|
<< everypar << "'");
|
2010-12-18 13:49:39 +00:00
|
|
|
|
2008-09-18 14:51:16 +00:00
|
|
|
OutputParams runparams = runparams_in;
|
2010-12-20 00:57:16 +00:00
|
|
|
runparams.isLastPar = (pit == pit_type(paragraphs.size() - 1));
|
2019-05-13 08:42:41 +00:00
|
|
|
// We reinitialize par begin and end to be on the safe side
|
2010-12-18 14:04:02 +00:00
|
|
|
// with embedded inset as we don't know if they set those
|
|
|
|
// value correctly.
|
|
|
|
runparams.par_begin = 0;
|
|
|
|
runparams.par_end = 0;
|
2008-09-18 14:51:16 +00:00
|
|
|
|
2010-02-09 14:01:21 +00:00
|
|
|
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.
|
2014-07-05 12:23:43 +00:00
|
|
|
OutputState * state = getOutputState();
|
2010-12-18 15:57:27 +00:00
|
|
|
if (pit == 0 && !maintext
|
2014-07-05 12:23:43 +00:00
|
|
|
&& (state->cjk_inherited_ > 0 || state->open_encoding_ == CJK)) {
|
|
|
|
state->cjk_inherited_ += 1;
|
|
|
|
state->open_encoding_ = none;
|
2010-02-09 14:01:21 +00:00
|
|
|
}
|
|
|
|
|
2019-12-26 12:47:50 +00:00
|
|
|
// This paragraph is merged and we do not show changes in the output
|
|
|
|
bool const merged_par = !bparams.output_changes && par.parEndChange().deleted();
|
|
|
|
|
2012-11-28 18:02:07 +00:00
|
|
|
if (text.inset().isPassThru()) {
|
2010-12-18 15:57:27 +00:00
|
|
|
Font const outerfont = text.outerFont(pit);
|
2007-10-30 16:22:56 +00:00
|
|
|
|
2010-11-06 15:06:19 +00:00
|
|
|
// No newline before first paragraph in this lyxtext
|
2019-12-26 12:47:50 +00:00
|
|
|
if (pit > 0 && !text.inset().getLayout().parbreakIgnored() && !merged_par) {
|
2007-10-30 16:22:56 +00:00
|
|
|
os << '\n';
|
2011-02-10 20:02:48 +00:00
|
|
|
if (!text.inset().getLayout().parbreakIsNewline())
|
2010-11-06 15:06:19 +00:00
|
|
|
os << '\n';
|
2007-10-30 16:22:56 +00:00
|
|
|
}
|
2007-10-24 07:13:20 +00:00
|
|
|
|
2017-12-26 12:11:00 +00:00
|
|
|
par.latex(bparams, outerfont, os, runparams, start_pos, end_pos, force);
|
2010-12-15 20:51:25 +00:00
|
|
|
return;
|
2007-10-23 18:23:03 +00:00
|
|
|
}
|
|
|
|
|
2010-12-18 15:57:27 +00:00
|
|
|
Paragraph const * nextpar = runparams.isLastPar
|
2019-07-06 19:05:16 +00:00
|
|
|
? nullptr : ¶graphs.at(pit + 1);
|
2010-12-18 15:57:27 +00:00
|
|
|
|
2019-08-16 09:48:57 +00:00
|
|
|
bool const intitle_command = style.intitle && style.isCommand();
|
2019-11-21 07:38:21 +00:00
|
|
|
// Intitle commands switch languages locally, thus increase
|
|
|
|
// language nesting level
|
|
|
|
if (intitle_command)
|
|
|
|
state->nest_level_ += 1;
|
2017-12-27 10:49:54 +00:00
|
|
|
|
2010-11-06 15:06:19 +00:00
|
|
|
if (style.pass_thru) {
|
2010-12-18 15:57:27 +00:00
|
|
|
Font const outerfont = text.outerFont(pit);
|
2011-02-10 20:02:48 +00:00
|
|
|
parStartCommand(par, os, runparams, style);
|
2019-03-14 13:24:43 +00:00
|
|
|
if (style.isCommand() && style.needprotect)
|
|
|
|
// Due to the moving argument, some fragile
|
|
|
|
// commands (labels, index entries)
|
|
|
|
// are output after this command (#2154)
|
2020-01-10 09:21:09 +00:00
|
|
|
runparams.postpone_fragile_stuff =
|
|
|
|
bparams.postpone_fragile_content;
|
2017-12-27 10:49:54 +00:00
|
|
|
if (intitle_command)
|
|
|
|
os << '{';
|
2011-01-16 19:14:14 +00:00
|
|
|
|
2017-12-26 12:11:00 +00:00
|
|
|
par.latex(bparams, outerfont, os, runparams, start_pos, end_pos, force);
|
2011-01-25 11:22:47 +00:00
|
|
|
|
|
|
|
// I did not create a parEndCommand for this minuscule
|
|
|
|
// task because in the other user of parStartCommand
|
|
|
|
// the code is different (JMarc)
|
2019-08-14 12:00:29 +00:00
|
|
|
if (style.isCommand()) {
|
|
|
|
os << "}";
|
|
|
|
if (par.needsCProtection(runparams.moving_arg)
|
|
|
|
&& contains(runparams.active_chars, '^'))
|
|
|
|
os << "\\endgroup";
|
2019-12-26 12:47:50 +00:00
|
|
|
if (merged_par)
|
|
|
|
os << "{}";
|
|
|
|
else
|
|
|
|
os << "\n";
|
2019-08-14 12:00:29 +00:00
|
|
|
}
|
2019-12-26 12:47:50 +00:00
|
|
|
else if (!merged_par)
|
Introduce a wrapper class for odocstream to help ensuring that no
blank lines may be inadvertently output. This is achieved by using two
special iomanip-like variables (breakln and safebreakln) in the lyx::
namespace. When they are inserted in the stream, a newline is output
only if not already at the beginning of a line. The difference between
breakln and safebreakln is that, if needed, the former outputs '\n'
and the latter "%\n".
In future, the new class will also be used for counting the number of
newlines issued. Even if the infractrure for doing that is already in
place, the counting is essentially still done the old way.
There are still places in the code where the functionality of the
class could be used, most probably. ATM, it is used for InsetTabular,
InsetListings, InsetFloat, and InsetText.
The Comment and GreyedOut insets required a special treatment and a
new InsetLayout parameter (Display) has been introduced. The default
for Display is "true", meaning that the corresponding latex
environment is of "display" type, i.e., it stands on its own, whereas
"false" means that the contents appear inline with the text. The
latter is the case for both Comment and GreyedOut insets.
Mostly, the only visible effects on latex exports should be the
disappearing of some redundant % chars and the appearing/disappearing
of null {} latex groups after a comment or lyxgreyedout environments
(they are related to the presence or absence of a space immediately
after those environments), as well as the fact that math environments
are now started on their own lines.
As a last thing, only the latex code between \begin{document} and
\end{document} goes through the new class, the preamble being directly
output through odocstream, as usual.
git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@37360 a592a061-630c-0410-9148-cb99ea01b6c8
2011-01-29 02:41:13 +00:00
|
|
|
os << '\n';
|
2019-12-26 12:47:50 +00:00
|
|
|
if (!style.parbreak_is_newline && !merged_par) {
|
2010-11-06 15:06:19 +00:00
|
|
|
os << '\n';
|
2013-01-23 23:16:42 +00:00
|
|
|
} else if (nextpar && !style.isEnvironment()) {
|
2011-02-10 20:02:48 +00:00
|
|
|
Layout const nextstyle = text.inset().forcePlainLayout()
|
|
|
|
? bparams.documentClass().plainLayout()
|
|
|
|
: nextpar->layout();
|
2019-12-26 12:47:50 +00:00
|
|
|
if (nextstyle.name() != style.name() && !merged_par)
|
2010-11-06 15:06:19 +00:00
|
|
|
os << '\n';
|
|
|
|
}
|
|
|
|
|
2010-12-15 20:51:25 +00:00
|
|
|
return;
|
2010-11-06 15:06:19 +00:00
|
|
|
}
|
|
|
|
|
2007-07-20 01:28:20 +00:00
|
|
|
// This paragraph's language
|
2010-12-18 15:57:27 +00:00
|
|
|
Language const * const par_language = par.getParLanguage(bparams);
|
2015-10-27 21:36:52 +00:00
|
|
|
Language const * const nextpar_language = nextpar ?
|
2019-07-06 19:05:16 +00:00
|
|
|
nextpar->getParLanguage(bparams) : nullptr;
|
2007-07-20 01:28:20 +00:00
|
|
|
// The document's language
|
2007-03-12 17:19:08 +00:00
|
|
|
Language const * const doc_language = bparams.language;
|
2008-10-13 11:25:37 +00:00
|
|
|
// The language that was in effect when the environment this paragraph is
|
2007-07-20 01:28:20 +00:00
|
|
|
// inside of was opened
|
2008-10-13 11:25:37 +00:00
|
|
|
Language const * const outer_language =
|
2019-07-06 19:05:16 +00:00
|
|
|
(runparams.local_font != nullptr) ?
|
2019-07-06 19:18:41 +00:00
|
|
|
runparams.local_font->language() : doc_language;
|
2009-07-30 00:58:37 +00:00
|
|
|
|
2019-07-06 19:05:16 +00:00
|
|
|
Paragraph const * priorpar = (pit == 0) ? nullptr : ¶graphs.at(pit - 1);
|
2010-12-18 15:57:27 +00:00
|
|
|
|
2009-07-30 00:58:37 +00:00
|
|
|
// 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.
|
2018-04-29 11:18:05 +00:00
|
|
|
// 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).
|
2019-07-06 19:05:16 +00:00
|
|
|
bool const use_prev_env_language = state->prev_env_language_ != nullptr
|
2010-12-18 15:57:27 +00:00
|
|
|
&& priorpar
|
|
|
|
&& priorpar->layout().isEnvironment()
|
|
|
|
&& (priorpar->getDepth() > par.getDepth()
|
|
|
|
|| (priorpar->getDepth() == par.getDepth()
|
2019-08-16 09:48:57 +00:00
|
|
|
&& priorpar->layout() != par.layout()));
|
2019-08-16 14:24:09 +00:00
|
|
|
|
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
}
|
2022-02-21 08:49:32 +00:00
|
|
|
bool const have_prior_nptpar =
|
|
|
|
prior_nontitle_par && !prior_nontitle_par->isPassThru();
|
2009-07-28 16:15:34 +00:00
|
|
|
Language const * const prev_language =
|
2022-05-09 20:06:02 +00:00
|
|
|
runparams_in.find_effective()
|
2019-08-16 14:24:09 +00:00
|
|
|
? languages.getLanguage("ignore")
|
2022-02-21 08:49:32 +00:00
|
|
|
: (have_prior_nptpar)
|
2019-08-16 14:24:09 +00:00
|
|
|
? (use_prev_env_language
|
|
|
|
? state->prev_env_language_
|
|
|
|
: prior_nontitle_par->getParLanguage(bparams))
|
|
|
|
: outer_language;
|
2009-07-28 16:15:34 +00:00
|
|
|
|
2012-06-23 13:41:05 +00:00
|
|
|
bool const use_polyglossia = runparams.use_polyglossia;
|
|
|
|
string const par_lang = use_polyglossia ?
|
2011-06-02 19:55:08 +00:00
|
|
|
getPolyglossiaEnvName(par_language): par_language->babel();
|
2012-06-23 13:41:05 +00:00
|
|
|
string const prev_lang = use_polyglossia ?
|
2011-06-02 19:55:08 +00:00
|
|
|
getPolyglossiaEnvName(prev_language) : prev_language->babel();
|
2012-06-23 13:41:05 +00:00
|
|
|
string const outer_lang = use_polyglossia ?
|
2011-06-02 19:55:08 +00:00
|
|
|
getPolyglossiaEnvName(outer_language) : outer_language->babel();
|
2015-10-27 21:36:52 +00:00
|
|
|
string const nextpar_lang = nextpar_language ? (use_polyglossia ?
|
|
|
|
getPolyglossiaEnvName(nextpar_language) :
|
|
|
|
nextpar_language->babel()) : string();
|
2012-11-28 19:55:21 +00:00
|
|
|
string lang_begin_command = use_polyglossia ?
|
2015-05-03 14:08:14 +00:00
|
|
|
"\\begin{$$lang}$$opts" : lyxrc.language_command_begin;
|
2012-11-28 19:55:21 +00:00
|
|
|
string lang_end_command = use_polyglossia ?
|
2011-06-02 19:55:08 +00:00
|
|
|
"\\end{$$lang}" : lyxrc.language_command_end;
|
2012-11-28 19:55:21 +00:00
|
|
|
// the '%' is necessary to prevent unwanted whitespace
|
|
|
|
string lang_command_termination = "%\n";
|
2017-05-30 15:49:59 +00:00
|
|
|
bool const using_begin_end = use_polyglossia ||
|
|
|
|
!lang_end_command.empty();
|
2012-11-28 19:55:21 +00:00
|
|
|
|
2017-12-23 12:25:13 +00:00
|
|
|
// For InTitle commands, we need to switch the language inside the command
|
|
|
|
// (see #10849); thus open the command here.
|
|
|
|
if (intitle_command) {
|
|
|
|
parStartCommand(par, os, runparams, style);
|
2019-03-14 13:24:43 +00:00
|
|
|
if (style.isCommand() && style.needprotect)
|
|
|
|
// Due to the moving argument, some fragile
|
|
|
|
// commands (labels, index entries)
|
|
|
|
// are output after this command (#2154)
|
2020-01-10 09:21:09 +00:00
|
|
|
runparams.postpone_fragile_stuff =
|
|
|
|
bparams.postpone_fragile_content;
|
2017-12-23 12:25:13 +00:00
|
|
|
os << '{';
|
|
|
|
}
|
|
|
|
|
2018-08-24 13:02:26 +00:00
|
|
|
// In some insets (such as Arguments), we cannot use \selectlanguage.
|
|
|
|
// Also, if an RTL language is set via environment in polyglossia,
|
|
|
|
// only a nested \\text<lang> command will reset the direction for LTR
|
|
|
|
// languages (see # 10111).
|
2018-09-10 10:29:22 +00:00
|
|
|
bool const in_polyglossia_rtl_env =
|
|
|
|
use_polyglossia
|
2019-07-06 19:05:16 +00:00
|
|
|
&& runparams.local_font != nullptr
|
2018-09-10 10:29:22 +00:00
|
|
|
&& outer_language->rightToLeft()
|
2022-02-21 08:49:32 +00:00
|
|
|
&& !par_language->rightToLeft()
|
|
|
|
&& !(have_prior_nptpar
|
|
|
|
&& (prev_language->rightToLeft() != par_language->rightToLeft()));
|
2019-11-19 12:37:44 +00:00
|
|
|
bool const localswitch =
|
2022-05-09 20:06:02 +00:00
|
|
|
(runparams_in.find_effective()
|
2018-10-05 18:26:44 +00:00
|
|
|
|| text.inset().forceLocalFontSwitch()
|
2018-08-24 13:02:26 +00:00
|
|
|
|| (using_begin_end && text.inset().forcePlainLayout())
|
2019-11-19 12:37:44 +00:00
|
|
|
|| in_polyglossia_rtl_env)
|
|
|
|
&& !text.inset().forceParDirectionSwitch();
|
2012-11-28 19:55:21 +00:00
|
|
|
if (localswitch) {
|
2015-05-03 14:08:14 +00:00
|
|
|
lang_begin_command = use_polyglossia ?
|
|
|
|
"\\text$$lang$$opts{" : lyxrc.language_command_local;
|
2012-11-28 19:55:21 +00:00
|
|
|
lang_end_command = "}";
|
|
|
|
lang_command_termination.clear();
|
|
|
|
}
|
2019-01-28 16:49:58 +00:00
|
|
|
|
2018-04-27 16:27:21 +00:00
|
|
|
bool const localswitch_needed = localswitch && par_lang != outer_lang;
|
2011-06-02 19:55:08 +00:00
|
|
|
|
2018-04-27 07:48:14 +00:00
|
|
|
// localswitches need to be closed and reopened at each par
|
2022-05-09 20:06:02 +00:00
|
|
|
if (runparams_in.find_effective() || ((par_lang != prev_lang || localswitch_needed)
|
2018-04-27 07:48:14 +00:00
|
|
|
// check if we already put language command in TeXEnvironment()
|
|
|
|
&& !(style.isEnvironment()
|
|
|
|
&& (pit == 0 || (priorpar->layout() != par.layout()
|
|
|
|
&& priorpar->getDepth() <= par.getDepth())
|
2018-11-03 14:00:58 +00:00
|
|
|
|| priorpar->getDepth() < par.getDepth())))) {
|
2018-04-27 07:48:14 +00:00
|
|
|
if (!localswitch
|
|
|
|
&& (!using_begin_end || langOpenedAtThisLevel(state))
|
|
|
|
&& !lang_end_command.empty()
|
2019-01-28 16:49:58 +00:00
|
|
|
&& prev_lang != outer_lang
|
2018-04-27 07:48:14 +00:00
|
|
|
&& !prev_lang.empty()
|
|
|
|
&& (!using_begin_end || !style.isEnvironment())) {
|
2010-11-22 12:10:16 +00:00
|
|
|
os << from_ascii(subst(lang_end_command,
|
2018-04-27 07:48:14 +00:00
|
|
|
"$$lang",
|
|
|
|
prev_lang))
|
2012-11-28 19:55:21 +00:00
|
|
|
<< lang_command_termination;
|
2017-05-30 15:49:59 +00:00
|
|
|
if (using_begin_end)
|
|
|
|
popLanguageName();
|
2003-11-05 12:06:20 +00:00
|
|
|
}
|
|
|
|
|
2008-10-13 11:25:37 +00:00
|
|
|
// We need to open a new language if we couldn't close the previous
|
2007-07-20 01:28:20 +00:00
|
|
|
// 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).
|
2016-09-24 01:15:02 +00:00
|
|
|
if ((lang_end_command.empty() || par_lang != outer_lang
|
2017-05-30 15:49:59 +00:00
|
|
|
|| (!using_begin_end
|
2016-09-24 01:15:02 +00:00
|
|
|
|| (style.isEnvironment() && par_lang != prev_lang)))
|
2010-12-18 16:19:05 +00:00
|
|
|
&& !par_lang.empty()) {
|
2007-07-20 01:28:20 +00:00
|
|
|
// 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.
|
2017-05-30 15:49:59 +00:00
|
|
|
if (!using_begin_end
|
2010-11-22 12:10:16 +00:00
|
|
|
// not for ArabTeX
|
2018-08-24 13:33:48 +00:00
|
|
|
&& par_language->lang() != "arabic_arabtex"
|
|
|
|
&& outer_language->lang() != "arabic_arabtex"
|
2010-11-22 12:10:16 +00:00
|
|
|
// are we in an inset?
|
2019-07-06 19:05:16 +00:00
|
|
|
&& runparams.local_font != nullptr
|
2010-11-22 12:10:16 +00:00
|
|
|
// 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?
|
2010-12-18 16:19:05 +00:00
|
|
|
&& runparams.local_font->isRightToLeft() != par_language->rightToLeft()) {
|
2007-07-20 01:28:20 +00:00
|
|
|
// 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{";
|
|
|
|
}
|
2007-12-08 11:21:00 +00:00
|
|
|
// With CJK, the CJK tag has to be closed first (see below)
|
2019-05-25 23:45:35 +00:00
|
|
|
if ((runparams.encoding->package() != Encoding::CJK
|
|
|
|
|| bparams.useNonTeXFonts
|
2022-05-09 20:06:02 +00:00
|
|
|
|| runparams.find_effective())
|
2019-08-16 14:24:09 +00:00
|
|
|
&& (par_lang != openLanguageName(state) || localswitch || intitle_command)
|
2012-06-24 08:56:08 +00:00
|
|
|
&& !par_lang.empty()) {
|
2015-05-03 14:08:14 +00:00
|
|
|
string bc = use_polyglossia ?
|
2018-03-06 14:31:43 +00:00
|
|
|
getPolyglossiaBegin(lang_begin_command, par_lang,
|
|
|
|
par_language->polyglossiaOpts(),
|
|
|
|
localswitch)
|
2015-05-03 14:08:14 +00:00
|
|
|
: subst(lang_begin_command, "$$lang", par_lang);
|
|
|
|
os << bc;
|
2012-11-28 19:55:21 +00:00
|
|
|
os << lang_command_termination;
|
2017-05-30 15:49:59 +00:00
|
|
|
if (using_begin_end)
|
|
|
|
pushLanguageName(par_lang, localswitch);
|
2007-12-08 11:21:00 +00:00
|
|
|
}
|
2003-11-05 12:06:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-16 18:17:32 +00:00
|
|
|
// Switch file encoding if necessary; no need to do this for "auto-legacy-plain"
|
2007-07-05 19:19:41 +00:00
|
|
|
// encoding, since this only affects the position of the outputted
|
|
|
|
// \inputencoding command; the encoding switch will occur when necessary
|
2019-04-16 18:17:32 +00:00
|
|
|
if (bparams.inputenc == "auto-legacy"
|
2015-11-12 15:55:04 +00:00
|
|
|
&& !runparams.isFullUnicode() // Xe/LuaTeX use one document-wide encoding (see also switchEncoding())
|
2019-04-11 16:19:44 +00:00
|
|
|
&& runparams.encoding->package() != Encoding::japanese
|
2010-12-18 16:32:29 +00:00
|
|
|
&& runparams.encoding->package() != Encoding::none) {
|
2007-04-16 18:06:01 +00:00
|
|
|
// 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
|
2010-03-27 17:29:56 +00:00
|
|
|
// 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().
|
2010-12-18 15:57:27 +00:00
|
|
|
for (pos_type i = 0; i < par.size(); ++i) {
|
|
|
|
char_type const c = par.getChar(i);
|
2008-01-25 13:27:08 +00:00
|
|
|
Encoding const * const encoding =
|
2010-12-18 15:57:27 +00:00
|
|
|
par.getFontSettings(bparams, i).language()->encoding();
|
2010-12-18 16:32:29 +00:00
|
|
|
if (encoding->package() != Encoding::CJK
|
|
|
|
&& runparams.encoding->package() == Encoding::inputenc
|
2012-12-30 10:58:21 +00:00
|
|
|
&& isASCII(c))
|
2007-04-16 18:06:01 +00:00
|
|
|
continue;
|
2010-12-18 15:57:27 +00:00
|
|
|
if (par.isInset(i))
|
2007-04-16 18:06:01 +00:00
|
|
|
break;
|
|
|
|
// All characters before c are in the ASCII range, and
|
|
|
|
// c is non-ASCII (but no inset), so change the
|
|
|
|
// encoding to that required by the language of c.
|
2008-01-25 13:27:08 +00:00
|
|
|
// With CJK, only add switch if we have CJK content at the beginning
|
2007-12-08 11:21:00 +00:00
|
|
|
// of the paragraph
|
2010-12-18 16:32:29 +00:00
|
|
|
if (i != 0 && encoding->package() == Encoding::CJK)
|
|
|
|
continue;
|
|
|
|
|
Introduce a wrapper class for odocstream to help ensuring that no
blank lines may be inadvertently output. This is achieved by using two
special iomanip-like variables (breakln and safebreakln) in the lyx::
namespace. When they are inserted in the stream, a newline is output
only if not already at the beginning of a line. The difference between
breakln and safebreakln is that, if needed, the former outputs '\n'
and the latter "%\n".
In future, the new class will also be used for counting the number of
newlines issued. Even if the infractrure for doing that is already in
place, the counting is essentially still done the old way.
There are still places in the code where the functionality of the
class could be used, most probably. ATM, it is used for InsetTabular,
InsetListings, InsetFloat, and InsetText.
The Comment and GreyedOut insets required a special treatment and a
new InsetLayout parameter (Display) has been introduced. The default
for Display is "true", meaning that the corresponding latex
environment is of "display" type, i.e., it stands on its own, whereas
"false" means that the contents appear inline with the text. The
latter is the case for both Comment and GreyedOut insets.
Mostly, the only visible effects on latex exports should be the
disappearing of some redundant % chars and the appearing/disappearing
of null {} latex groups after a comment or lyxgreyedout environments
(they are related to the presence or absence of a space immediately
after those environments), as well as the fact that math environments
are now started on their own lines.
As a last thing, only the latex code between \begin{document} and
\end{document} goes through the new class, the preamble being directly
output through odocstream, as usual.
git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@37360 a592a061-630c-0410-9148-cb99ea01b6c8
2011-01-29 02:41:13 +00:00
|
|
|
pair<bool, int> enc_switch = switchEncoding(os.os(),
|
|
|
|
bparams, runparams, *encoding);
|
2010-12-18 16:32:29 +00:00
|
|
|
// the following is necessary after a CJK environment in a multilingual
|
|
|
|
// context (nesting issue).
|
|
|
|
if (par_language->encoding()->package() == Encoding::CJK
|
2014-07-05 12:23:43 +00:00
|
|
|
&& state->open_encoding_ != CJK && state->cjk_inherited_ == 0) {
|
2019-02-05 10:31:27 +00:00
|
|
|
os << "\\begin{CJK}{"
|
|
|
|
<< from_ascii(par_language->encoding()->latexName())
|
2010-12-18 16:32:29 +00:00
|
|
|
<< "}{" << from_ascii(bparams.fonts_cjk) << "}%\n";
|
2014-07-05 12:23:43 +00:00
|
|
|
state->open_encoding_ = CJK;
|
2010-12-18 16:32:29 +00:00
|
|
|
}
|
|
|
|
if (encoding->package() != Encoding::none && enc_switch.first) {
|
|
|
|
if (enc_switch.second > 0) {
|
|
|
|
// the '%' is necessary to prevent unwanted whitespace
|
|
|
|
os << "%\n";
|
2007-07-05 19:19:41 +00:00
|
|
|
}
|
2010-12-18 16:32:29 +00:00
|
|
|
// With CJK, the CJK tag had to be closed first (see above)
|
2012-06-24 08:56:08 +00:00
|
|
|
if (runparams.encoding->package() == Encoding::CJK
|
2017-05-30 15:49:59 +00:00
|
|
|
&& par_lang != openLanguageName(state)
|
2012-06-24 08:56:08 +00:00
|
|
|
&& !par_lang.empty()) {
|
2019-05-24 20:48:06 +00:00
|
|
|
os << subst(lang_begin_command, "$$lang", par_lang)
|
2018-03-06 14:31:43 +00:00
|
|
|
<< lang_command_termination;
|
2017-05-30 15:49:59 +00:00
|
|
|
if (using_begin_end)
|
|
|
|
pushLanguageName(par_lang, localswitch);
|
2007-12-08 11:21:00 +00:00
|
|
|
}
|
2010-12-18 16:32:29 +00:00
|
|
|
runparams.encoding = encoding;
|
2007-04-16 18:06:01 +00:00
|
|
|
}
|
2010-12-18 16:32:29 +00:00
|
|
|
break;
|
2007-04-16 18:06:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-03-27 17:29:56 +00:00
|
|
|
runparams.moving_arg |= style.needprotect;
|
2019-03-12 13:08:05 +00:00
|
|
|
if (style.needmboxprotect)
|
|
|
|
++runparams.inulemcmd;
|
2009-08-03 18:31:20 +00:00
|
|
|
Encoding const * const prev_encoding = runparams.encoding;
|
|
|
|
|
2008-02-28 01:42:02 +00:00
|
|
|
bool const useSetSpace = bparams.documentClass().provides("SetSpace");
|
2010-12-18 15:57:27 +00:00
|
|
|
if (par.allowParagraphCustomization()) {
|
|
|
|
if (par.params().startOfAppendix()) {
|
2014-05-16 13:39:33 +00:00
|
|
|
os << "\n\\appendix\n";
|
2004-09-28 13:29:19 +00:00
|
|
|
}
|
|
|
|
|
2017-12-23 12:25:13 +00:00
|
|
|
// InTitle commands must use switches (not environments)
|
|
|
|
// inside the commands (see #9332)
|
|
|
|
if (style.intitle) {
|
|
|
|
if (!par.params().spacing().isDefault())
|
|
|
|
{
|
|
|
|
if (runparams.moving_arg)
|
|
|
|
os << "\\protect";
|
|
|
|
os << from_ascii(par.params().spacing().writeCmd(useSetSpace));
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (!par.params().spacing().isDefault()
|
|
|
|
&& (pit == 0 || !priorpar->hasSameLayout(par)))
|
|
|
|
{
|
|
|
|
os << from_ascii(par.params().spacing().writeEnvirBegin(useSetSpace))
|
|
|
|
<< '\n';
|
|
|
|
}
|
2004-09-28 13:29:19 +00:00
|
|
|
|
2017-12-23 12:25:13 +00:00
|
|
|
if (style.isCommand()) {
|
|
|
|
os << '\n';
|
|
|
|
}
|
2004-09-28 13:29:19 +00:00
|
|
|
}
|
2004-10-05 10:11:42 +00:00
|
|
|
}
|
2004-09-28 13:29:19 +00:00
|
|
|
|
2017-12-23 12:25:13 +00:00
|
|
|
// For InTitle commands, we already started the command before
|
|
|
|
// the language switch
|
2019-03-14 13:24:43 +00:00
|
|
|
if (!intitle_command) {
|
2017-12-23 12:25:13 +00:00
|
|
|
parStartCommand(par, os, runparams, style);
|
2019-03-14 13:24:43 +00:00
|
|
|
if (style.isCommand() && style.needprotect)
|
|
|
|
// Due to the moving argument, some fragile
|
|
|
|
// commands (labels, index entries)
|
|
|
|
// are output after this command (#2154)
|
2020-01-10 09:21:09 +00:00
|
|
|
runparams.postpone_fragile_stuff =
|
|
|
|
bparams.postpone_fragile_content;
|
2019-03-14 13:24:43 +00:00
|
|
|
}
|
2017-12-23 12:25:13 +00:00
|
|
|
|
2010-12-18 15:57:27 +00:00
|
|
|
Font const outerfont = text.outerFont(pit);
|
2007-03-18 10:59:16 +00:00
|
|
|
|
2006-10-19 16:51:30 +00:00
|
|
|
// FIXME UNICODE
|
2006-10-21 00:16:43 +00:00
|
|
|
os << from_utf8(everypar);
|
2017-12-26 12:11:00 +00:00
|
|
|
par.latex(bparams, outerfont, os, runparams, start_pos, end_pos, force);
|
2003-11-05 12:06:20 +00:00
|
|
|
|
2010-12-18 15:57:27 +00:00
|
|
|
Font const font = par.empty()
|
|
|
|
? par.getLayoutFont(bparams, outerfont)
|
|
|
|
: par.getFont(bparams, par.size() - 1, outerfont);
|
2003-11-05 12:06:20 +00:00
|
|
|
|
2008-10-31 15:33:48 +00:00
|
|
|
bool const is_command = style.isCommand();
|
2003-11-05 12:06:20 +00:00
|
|
|
|
2017-12-23 12:25:13 +00:00
|
|
|
// 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:");
|
2019-03-14 13:24:43 +00:00
|
|
|
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();
|
|
|
|
}
|
2019-08-14 12:00:29 +00:00
|
|
|
if (par.needsCProtection(runparams.moving_arg)
|
|
|
|
&& contains(runparams.active_chars, '^'))
|
|
|
|
os << "\\endgroup";
|
2017-12-23 12:25:13 +00:00
|
|
|
if (runparams.encoding != prev_encoding) {
|
|
|
|
runparams.encoding = prev_encoding;
|
|
|
|
os << setEncoding(prev_encoding->iconvName());
|
|
|
|
}
|
2009-09-16 20:50:40 +00:00
|
|
|
}
|
2009-08-03 18:31:20 +00:00
|
|
|
}
|
2003-11-05 12:06:20 +00:00
|
|
|
|
2007-01-17 22:01:08 +00:00
|
|
|
bool pending_newline = false;
|
2011-09-17 15:25:14 +00:00
|
|
|
bool unskip_newline = false;
|
2016-09-24 01:15:02 +00:00
|
|
|
bool close_lang_switch = false;
|
2008-03-06 21:31:27 +00:00
|
|
|
switch (style.latextype) {
|
2003-11-05 12:06:20 +00:00
|
|
|
case LATEX_ITEM_ENVIRONMENT:
|
|
|
|
case LATEX_LIST_ENVIRONMENT:
|
2016-09-27 19:32:40 +00:00
|
|
|
if ((nextpar && par_lang != nextpar_lang
|
|
|
|
&& nextpar->getDepth() == par.getDepth())
|
2016-09-24 01:15:02 +00:00
|
|
|
|| (atSameLastLangSwitchDepth(state) && nextpar
|
|
|
|
&& nextpar->getDepth() < par.getDepth()))
|
2017-05-30 15:49:59 +00:00
|
|
|
close_lang_switch = using_begin_end;
|
2014-05-20 22:59:36 +00:00
|
|
|
if (nextpar && par.params().depth() < nextpar->params().depth())
|
2019-12-26 12:47:50 +00:00
|
|
|
pending_newline = !text.inset().getLayout().parbreakIgnored() && !merged_par;
|
2003-11-05 12:06:20 +00:00
|
|
|
break;
|
|
|
|
case LATEX_ENVIRONMENT: {
|
2019-04-10 13:59:17 +00:00
|
|
|
// if it's the last paragraph of the current environment
|
2003-11-05 12:06:20 +00:00
|
|
|
// skip it otherwise fall through
|
2010-12-18 16:19:05 +00:00
|
|
|
if (nextpar
|
2016-09-24 01:15:02 +00:00
|
|
|
&& ((nextpar->layout() != par.layout()
|
|
|
|
|| nextpar->params().depth() != par.params().depth())
|
2017-05-30 15:49:59 +00:00
|
|
|
|| (!using_begin_end || par_lang != nextpar_lang)))
|
2016-09-24 01:15:02 +00:00
|
|
|
{
|
2017-05-30 15:49:59 +00:00
|
|
|
close_lang_switch = using_begin_end;
|
2003-11-05 12:06:20 +00:00
|
|
|
break;
|
2016-09-24 01:15:02 +00:00
|
|
|
}
|
2003-11-05 12:06:20 +00:00
|
|
|
}
|
2017-08-12 07:06:29 +00:00
|
|
|
// possible
|
|
|
|
// fall through
|
2003-11-05 12:06:20 +00:00
|
|
|
default:
|
2017-12-23 12:25:13 +00:00
|
|
|
// we don't need it for the last paragraph and in InTitle commands!!!
|
|
|
|
if (nextpar && !intitle_command)
|
2019-12-26 12:47:50 +00:00
|
|
|
pending_newline = !text.inset().getLayout().parbreakIgnored() && !merged_par;
|
2003-11-05 12:06:20 +00:00
|
|
|
}
|
|
|
|
|
2017-12-23 12:25:13 +00:00
|
|
|
// InTitle commands use switches (not environments) for space settings
|
|
|
|
if (par.allowParagraphCustomization() && !style.intitle) {
|
2010-12-18 15:57:27 +00:00
|
|
|
if (!par.params().spacing().isDefault()
|
2010-12-18 16:19:05 +00:00
|
|
|
&& (runparams.isLastPar || !nextpar->hasSameLayout(par))) {
|
2011-02-10 20:02:48 +00:00
|
|
|
if (pending_newline)
|
2007-01-17 22:01:08 +00:00
|
|
|
os << '\n';
|
Fix bugs #8546 and #9055, and introduce new separator inset.
The algorithm used for breaking a paragraph in LaTeX export is changed
for avoiding spurious blank lines causing too much vertical space.
This change is tied to the introduction of a new inset (with two
different specializations) helping in either outputing LaTeX paragraph
breaks or separating environments in LyX. Both of the above goals were
previously achieved by the ---Separator--- layout and can now be
accomplished by the new inset in a more natural way. As an example,
after leaving an environment by hitting the Return key for two times,
a third return automatically inserts a parbreak inset, which is
equivalent to the old separator layout, i.e., it also introduces a
blank line in the output. If this blank line is not wanted, the
parbreak separator can be changed to a plain separator by a right
click of the mouse. Of course, an environment can still be separated
by the following one by using the Alt+P+Return shortcut (or the
corresponding menu key), but now the plain separator inset is used
instead of the old separator layout, such that no blank line occurs in
the LaTeX output.
Old documents are converted such that the LaTeX output remains unchanged.
As a result of this conversion, the old separator layout is replaced by
the new parbreak inset, which may also appear in places where the old
algorithm was introducing blank lines while the new one is not.
Note that not all blank lines were actually affecting the LaTeX output,
because a blank line is simply ignored by the TeX engine when it occurs
in the so called "vertical mode" (e.g., after an alignment environment).
The old ---Separator--- layout is now gone and old layout files using it
are also automatically converted.
Round trip conversions between old and new format should leave a document
unchanged. This means that the new behavior about paragraph breaking is
not "carried back" to the old format. Indeed, this would need introducing
special LaTeX commands in ERT that would accumulate in roundtrip
conversions, horribly cluttering the document. So, when converting a
modified document to old formats, the LaTeX output may slightly differ in
vertical spacing if the document is processed by an old version of LyX.
In other words, forward compatibility is guaranteed, but not backwards.
2014-05-10 21:25:11 +00:00
|
|
|
|
|
|
|
string const endtag =
|
|
|
|
par.params().spacing().writeEnvirEnd(useSetSpace);
|
|
|
|
if (prefixIs(endtag, "\\end{"))
|
|
|
|
os << breakln;
|
|
|
|
|
|
|
|
os << from_ascii(endtag);
|
2007-01-17 22:01:08 +00:00
|
|
|
pending_newline = true;
|
2004-09-28 13:29:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-23 12:25:13 +00:00
|
|
|
// Closing the language is needed for the last paragraph in a given language
|
|
|
|
// as well as for any InTitleCommand (since these set the language locally);
|
|
|
|
// 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.
|
2017-05-30 15:49:59 +00:00
|
|
|
bool closing_rtl_ltr_environment = !using_begin_end
|
2007-07-20 01:28:20 +00:00
|
|
|
// not for ArabTeX
|
2010-12-18 16:11:38 +00:00
|
|
|
&& (par_language->lang() != "arabic_arabtex"
|
|
|
|
&& outer_language->lang() != "arabic_arabtex")
|
2013-05-20 10:31:46 +00:00
|
|
|
// have we opened an \L or \R environment?
|
2019-07-06 19:18:41 +00:00
|
|
|
&& runparams.local_font != nullptr
|
2010-12-18 16:11:38 +00:00
|
|
|
&& runparams.local_font->isRightToLeft() != par_language->rightToLeft()
|
2007-07-20 01:28:20 +00:00
|
|
|
// are we about to close the language?
|
2015-10-27 21:36:52 +00:00
|
|
|
&&((nextpar && par_lang != nextpar_lang)
|
|
|
|
|| (runparams.isLastPar && par_lang != outer_lang));
|
2010-12-18 15:57:27 +00:00
|
|
|
|
2018-04-27 16:27:21 +00:00
|
|
|
if (localswitch_needed
|
2018-04-27 07:48:14 +00:00
|
|
|
|| (intitle_command && using_begin_end)
|
2017-12-23 12:25:13 +00:00
|
|
|
|| closing_rtl_ltr_environment
|
2019-05-10 06:09:26 +00:00
|
|
|
|| (((runparams.isLastPar && !runparams.inbranch) || close_lang_switch)
|
2017-05-30 15:49:59 +00:00
|
|
|
&& (par_lang != outer_lang || (using_begin_end
|
2016-09-24 01:15:02 +00:00
|
|
|
&& style.isEnvironment()
|
|
|
|
&& par_lang != nextpar_lang)))) {
|
2004-04-22 13:59:39 +00:00
|
|
|
// Since \selectlanguage write the language to the aux file,
|
|
|
|
// we need to reset the language at the end of footnote or
|
|
|
|
// float.
|
|
|
|
|
2018-04-27 07:48:14 +00:00
|
|
|
if (!localswitch && (pending_newline || close_lang_switch))
|
2007-01-17 22:01:08 +00:00
|
|
|
os << '\n';
|
2011-02-10 20:02:48 +00:00
|
|
|
|
2007-12-08 11:21:00 +00:00
|
|
|
// when the paragraph uses CJK, the language has to be closed earlier
|
2019-05-25 23:45:35 +00:00
|
|
|
if ((font.language()->encoding()->package() != Encoding::CJK)
|
|
|
|
|| bparams.useNonTeXFonts
|
2022-05-09 20:06:02 +00:00
|
|
|
|| runparams_in.find_effective()) {
|
2010-11-22 12:10:16 +00:00
|
|
|
if (lang_end_command.empty()) {
|
2009-10-18 21:48:13 +00:00
|
|
|
// If this is a child, we should restore the
|
|
|
|
// master language after the last paragraph.
|
|
|
|
Language const * const current_language =
|
2010-12-18 15:57:27 +00:00
|
|
|
(runparams.isLastPar && runparams.master_language)
|
2009-10-18 21:48:13 +00:00
|
|
|
? runparams.master_language
|
2010-01-06 17:36:22 +00:00
|
|
|
: outer_language;
|
2012-06-23 13:41:05 +00:00
|
|
|
string const current_lang = use_polyglossia
|
2011-06-02 19:55:08 +00:00
|
|
|
? getPolyglossiaEnvName(current_language)
|
2010-11-22 12:10:16 +00:00
|
|
|
: current_language->babel();
|
2016-09-24 01:15:02 +00:00
|
|
|
if (!current_lang.empty()
|
2017-05-30 15:49:59 +00:00
|
|
|
&& current_lang != openLanguageName(state)) {
|
2015-05-03 14:08:14 +00:00
|
|
|
string bc = use_polyglossia ?
|
|
|
|
getPolyglossiaBegin(lang_begin_command, current_lang,
|
2018-03-06 14:31:43 +00:00
|
|
|
current_language->polyglossiaOpts(),
|
|
|
|
localswitch)
|
2015-05-03 14:08:14 +00:00
|
|
|
: subst(lang_begin_command, "$$lang", current_lang);
|
|
|
|
os << bc;
|
2019-06-02 16:16:30 +00:00
|
|
|
pending_newline = !localswitch
|
|
|
|
&& !text.inset().getLayout().parbreakIgnored();
|
2012-11-28 19:55:21 +00:00
|
|
|
unskip_newline = !localswitch;
|
2017-05-30 15:49:59 +00:00
|
|
|
if (using_begin_end)
|
|
|
|
pushLanguageName(current_lang, localswitch);
|
2007-12-08 11:21:00 +00:00
|
|
|
}
|
2017-05-30 15:49:59 +00:00
|
|
|
} else if ((!using_begin_end ||
|
2017-05-16 20:02:42 +00:00
|
|
|
langOpenedAtThisLevel(state)) &&
|
2017-05-16 18:20:32 +00:00
|
|
|
!par_lang.empty()) {
|
|
|
|
// If we are in an environment, we have to
|
|
|
|
// close the "outer" language afterwards
|
2017-05-30 15:49:59 +00:00
|
|
|
string const & cur_lang = openLanguageName(state);
|
2016-09-24 01:15:02 +00:00
|
|
|
if (!style.isEnvironment()
|
|
|
|
|| (close_lang_switch
|
|
|
|
&& atSameLastLangSwitchDepth(state)
|
|
|
|
&& par_lang != outer_lang
|
2017-05-30 15:49:59 +00:00
|
|
|
&& (par_lang != cur_lang
|
|
|
|
|| (cur_lang != outer_lang
|
2016-09-24 01:15:02 +00:00
|
|
|
&& nextpar
|
|
|
|
&& style != nextpar->layout())))
|
|
|
|
|| (atSameLastLangSwitchDepth(state)
|
2020-10-05 10:38:09 +00:00
|
|
|
&& !state->lang_switch_depth_.empty()
|
2018-09-08 10:50:42 +00:00
|
|
|
&& cur_lang != par_lang)
|
2018-09-10 10:29:22 +00:00
|
|
|
|| in_polyglossia_rtl_env)
|
2016-09-24 01:15:02 +00:00
|
|
|
{
|
2017-05-30 15:49:59 +00:00
|
|
|
if (using_begin_end && !localswitch)
|
2016-09-24 01:15:02 +00:00
|
|
|
os << breakln;
|
2015-06-19 07:25:11 +00:00
|
|
|
os << from_ascii(subst(
|
|
|
|
lang_end_command,
|
|
|
|
"$$lang",
|
|
|
|
par_lang));
|
2019-06-02 16:16:30 +00:00
|
|
|
pending_newline = !localswitch
|
|
|
|
&& !text.inset().getLayout().parbreakIgnored();
|
2015-06-19 07:25:11 +00:00
|
|
|
unskip_newline = !localswitch;
|
2017-05-30 15:49:59 +00:00
|
|
|
if (using_begin_end)
|
|
|
|
popLanguageName();
|
2015-06-19 07:25:11 +00:00
|
|
|
}
|
2007-05-05 19:18:34 +00:00
|
|
|
}
|
2007-05-05 20:27:43 +00:00
|
|
|
}
|
2004-04-22 13:59:39 +00:00
|
|
|
}
|
2007-07-20 01:28:20 +00:00
|
|
|
if (closing_rtl_ltr_environment)
|
|
|
|
os << "}";
|
2004-04-22 13:59:39 +00:00
|
|
|
|
2017-12-23 12:25:13 +00:00
|
|
|
// InTitle commands need to be closed after the language has been closed.
|
|
|
|
if (intitle_command) {
|
2019-08-16 09:48:57 +00:00
|
|
|
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());
|
2017-12-23 12:25:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-05-20 22:59:36 +00:00
|
|
|
bool const last_was_separator =
|
2020-10-05 10:38:09 +00:00
|
|
|
!par.empty() && par.isEnvSeparator(par.size() - 1);
|
2014-05-20 22:59:36 +00:00
|
|
|
|
2019-12-26 14:43:00 +00:00
|
|
|
// 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 << "}";
|
|
|
|
}
|
|
|
|
|
2011-09-17 15:25:14 +00:00
|
|
|
if (pending_newline) {
|
|
|
|
if (unskip_newline)
|
|
|
|
// prevent unwanted whitespace
|
|
|
|
os << '%';
|
2014-05-20 22:59:36 +00:00
|
|
|
if (!os.afterParbreak() && !last_was_separator)
|
2017-05-29 21:22:14 +00:00
|
|
|
os << '\n';
|
2011-09-17 15:25:14 +00:00
|
|
|
}
|
2007-07-20 01:28:20 +00:00
|
|
|
|
2007-12-08 11:21:00 +00:00
|
|
|
// 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)
|
2019-05-25 23:45:35 +00:00
|
|
|
if (nextpar && state->open_encoding_ == CJK
|
|
|
|
&& bparams.encoding().iconvName() != "UTF-8"
|
|
|
|
&& bparams.encoding().package() != Encoding::CJK
|
2020-02-18 08:03:20 +00:00
|
|
|
&& ((nextpar_language &&
|
|
|
|
nextpar_language->encoding()->package() != Encoding::CJK)
|
2019-05-25 23:45:35 +00:00
|
|
|
|| (nextpar->layout().isEnvironment() && nextpar->isMultiLingual(bparams)))
|
2010-12-18 16:11:38 +00:00
|
|
|
// inbetween environments, CJK has to be closed later (nesting!)
|
|
|
|
&& (!style.isEnvironment() || !nextpar->layout().isEnvironment())) {
|
2007-12-08 11:21:00 +00:00
|
|
|
os << "\\end{CJK}\n";
|
2014-07-05 12:23:43 +00:00
|
|
|
state->open_encoding_ = none;
|
2007-12-08 11:21:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// If this is the last paragraph, close the CJK environment
|
2019-01-28 22:02:33 +00:00
|
|
|
// if necessary. If it's an environment or nested in an environment,
|
|
|
|
// we'll have to \end that first.
|
|
|
|
if (runparams.isLastPar && !style.isEnvironment()
|
|
|
|
&& par.params().depth() < 1) {
|
2014-07-05 12:23:43 +00:00
|
|
|
switch (state->open_encoding_) {
|
2007-12-08 11:21:00 +00:00
|
|
|
case CJK: {
|
2008-10-21 17:03:49 +00:00
|
|
|
// do nothing at the end of child documents
|
|
|
|
if (maintext && buf.masterBuffer() != &buf)
|
|
|
|
break;
|
2019-01-24 13:40:19 +00:00
|
|
|
// end of main text: also insert a \clearpage (see #5386)
|
2008-01-25 13:27:08 +00:00
|
|
|
if (maintext) {
|
2019-01-24 13:40:19 +00:00
|
|
|
os << "\n\\clearpage\n\\end{CJK}\n";
|
2007-12-08 11:21:00 +00:00
|
|
|
// end of an inset
|
|
|
|
} else
|
|
|
|
os << "\\end{CJK}";
|
2014-07-05 12:23:43 +00:00
|
|
|
state->open_encoding_ = none;
|
2007-12-08 11:21:00 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case inputenc: {
|
2019-05-13 08:42:41 +00:00
|
|
|
// 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;
|
2007-12-08 11:21:00 +00:00
|
|
|
os << "\\egroup";
|
2014-07-05 12:23:43 +00:00
|
|
|
state->open_encoding_ = none;
|
2007-12-08 11:21:00 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case none:
|
|
|
|
default:
|
|
|
|
// do nothing
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-16 11:43:50 +00:00
|
|
|
// Information about local language is stored as a font feature.
|
2019-04-05 14:14:58 +00:00
|
|
|
// If this is the last paragraph of the inset and a local_font was set upon entering
|
2019-04-16 18:17:32 +00:00
|
|
|
// and we are mixing encodings ("auto-legacy" or "auto-legacy-plain" and no XeTeX or LuaTeX),
|
2019-04-05 14:14:58 +00:00
|
|
|
// ensure the encoding is set back to the default encoding of the local language.
|
2019-07-06 19:05:16 +00:00
|
|
|
if (runparams.isLastPar && runparams_in.local_font != nullptr
|
2008-07-09 07:21:02 +00:00
|
|
|
&& runparams_in.encoding != runparams_in.local_font->language()->encoding()
|
2019-04-16 18:17:32 +00:00
|
|
|
&& (bparams.inputenc == "auto-legacy" || bparams.inputenc == "auto-legacy-plain")
|
2019-04-05 14:14:58 +00:00
|
|
|
&& !runparams.isFullUnicode()
|
2015-11-10 23:10:06 +00:00
|
|
|
) {
|
2007-07-20 01:28:20 +00:00
|
|
|
runparams_in.encoding = runparams_in.local_font->language()->encoding();
|
2008-03-26 22:38:41 +00:00
|
|
|
os << setEncoding(runparams_in.encoding->iconvName());
|
2007-07-20 01:28:20 +00:00
|
|
|
}
|
|
|
|
// Otherwise, the current encoding should be set for the next paragraph.
|
|
|
|
else
|
|
|
|
runparams_in.encoding = runparams.encoding;
|
|
|
|
|
2019-03-14 13:24:43 +00:00
|
|
|
// Also pass the post_macros upstream
|
|
|
|
runparams_in.post_macro = runparams.post_macro;
|
2020-07-03 14:18:53 +00:00
|
|
|
// These need to be passed upstream as well
|
|
|
|
runparams_in.need_maketitle = runparams.need_maketitle;
|
|
|
|
runparams_in.have_maketitle = runparams.have_maketitle;
|
2019-03-14 13:24:43 +00:00
|
|
|
|
2007-01-09 19:25:40 +00:00
|
|
|
|
2008-10-31 15:37:34 +00:00
|
|
|
// we don't need a newline for the last paragraph!!!
|
|
|
|
// Note from JMarc: we will re-add a \n explicitly in
|
2004-04-22 13:59:39 +00:00
|
|
|
// TeXEnvironment, because it is needed in this case
|
2014-05-20 22:59:36 +00:00
|
|
|
if (nextpar && !os.afterParbreak() && !last_was_separator) {
|
2021-01-23 13:53:51 +00:00
|
|
|
if (!text.inset().getLayout().parbreakIgnored() && !merged_par)
|
2019-06-02 16:16:30 +00:00
|
|
|
// Make sure to start a new line
|
|
|
|
os << breakln;
|
2014-05-14 20:25:15 +00:00
|
|
|
// A newline '\n' is always output before a command,
|
|
|
|
// so avoid doubling it.
|
2021-01-23 13:24:54 +00:00
|
|
|
Layout const & next_layout = nextpar->layout();
|
2014-05-14 20:25:15 +00:00
|
|
|
if (!next_layout.isCommand()) {
|
|
|
|
// Here we now try to avoid spurious empty lines by
|
|
|
|
// outputting a paragraph break only if: (case 1) the
|
|
|
|
// paragraph style allows parbreaks and no \begin, \end
|
|
|
|
// or \item tags are going to follow (i.e., if the next
|
|
|
|
// isn't the first or the current isn't the last
|
|
|
|
// paragraph of an environment or itemize) and the
|
|
|
|
// depth and alignment of the following paragraph is
|
|
|
|
// unchanged, or (case 2) the following is a
|
|
|
|
// non-environment paragraph whose depth is increased
|
|
|
|
// but whose alignment is unchanged, or (case 3) the
|
2014-05-21 19:08:11 +00:00
|
|
|
// paragraph is not an environment and the next one is a
|
|
|
|
// non-itemize-like env at lower depth, or (case 4) the
|
2014-05-14 20:25:15 +00:00
|
|
|
// paragraph is a command not followed by an environment
|
|
|
|
// and the alignment of the current and next paragraph
|
2014-05-21 19:08:11 +00:00
|
|
|
// is unchanged, or (case 5) the current alignment is
|
2014-05-16 13:39:33 +00:00
|
|
|
// changed and a standard paragraph follows.
|
|
|
|
DocumentClass const & tclass = bparams.documentClass();
|
2014-05-14 20:25:15 +00:00
|
|
|
if ((style == next_layout
|
|
|
|
&& !style.parbreak_is_newline
|
2015-04-21 17:43:41 +00:00
|
|
|
&& !text.inset().getLayout().parbreakIsNewline()
|
2019-06-02 16:16:30 +00:00
|
|
|
&& !text.inset().getLayout().parbreakIgnored()
|
2014-05-14 20:25:15 +00:00
|
|
|
&& style.latextype != LATEX_ITEM_ENVIRONMENT
|
|
|
|
&& style.latextype != LATEX_LIST_ENVIRONMENT
|
2019-07-10 12:50:08 +00:00
|
|
|
&& style.align == par.getAlign(bparams)
|
2014-05-14 20:25:15 +00:00
|
|
|
&& nextpar->getDepth() == par.getDepth()
|
2019-07-10 12:50:08 +00:00
|
|
|
&& nextpar->getAlign(bparams) == par.getAlign(bparams))
|
2014-05-14 20:25:15 +00:00
|
|
|
|| (!next_layout.isEnvironment()
|
|
|
|
&& nextpar->getDepth() > par.getDepth()
|
2019-07-10 12:50:08 +00:00
|
|
|
&& nextpar->getAlign(bparams) == next_layout.align)
|
2014-05-21 19:08:11 +00:00
|
|
|
|| (!style.isEnvironment()
|
|
|
|
&& next_layout.latextype == LATEX_ENVIRONMENT
|
|
|
|
&& nextpar->getDepth() < par.getDepth())
|
2014-05-14 20:25:15 +00:00
|
|
|
|| (style.isCommand()
|
|
|
|
&& !next_layout.isEnvironment()
|
2019-07-10 12:50:08 +00:00
|
|
|
&& style.align == par.getAlign(bparams)
|
|
|
|
&& next_layout.align == nextpar->getAlign(bparams))
|
|
|
|
|| (style.align != par.getAlign(bparams)
|
2014-05-16 13:39:33 +00:00
|
|
|
&& tclass.isDefaultLayout(next_layout))) {
|
2019-12-26 12:47:50 +00:00
|
|
|
// and omit paragraph break if it has been deleted with ct
|
|
|
|
// and changes are not shown in output
|
2021-01-23 13:53:51 +00:00
|
|
|
if (!merged_par) {
|
|
|
|
if (runparams.isNonLong)
|
|
|
|
// This is to allow parbreak in multirow
|
|
|
|
// It could also be used for other non-long
|
|
|
|
// contexts
|
|
|
|
os << "\\endgraf\n";
|
|
|
|
else
|
|
|
|
os << '\n';
|
|
|
|
}
|
2014-05-14 20:25:15 +00:00
|
|
|
}
|
2008-07-02 08:34:55 +00:00
|
|
|
}
|
2003-11-05 12:06:20 +00:00
|
|
|
}
|
|
|
|
|
2019-11-21 07:38:21 +00:00
|
|
|
// Reset language nesting level after intitle command
|
|
|
|
if (intitle_command)
|
|
|
|
state->nest_level_ -= 1;
|
|
|
|
|
2022-02-27 19:35:58 +00:00
|
|
|
LYXERR(Debug::OUTFILE, "TeXOnePar for paragraph " << pit << " done; ptr "
|
|
|
|
<< &par << " next " << nextpar);
|
2006-10-26 15:01:45 +00:00
|
|
|
|
2010-12-15 20:51:25 +00:00
|
|
|
return;
|
2003-11-05 12:06:20 +00:00
|
|
|
}
|
|
|
|
|
2004-02-11 14:45:44 +00:00
|
|
|
|
|
|
|
// LaTeX all paragraphs
|
2003-11-05 12:06:20 +00:00
|
|
|
void latexParagraphs(Buffer const & buf,
|
2008-01-25 13:27:08 +00:00
|
|
|
Text const & text,
|
Introduce a wrapper class for odocstream to help ensuring that no
blank lines may be inadvertently output. This is achieved by using two
special iomanip-like variables (breakln and safebreakln) in the lyx::
namespace. When they are inserted in the stream, a newline is output
only if not already at the beginning of a line. The difference between
breakln and safebreakln is that, if needed, the former outputs '\n'
and the latter "%\n".
In future, the new class will also be used for counting the number of
newlines issued. Even if the infractrure for doing that is already in
place, the counting is essentially still done the old way.
There are still places in the code where the functionality of the
class could be used, most probably. ATM, it is used for InsetTabular,
InsetListings, InsetFloat, and InsetText.
The Comment and GreyedOut insets required a special treatment and a
new InsetLayout parameter (Display) has been introduced. The default
for Display is "true", meaning that the corresponding latex
environment is of "display" type, i.e., it stands on its own, whereas
"false" means that the contents appear inline with the text. The
latter is the case for both Comment and GreyedOut insets.
Mostly, the only visible effects on latex exports should be the
disappearing of some redundant % chars and the appearing/disappearing
of null {} latex groups after a comment or lyxgreyedout environments
(they are related to the presence or absence of a space immediately
after those environments), as well as the fact that math environments
are now started on their own lines.
As a last thing, only the latex code between \begin{document} and
\end{document} goes through the new class, the preamble being directly
output through odocstream, as usual.
git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@37360 a592a061-630c-0410-9148-cb99ea01b6c8
2011-01-29 02:41:13 +00:00
|
|
|
otexstream & os,
|
2017-02-12 17:12:38 +00:00
|
|
|
OutputParams const & runparams,
|
2003-11-05 12:06:20 +00:00
|
|
|
string const & everypar)
|
|
|
|
{
|
2013-04-25 21:27:10 +00:00
|
|
|
LASSERT(runparams.par_begin <= runparams.par_end,
|
|
|
|
{ os << "% LaTeX Output Error\n"; return; } );
|
|
|
|
|
2008-01-25 13:27:08 +00:00
|
|
|
BufferParams const & bparams = buf.params();
|
2017-02-04 18:23:46 +00:00
|
|
|
BufferParams const & mparams = buf.masterParams();
|
view-source feature, from Bo Peng <ben.bob@gmail.com>
* src/buffer.h buffer.C - getSourceCode()
* src/lyxfunc.C - open view-source dialog
* src/text3.C - change LFUN_MOUSE_RELEASE
* src/output_linuxdoc.C, src/output_docbook.C, src/output_latex.C
- intercept output
* src/outputparams.h, outputparams.C - add par_begin, par_end, dryrun
* src/insets/insetgraphics.C - add dryrun mode of file conversion
* lib/ui/stdmenus.ui - add view-source menu item under view
* Add view-source dialog, add
src/frontends/qt2/QViewSourceDialog.h, QViewSource.C, QViewSource.h, QViewSourceDialog.C
src/frontends/qt2/ui/QViewSourceDialogBase.ui
src/frontends/controllers/ControlViewSource.h ControlViewSource.C
modify
src/frontends/qt2/Makefile.dialogs, Makefile.am, Dialogs.C,
src/frontends/controllers/Makefile.am, po.POTFILES.in
git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@13610 a592a061-630c-0410-9148-cb99ea01b6c8
2006-04-09 02:48:54 +00:00
|
|
|
|
2009-08-09 15:29:34 +00:00
|
|
|
bool const maintext = text.isMainText();
|
2008-10-21 17:03:49 +00:00
|
|
|
bool const is_child = buf.masterBuffer() != &buf;
|
2017-02-04 18:23:46 +00:00
|
|
|
bool const multibib_child = maintext && is_child
|
|
|
|
&& mparams.multibib == "child";
|
|
|
|
|
|
|
|
if (multibib_child && mparams.useBiblatex())
|
|
|
|
os << "\\newrefsection";
|
2019-04-23 06:58:01 +00:00
|
|
|
else if (multibib_child && mparams.useBibtopic()
|
|
|
|
&& !buf.masterBibInfo().empty()) {
|
2017-02-04 18:23:46 +00:00
|
|
|
os << "\\begin{btUnit}\n";
|
|
|
|
runparams.openbtUnit = true;
|
|
|
|
}
|
2008-01-25 13:27:08 +00:00
|
|
|
|
|
|
|
// Open a CJK environment at the beginning of the main buffer
|
2019-02-05 10:31:27 +00:00
|
|
|
// 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):
|
2014-07-05 12:23:43 +00:00
|
|
|
OutputState * state = getOutputState();
|
2019-01-06 15:40:36 +00:00
|
|
|
if (maintext && !is_child && !bparams.useNonTeXFonts
|
2019-02-05 10:31:27 +00:00
|
|
|
&& (bparams.encoding().package() == Encoding::CJK
|
|
|
|
|| (bparams.encoding().name() == "utf8"
|
2019-03-13 10:31:25 +00:00
|
|
|
&& runparams.use_CJK))
|
|
|
|
) {
|
2019-01-23 23:36:33 +00:00
|
|
|
docstring const cjkenc = bparams.encoding().iconvName() == "UTF-8"
|
2019-07-18 15:05:44 +00:00
|
|
|
? from_ascii("UTF8")
|
|
|
|
: from_ascii(bparams.encoding().latexName());
|
2019-01-06 13:36:11 +00:00
|
|
|
os << "\\begin{CJK}{" << cjkenc
|
|
|
|
<< "}{" << from_ascii(bparams.fonts_cjk) << "}%\n";
|
2014-07-05 12:23:43 +00:00
|
|
|
state->open_encoding_ = CJK;
|
2008-01-25 13:27:08 +00:00
|
|
|
}
|
2010-01-29 14:44:21 +00:00
|
|
|
// if "auto begin" is switched off, explicitly switch the
|
2008-01-25 13:27:08 +00:00
|
|
|
// language on at start
|
2011-06-02 19:55:08 +00:00
|
|
|
string const mainlang = runparams.use_polyglossia
|
|
|
|
? getPolyglossiaEnvName(bparams.language)
|
2010-11-22 12:10:16 +00:00
|
|
|
: bparams.language->babel();
|
|
|
|
string const lang_begin_command = runparams.use_polyglossia ?
|
2015-05-03 14:08:14 +00:00
|
|
|
"\\begin{$$lang}$$opts" : lyxrc.language_command_begin;
|
2017-05-30 15:49:59 +00:00
|
|
|
string const lang_end_command = runparams.use_polyglossia ?
|
|
|
|
"\\end{$$lang}" : lyxrc.language_command_end;
|
|
|
|
bool const using_begin_end = runparams.use_polyglossia ||
|
|
|
|
!lang_end_command.empty();
|
2010-11-22 12:10:16 +00:00
|
|
|
|
2008-01-25 13:27:08 +00:00
|
|
|
if (maintext && !lyxrc.language_auto_begin &&
|
2010-11-22 12:10:16 +00:00
|
|
|
!mainlang.empty()) {
|
2008-01-25 13:27:08 +00:00
|
|
|
// FIXME UNICODE
|
2015-05-03 14:08:14 +00:00
|
|
|
string bc = runparams.use_polyglossia ?
|
|
|
|
getPolyglossiaBegin(lang_begin_command, mainlang,
|
|
|
|
bparams.language->polyglossiaOpts())
|
|
|
|
: subst(lang_begin_command, "$$lang", mainlang);
|
|
|
|
os << bc;
|
2010-11-22 12:10:16 +00:00
|
|
|
os << '\n';
|
2017-05-30 15:49:59 +00:00
|
|
|
if (using_begin_end)
|
|
|
|
pushLanguageName(mainlang);
|
2008-01-25 13:27:08 +00:00
|
|
|
}
|
|
|
|
|
2010-12-18 08:31:34 +00:00
|
|
|
ParagraphList const & paragraphs = text.paragraphs();
|
2010-12-18 13:49:39 +00:00
|
|
|
|
|
|
|
if (runparams.par_begin == runparams.par_end) {
|
|
|
|
// 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;
|
2020-10-13 21:24:36 +00:00
|
|
|
runparams.par_end = static_cast<int>(paragraphs.size());
|
2010-12-18 08:23:14 +00:00
|
|
|
}
|
|
|
|
|
2010-12-18 13:49:39 +00:00
|
|
|
pit_type pit = runparams.par_begin;
|
2010-12-18 08:23:14 +00:00
|
|
|
// lastpit is for the language check after the loop.
|
2010-12-20 00:57:16 +00:00
|
|
|
pit_type lastpit = pit;
|
2010-12-18 08:31:34 +00:00
|
|
|
DocumentClass const & tclass = bparams.documentClass();
|
|
|
|
|
2020-03-20 21:18:11 +00:00
|
|
|
// Did we already warn about inTitle layout mixing? (we only warn once)
|
|
|
|
bool gave_layout_warning = false;
|
2010-12-18 13:49:39 +00:00
|
|
|
for (; pit < runparams.par_end; ++pit) {
|
2010-12-18 08:23:14 +00:00
|
|
|
lastpit = pit;
|
2020-05-11 10:31:25 +00:00
|
|
|
ParagraphList::const_iterator par = paragraphs.iterator_at(pit);
|
2010-12-18 08:23:14 +00:00
|
|
|
|
2008-10-31 15:33:48 +00:00
|
|
|
// FIXME This check should not be needed. We should
|
|
|
|
// perhaps issue an error if it is.
|
2009-08-09 16:19:43 +00:00
|
|
|
Layout const & layout = text.inset().forcePlainLayout() ?
|
2009-02-11 17:16:05 +00:00
|
|
|
tclass.plainLayout() : par->layout();
|
2008-04-22 18:33:07 +00:00
|
|
|
|
|
|
|
if (layout.intitle) {
|
2020-07-03 14:18:53 +00:00
|
|
|
if (runparams.have_maketitle) {
|
2020-03-20 21:18:11 +00:00
|
|
|
if (!gave_layout_warning && !runparams.dryrun) {
|
|
|
|
gave_layout_warning = true;
|
2016-08-17 02:09:57 +00:00
|
|
|
frontend::Alert::warning(_("Error in latexParagraphs"),
|
|
|
|
bformat(_("You are using at least one "
|
|
|
|
"layout (%1$s) intended for the title, "
|
|
|
|
"after using non-title layouts. This "
|
|
|
|
"could lead to missing or incorrect output."
|
|
|
|
), layout.name()));
|
|
|
|
}
|
2020-07-03 14:18:53 +00:00
|
|
|
} else if (!runparams.need_maketitle) {
|
|
|
|
runparams.need_maketitle = true;
|
2003-11-05 12:06:20 +00:00
|
|
|
if (tclass.titletype() == TITLE_ENVIRONMENT) {
|
2008-04-22 18:33:07 +00:00
|
|
|
os << "\\begin{"
|
|
|
|
<< from_ascii(tclass.titlename())
|
|
|
|
<< "}\n";
|
2003-11-05 12:06:20 +00:00
|
|
|
}
|
|
|
|
}
|
2020-07-04 08:54:20 +00:00
|
|
|
} else if (runparams.need_maketitle && !runparams.have_maketitle
|
|
|
|
&& !layout.inpreamble && !text.inset().isInTitle()) {
|
2008-04-22 18:33:07 +00:00
|
|
|
if (tclass.titletype() == TITLE_ENVIRONMENT) {
|
|
|
|
os << "\\end{" << from_ascii(tclass.titlename())
|
|
|
|
<< "}\n";
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
os << "\\" << from_ascii(tclass.titlename())
|
|
|
|
<< "\n";
|
|
|
|
}
|
2020-07-03 14:18:53 +00:00
|
|
|
runparams.have_maketitle = true;
|
|
|
|
runparams.need_maketitle = false;
|
2008-04-22 18:33:07 +00:00
|
|
|
}
|
2003-11-05 12:06:20 +00:00
|
|
|
|
2017-02-04 11:02:00 +00:00
|
|
|
if (layout.isCommand() && !layout.latexname().empty()
|
|
|
|
&& layout.latexname() == bparams.multibib) {
|
|
|
|
if (runparams.openbtUnit)
|
|
|
|
os << "\\end{btUnit}\n";
|
2019-04-23 06:58:01 +00:00
|
|
|
if (!bparams.useBiblatex()
|
|
|
|
&& !buf.masterBibInfo().empty()) {
|
2017-02-04 11:02:00 +00:00
|
|
|
os << '\n' << "\\begin{btUnit}\n";
|
|
|
|
runparams.openbtUnit = true;
|
|
|
|
}
|
|
|
|
}
|
2010-12-18 13:49:39 +00:00
|
|
|
|
2010-12-18 08:23:14 +00:00
|
|
|
if (!layout.isEnvironment() && par->params().leftIndent().zero()) {
|
2010-12-18 13:49:39 +00:00
|
|
|
// This is a standard top level paragraph, TeX it and continue.
|
2011-02-10 20:02:48 +00:00
|
|
|
TeXOnePar(buf, text, pit, os, runparams, everypar);
|
2010-12-18 08:23:14 +00:00
|
|
|
continue;
|
2003-11-05 12:06:20 +00:00
|
|
|
}
|
2017-07-03 17:53:14 +00:00
|
|
|
|
2019-12-26 14:24:48 +00:00
|
|
|
// Do not output empty environments if the whole paragraph has
|
|
|
|
// been deleted with ct and changes are not output.
|
2021-01-22 20:11:28 +00:00
|
|
|
bool output_changes;
|
2022-05-09 20:06:02 +00:00
|
|
|
if (!runparams.find_effective())
|
2021-01-22 20:11:28 +00:00
|
|
|
output_changes = bparams.output_changes;
|
|
|
|
else
|
2022-05-09 20:06:02 +00:00
|
|
|
output_changes = runparams.find_with_deleted();
|
2021-12-29 15:07:40 +00:00
|
|
|
bool const lastpar = size_t(pit + 1) >= paragraphs.size();
|
|
|
|
if (!lastpar) {
|
2020-05-11 10:31:25 +00:00
|
|
|
ParagraphList::const_iterator nextpar = paragraphs.iterator_at(pit + 1);
|
2019-12-26 14:24:48 +00:00
|
|
|
Paragraph const & cpar = paragraphs.at(pit);
|
|
|
|
if ((par->layout() != nextpar->layout()
|
|
|
|
|| par->params().depth() == nextpar->params().depth()
|
|
|
|
|| par->params().leftIndent() == nextpar->params().leftIndent())
|
2021-01-22 16:03:54 +00:00
|
|
|
&& !cpar.empty()
|
2021-01-22 20:11:28 +00:00
|
|
|
&& cpar.isDeleted(0, cpar.size()) && !output_changes) {
|
2020-10-01 10:34:15 +00:00
|
|
|
if (!cpar.parEndChange().deleted())
|
2019-12-26 14:24:48 +00:00
|
|
|
os << '\n' << '\n';
|
|
|
|
continue;
|
|
|
|
}
|
2020-12-27 13:00:30 +00:00
|
|
|
} else {
|
|
|
|
// This is the last par
|
|
|
|
Paragraph const & cpar = paragraphs.at(pit);
|
2021-01-22 20:11:28 +00:00
|
|
|
if ( !cpar.empty()
|
|
|
|
&& cpar.isDeleted(0, cpar.size()) && !output_changes) {
|
2020-12-27 13:00:30 +00:00
|
|
|
if (!cpar.parEndChange().deleted())
|
|
|
|
os << '\n' << '\n';
|
|
|
|
continue;
|
|
|
|
}
|
2019-12-26 14:24:48 +00:00
|
|
|
}
|
|
|
|
|
2011-06-02 19:39:44 +00:00
|
|
|
TeXEnvironmentData const data =
|
|
|
|
prepareEnvironment(buf, text, par, os, runparams);
|
2010-12-18 13:49:39 +00:00
|
|
|
// pit can be changed in TeXEnvironment.
|
2011-02-10 20:02:48 +00:00
|
|
|
TeXEnvironment(buf, text, runparams, pit, os);
|
2021-12-29 15:07:40 +00:00
|
|
|
finishEnvironment(os, runparams, data, maintext, lastpar);
|
2010-12-18 13:49:39 +00:00
|
|
|
}
|
|
|
|
|
2019-05-25 23:45:35 +00:00
|
|
|
// FIXME: uncomment the content or remove this block
|
2010-12-18 13:49:39 +00:00
|
|
|
if (pit == runparams.par_end) {
|
|
|
|
// Make sure that the last paragraph is
|
|
|
|
// correctly terminated (because TeXOnePar does
|
|
|
|
// not add a \n in this case)
|
|
|
|
//os << '\n';
|
2003-11-05 12:06:20 +00:00
|
|
|
}
|
2008-04-22 18:33:07 +00:00
|
|
|
|
2020-03-17 05:33:44 +00:00
|
|
|
// It might be that we only have a title in this document.
|
2020-07-03 14:18:53 +00:00
|
|
|
// But if we're in an inset, this is not the end of
|
2020-03-17 05:33:44 +00:00
|
|
|
// the document. (There may be some other checks of this
|
|
|
|
// kind that are needed.)
|
2020-07-03 14:18:53 +00:00
|
|
|
if (runparams.need_maketitle && !runparams.have_maketitle && maintext) {
|
2003-11-05 12:06:20 +00:00
|
|
|
if (tclass.titletype() == TITLE_ENVIRONMENT) {
|
2006-10-21 00:16:43 +00:00
|
|
|
os << "\\end{" << from_ascii(tclass.titlename())
|
Introduce a wrapper class for odocstream to help ensuring that no
blank lines may be inadvertently output. This is achieved by using two
special iomanip-like variables (breakln and safebreakln) in the lyx::
namespace. When they are inserted in the stream, a newline is output
only if not already at the beginning of a line. The difference between
breakln and safebreakln is that, if needed, the former outputs '\n'
and the latter "%\n".
In future, the new class will also be used for counting the number of
newlines issued. Even if the infractrure for doing that is already in
place, the counting is essentially still done the old way.
There are still places in the code where the functionality of the
class could be used, most probably. ATM, it is used for InsetTabular,
InsetListings, InsetFloat, and InsetText.
The Comment and GreyedOut insets required a special treatment and a
new InsetLayout parameter (Display) has been introduced. The default
for Display is "true", meaning that the corresponding latex
environment is of "display" type, i.e., it stands on its own, whereas
"false" means that the contents appear inline with the text. The
latter is the case for both Comment and GreyedOut insets.
Mostly, the only visible effects on latex exports should be the
disappearing of some redundant % chars and the appearing/disappearing
of null {} latex groups after a comment or lyxgreyedout environments
(they are related to the presence or absence of a space immediately
after those environments), as well as the fact that math environments
are now started on their own lines.
As a last thing, only the latex code between \begin{document} and
\end{document} goes through the new class, the preamble being directly
output through odocstream, as usual.
git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@37360 a592a061-630c-0410-9148-cb99ea01b6c8
2011-01-29 02:41:13 +00:00
|
|
|
<< "}\n";
|
|
|
|
} else {
|
2006-10-21 00:16:43 +00:00
|
|
|
os << "\\" << from_ascii(tclass.titlename())
|
Introduce a wrapper class for odocstream to help ensuring that no
blank lines may be inadvertently output. This is achieved by using two
special iomanip-like variables (breakln and safebreakln) in the lyx::
namespace. When they are inserted in the stream, a newline is output
only if not already at the beginning of a line. The difference between
breakln and safebreakln is that, if needed, the former outputs '\n'
and the latter "%\n".
In future, the new class will also be used for counting the number of
newlines issued. Even if the infractrure for doing that is already in
place, the counting is essentially still done the old way.
There are still places in the code where the functionality of the
class could be used, most probably. ATM, it is used for InsetTabular,
InsetListings, InsetFloat, and InsetText.
The Comment and GreyedOut insets required a special treatment and a
new InsetLayout parameter (Display) has been introduced. The default
for Display is "true", meaning that the corresponding latex
environment is of "display" type, i.e., it stands on its own, whereas
"false" means that the contents appear inline with the text. The
latter is the case for both Comment and GreyedOut insets.
Mostly, the only visible effects on latex exports should be the
disappearing of some redundant % chars and the appearing/disappearing
of null {} latex groups after a comment or lyxgreyedout environments
(they are related to the presence or absence of a space immediately
after those environments), as well as the fact that math environments
are now started on their own lines.
As a last thing, only the latex code between \begin{document} and
\end{document} goes through the new class, the preamble being directly
output through odocstream, as usual.
git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@37360 a592a061-630c-0410-9148-cb99ea01b6c8
2011-01-29 02:41:13 +00:00
|
|
|
<< "\n";
|
|
|
|
}
|
2003-11-05 12:06:20 +00:00
|
|
|
}
|
2008-04-22 18:33:07 +00:00
|
|
|
|
2017-02-04 15:07:58 +00:00
|
|
|
if (maintext && !is_child && runparams.openbtUnit)
|
2017-02-04 11:02:00 +00:00
|
|
|
os << "\\end{btUnit}\n";
|
|
|
|
|
2010-01-29 14:44:21 +00:00
|
|
|
// if "auto end" is switched off, explicitly close the language at the end
|
2015-10-18 18:55:53 +00:00
|
|
|
// but only if the last par is in a babel or polyglossia language
|
2019-07-18 15:05:44 +00:00
|
|
|
Language const * const lastpar_language =
|
|
|
|
paragraphs.at(lastpit).getParLanguage(bparams);
|
2010-11-22 12:10:16 +00:00
|
|
|
if (maintext && !lyxrc.language_auto_end && !mainlang.empty() &&
|
2019-07-18 15:05:44 +00:00
|
|
|
lastpar_language->encoding()->package() != Encoding::CJK) {
|
2010-11-22 12:10:16 +00:00
|
|
|
os << from_utf8(subst(lang_end_command,
|
2008-01-25 13:27:08 +00:00
|
|
|
"$$lang",
|
2010-11-22 12:10:16 +00:00
|
|
|
mainlang))
|
2008-01-25 13:27:08 +00:00
|
|
|
<< '\n';
|
2019-11-21 07:38:21 +00:00
|
|
|
// If we have language_auto_begin, the stack will
|
|
|
|
// already be empty, nothing to pop()
|
2022-02-04 16:23:52 +00:00
|
|
|
if (using_begin_end && langOpenedAtThisLevel(state))
|
2017-05-30 15:49:59 +00:00
|
|
|
popLanguageName();
|
2008-01-25 13:27:08 +00:00
|
|
|
}
|
2008-04-22 18:33:07 +00:00
|
|
|
|
2007-12-08 11:21:00 +00:00
|
|
|
// If the last paragraph is an environment, we'll have to close
|
|
|
|
// CJK at the very end to do proper nesting.
|
2014-07-05 12:23:43 +00:00
|
|
|
if (maintext && !is_child && state->open_encoding_ == CJK) {
|
2019-01-28 16:49:58 +00:00
|
|
|
os << "\\clearpage\n\\end{CJK}\n";
|
2014-07-05 12:23:43 +00:00
|
|
|
state->open_encoding_ = none;
|
2007-12-08 11:21:00 +00:00
|
|
|
}
|
2017-05-30 15:49:59 +00:00
|
|
|
// Likewise for polyglossia or when using begin/end commands
|
2019-07-18 15:05:44 +00:00
|
|
|
// or at the very end of an active branch inset with a language switch
|
2019-07-06 19:05:16 +00:00
|
|
|
Language const * const outer_language = (runparams.local_font != nullptr)
|
2019-05-10 06:09:26 +00:00
|
|
|
? runparams.local_font->language() : bparams.language;
|
|
|
|
string const & prev_lang = runparams.use_polyglossia
|
|
|
|
? getPolyglossiaEnvName(outer_language)
|
|
|
|
: outer_language->babel();
|
2019-07-18 15:05:44 +00:00
|
|
|
string const lastpar_lang = runparams.use_polyglossia ?
|
|
|
|
getPolyglossiaEnvName(lastpar_language): lastpar_language->babel();
|
2017-05-30 15:49:59 +00:00
|
|
|
string const & cur_lang = openLanguageName(state);
|
2019-05-10 06:09:26 +00:00
|
|
|
if (((runparams.inbranch && langOpenedAtThisLevel(state) && prev_lang != cur_lang)
|
|
|
|
|| (maintext && !is_child)) && !cur_lang.empty()) {
|
2015-10-18 18:55:53 +00:00
|
|
|
os << from_utf8(subst(lang_end_command,
|
|
|
|
"$$lang",
|
2017-05-30 15:49:59 +00:00
|
|
|
cur_lang))
|
2015-10-18 18:55:53 +00:00
|
|
|
<< '\n';
|
2017-05-30 15:49:59 +00:00
|
|
|
if (using_begin_end)
|
|
|
|
popLanguageName();
|
2019-07-18 15:05:44 +00:00
|
|
|
} 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)
|
2019-05-10 06:09:26 +00:00
|
|
|
os << subst(lang_begin_command, "$$lang", prev_lang) << '\n';
|
2015-06-19 07:25:11 +00:00
|
|
|
}
|
2008-04-22 18:33:07 +00:00
|
|
|
|
2007-12-08 11:21:00 +00:00
|
|
|
// reset inherited encoding
|
2014-07-05 12:23:43 +00:00
|
|
|
if (state->cjk_inherited_ > 0) {
|
|
|
|
state->cjk_inherited_ -= 1;
|
|
|
|
if (state->cjk_inherited_ == 0)
|
|
|
|
state->open_encoding_ = CJK;
|
2007-12-08 11:21:00 +00:00
|
|
|
}
|
2017-02-04 18:23:46 +00:00
|
|
|
|
|
|
|
if (multibib_child && mparams.useBibtopic()) {
|
|
|
|
os << "\\end{btUnit}\n";
|
|
|
|
runparams.openbtUnit = false;
|
|
|
|
}
|
2003-11-05 12:06:20 +00:00
|
|
|
}
|
2006-10-21 00:16:43 +00:00
|
|
|
|
2019-04-11 16:19:44 +00:00
|
|
|
// Switch the input encoding for some part(s) of the document.
|
2007-07-05 19:19:41 +00:00
|
|
|
pair<bool, int> switchEncoding(odocstream & os, BufferParams const & bparams,
|
2008-07-20 17:14:10 +00:00
|
|
|
OutputParams const & runparams, Encoding const & newEnc,
|
2018-05-01 12:21:05 +00:00
|
|
|
bool force, bool noswitchmacro)
|
2007-01-09 19:25:40 +00:00
|
|
|
{
|
2019-07-12 10:46:50 +00:00
|
|
|
// Never switch encoding with XeTeX/LuaTeX
|
2019-04-11 16:19:44 +00:00
|
|
|
// or if we're in a moving argument or inherit the outer encoding.
|
2019-07-12 10:46:50 +00:00
|
|
|
if (runparams.isFullUnicode() || newEnc.name() == "inherit")
|
|
|
|
return make_pair(false, 0);
|
2015-11-12 15:55:04 +00:00
|
|
|
|
2019-04-11 16:19:44 +00:00
|
|
|
// Only switch for auto-selected legacy encodings (inputenc setting
|
2019-04-16 18:17:32 +00:00
|
|
|
// "auto-legacy" or "auto-legacy-plain").
|
2019-04-11 16:19:44 +00:00
|
|
|
// 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).
|
2019-04-16 18:17:32 +00:00
|
|
|
if (!force && ((bparams.inputenc != "auto-legacy" && bparams.inputenc != "auto-legacy-plain")
|
2019-04-11 16:19:44 +00:00
|
|
|
|| runparams.moving_arg))
|
2007-07-05 19:19:41 +00:00
|
|
|
return make_pair(false, 0);
|
2007-05-07 17:10:10 +00:00
|
|
|
|
2019-04-11 16:19:44 +00:00
|
|
|
Encoding const & oldEnc = *runparams.encoding;
|
|
|
|
// 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
|
2019-04-17 05:40:31 +00:00
|
|
|
|| newEnc.package() == Encoding::none
|
2022-05-09 20:06:02 +00:00
|
|
|
|| runparams.find_effective())
|
2007-07-05 19:19:41 +00:00
|
|
|
return make_pair(false, 0);
|
2007-05-06 20:26:02 +00:00
|
|
|
// FIXME We ignore encoding switches from/to encodings that do
|
|
|
|
// neither support the inputenc package nor the CJK package here.
|
2019-04-11 16:19:44 +00:00
|
|
|
// This may fail for characters not supported by "unicodesymbols"
|
|
|
|
// or for non-ASCII characters in "listings"
|
|
|
|
// but it is the best we can do.
|
2007-05-07 17:10:10 +00:00
|
|
|
|
2019-02-07 21:07:59 +00:00
|
|
|
// change encoding
|
2022-02-27 19:35:58 +00:00
|
|
|
LYXERR(Debug::OUTFILE, "Changing LaTeX encoding from "
|
2019-02-07 21:07:59 +00:00
|
|
|
<< oldEnc.name() << " to " << newEnc.name());
|
|
|
|
os << setEncoding(newEnc.iconvName());
|
2019-04-16 18:17:32 +00:00
|
|
|
if (bparams.inputenc == "auto-legacy-plain")
|
2019-02-07 21:07:59 +00:00
|
|
|
return make_pair(true, 0);
|
2007-05-07 17:10:10 +00:00
|
|
|
|
2007-12-08 11:21:00 +00:00
|
|
|
docstring const inputenc_arg(from_ascii(newEnc.latexName()));
|
2014-07-05 12:23:43 +00:00
|
|
|
OutputState * state = getOutputState();
|
2007-05-07 17:10:10 +00:00
|
|
|
switch (newEnc.package()) {
|
|
|
|
case Encoding::none:
|
2008-08-18 17:26:09 +00:00
|
|
|
case Encoding::japanese:
|
2019-04-11 16:19:44 +00:00
|
|
|
// shouldn't ever reach here (see above) but avoids warning.
|
2007-07-05 19:19:41 +00:00
|
|
|
return make_pair(true, 0);
|
2007-05-07 17:10:10 +00:00
|
|
|
case Encoding::inputenc: {
|
2020-10-13 21:24:36 +00:00
|
|
|
size_t count = inputenc_arg.length();
|
2007-12-08 11:21:00 +00:00
|
|
|
if (oldEnc.package() == Encoding::CJK &&
|
2014-07-05 12:23:43 +00:00
|
|
|
state->open_encoding_ == CJK) {
|
2007-05-07 17:10:10 +00:00
|
|
|
os << "\\end{CJK}";
|
2014-07-05 12:23:43 +00:00
|
|
|
state->open_encoding_ = none;
|
2007-05-07 17:10:10 +00:00
|
|
|
count += 9;
|
|
|
|
}
|
2007-12-08 11:21:00 +00:00
|
|
|
else if (oldEnc.package() == Encoding::inputenc &&
|
2014-07-05 12:23:43 +00:00
|
|
|
state->open_encoding_ == inputenc) {
|
2007-12-08 11:21:00 +00:00
|
|
|
os << "\\egroup";
|
2014-07-05 12:23:43 +00:00
|
|
|
state->open_encoding_ = none;
|
2007-12-08 11:21:00 +00:00
|
|
|
count += 7;
|
|
|
|
}
|
2019-07-06 19:05:16 +00:00
|
|
|
if (runparams.local_font != nullptr
|
2008-11-16 00:12:21 +00:00
|
|
|
&& oldEnc.package() == Encoding::CJK) {
|
2008-08-19 07:51:40 +00:00
|
|
|
// within insets, \inputenc switches need
|
|
|
|
// to be embraced within \bgroup...\egroup;
|
|
|
|
// else CJK fails.
|
2007-12-08 11:21:00 +00:00
|
|
|
os << "\\bgroup";
|
|
|
|
count += 7;
|
2014-07-05 12:23:43 +00:00
|
|
|
state->open_encoding_ = inputenc;
|
2007-12-08 11:21:00 +00:00
|
|
|
}
|
2019-04-11 16:19:44 +00:00
|
|
|
if (noswitchmacro)
|
2008-08-18 17:26:09 +00:00
|
|
|
return make_pair(true, count);
|
2007-12-08 11:21:00 +00:00
|
|
|
os << "\\inputencoding{" << inputenc_arg << '}';
|
2007-07-05 19:19:41 +00:00
|
|
|
return make_pair(true, count + 16);
|
2007-11-15 20:04:51 +00:00
|
|
|
}
|
2007-05-07 17:10:10 +00:00
|
|
|
case Encoding::CJK: {
|
2020-10-13 21:24:36 +00:00
|
|
|
size_t count = inputenc_arg.length();
|
2008-10-13 11:25:37 +00:00
|
|
|
if (oldEnc.package() == Encoding::CJK &&
|
2014-07-05 12:23:43 +00:00
|
|
|
state->open_encoding_ == CJK) {
|
2007-05-07 17:10:10 +00:00
|
|
|
os << "\\end{CJK}";
|
|
|
|
count += 9;
|
2007-05-06 20:26:02 +00:00
|
|
|
}
|
2008-10-13 11:25:37 +00:00
|
|
|
if (oldEnc.package() == Encoding::inputenc &&
|
2014-07-05 12:23:43 +00:00
|
|
|
state->open_encoding_ == inputenc) {
|
2007-12-08 11:21:00 +00:00
|
|
|
os << "\\egroup";
|
|
|
|
count += 7;
|
|
|
|
}
|
2019-02-27 13:01:53 +00:00
|
|
|
os << "\\begin{CJK}{"
|
|
|
|
<< from_ascii(newEnc.latexName()) << "}{"
|
2010-11-26 18:32:29 +00:00
|
|
|
<< from_ascii(bparams.fonts_cjk) << "}";
|
2014-07-05 12:23:43 +00:00
|
|
|
state->open_encoding_ = CJK;
|
2007-07-05 19:19:41 +00:00
|
|
|
return make_pair(true, count + 15);
|
2007-01-13 14:36:54 +00:00
|
|
|
}
|
2007-01-09 19:25:40 +00:00
|
|
|
}
|
2007-05-07 17:10:10 +00:00
|
|
|
// Dead code to avoid a warning:
|
2007-07-05 19:19:41 +00:00
|
|
|
return make_pair(true, 0);
|
2007-01-09 19:25:40 +00:00
|
|
|
}
|
|
|
|
|
2006-10-21 00:16:43 +00:00
|
|
|
} // namespace lyx
|