Hi!
Attached find a cleaned up version of the patch for 1820, based on the
explanations I provided last night
(http://permalink.gmane.org/gmane.editors.lyx.devel/89979).
I now feel quite confident that this patch is good. I tried it on all
the sample files I have and that I created, I tried it on the sample
files Enrico sent in on Friday, and I also tried it on most of the LyX
files that I just happen to have lying around --- and it does the right
thing for all of them. Still, I would be very happy to have other people
test it and provide feedback.
There are one or two FIXMEs in the patch --- if anyone can help me with
them, that would be great, I'll try to work on them myself, too. But The
patch should be applied even in its current form.
There's still the issue of a lyx2lyx for this, as this *is* a format
change. I'm not sure how to go about this, though. First of all, as I
already explained, the patch only fixes things which were outputting
*incorrectly* (i.e., the output did not match the GUI) and now it does.
So do we really want to force the *wrong* display for old files?
Secondly, some of the fixes here actually fix things which caused
encoding errors previously --- obviously, we don't try to simulate
those, too... In a word --- I need help from the lyx2lyx people for this
part.
Dov
Index: src/output_latex.cpp
===================================================================
--- src/output_latex.cpp (revision 19080)
+++ src/output_latex.cpp (working copy)
@@ -259,14 +259,23 @@
OutputParams runparams = runparams_in;
runparams.moving_arg |= style->needprotect;
+ // This paragraph's language
Language const * const par_language = pit->getParLanguage(bparams);
+ // The document's language
Language const * const doc_language = bparams.language;
- Language const * const prev_par_language =
- (pit != paragraphs.begin())
- ? boost::prior(pit)->getParLanguage(bparams)
- : doc_language;
+ // The language that was in effect when the environemnt this paragraph
is
+ // inside of was opened
+ Language const * const outer_language =
+ (runparams.local_font != 0) ?
+ runparams.local_font->language() : doc_language;
+ // The previous language that was in effect is either the language of
+ // the previous paragraph, if there is one, or else the outer language
+ // if there is no previous paragraph
+ Language const * const prev_language =
+ (pit != paragraphs.begin()) ?
+ boost::prior(pit)->getParLanguage(bparams) :
outer_language;
- if (par_language->babel() != prev_par_language->babel()
+ if (par_language->babel() != prev_language->babel()
// check if we already put language command in TeXEnvironment()
&& !(style->isEnvironment()
&& (pit == paragraphs.begin() ||
@@ -275,19 +284,47 @@
|| boost::prior(pit)->getDepth() < pit->getDepth())))
{
if (!lyxrc.language_command_end.empty() &&
- prev_par_language->babel() != doc_language->babel() &&
- !prev_par_language->babel().empty())
+ prev_language->babel() != outer_language->babel() &&
+ !prev_language->babel().empty())
{
os << from_ascii(subst(lyxrc.language_command_end,
"$$lang",
- prev_par_language->babel()))
+ prev_language->babel()))
<< '\n';
texrow.newline();
}
+ // We need to open a new language if we couldn't close the
previous
+ // one (because there's no language_command_end); and even if
we closed
+ // the previous one, if the current language is different than
the
+ // outer_language (which is currently in effect once the
previous one
+ // is closed).
if ((lyxrc.language_command_end.empty() ||
- par_language->babel() != doc_language->babel()) &&
+ par_language->babel() != outer_language->babel()) &&
!par_language->babel().empty()) {
+ // If we're inside an inset, and that inset is within
an \L or \R
+ // (or equivalents), then within the inset, too, any
opposite
+ // language paragraph should appear within an \L or \R
(in addition
+ // to, outside of, the normal language switch commands).
+ if (lyxrc.rtl_support &&
+ // are we in an inset?
+ runparams.local_font != 0 &&
+ // is the inset within an \L or \R?
+ //
+ // FIXME: currently, we don't check
this; this means that
+ // we'll have unnnecessary \L and \R
commands, but that
+ // doesn't seem to hurt (though latex
will complain)
+ //
+ // is this paragraph in the opposite
direction?
+ runparams.local_font->isRightToLeft() !=
+ par_language->rightToLeft()) {
+ // FIXME: instead of \\R, \\L, use correct
form, depending
+ // on the language (arabic, farsi, etc.)
+ if (par_language->rightToLeft())
+ os << "\\R{";
+ else
+ os << "\\L{";
+ }
os << from_ascii(subst(
lyxrc.language_command_begin,
"$$lang",
@@ -457,8 +494,23 @@
}
}
- if (boost::next(pit) == paragraphs.end()
- && par_language->babel() != doc_language->babel()) {
+ // Closing the language is needed for the last paragraph; it is also
+ // needed if we're within an \L or \R that we may have opened above (not
+ // necessarily in this paragraph) and are about to close.
+ bool closing_rtl_ltr_environment =
+ lyxrc.rtl_support &&
+ // have we opened and \L or \R environment?
+ runparams.local_font != 0 &&
+ runparams.local_font->isRightToLeft() !=
par_language->rightToLeft() &&
+ // are we about to close the language?
+ ((boost::next(pit) != paragraphs.end() &&
+ par_language->babel() !=
+ (boost::next(pit)->getParLanguage(bparams))->babel()) ||
+ (boost::next(pit) == paragraphs.end() &&
+ par_language->babel() != outer_language->babel()));
+
+ if (closing_rtl_ltr_environment || (boost::next(pit) == paragraphs.end()
+ && par_language->babel() != outer_language->babel())) {
// Since \selectlanguage write the language to the aux file,
// we need to reset the language at the end of footnote or
// float.
@@ -468,11 +520,11 @@
texrow.newline();
}
if (lyxrc.language_command_end.empty()) {
- if (!doc_language->babel().empty()) {
+ if (!prev_language->babel().empty()) {
os << from_ascii(subst(
lyxrc.language_command_begin,
"$$lang",
- doc_language->babel()));
+ prev_language->babel()));
pending_newline = true;
}
} else if (!par_language->babel().empty()) {
@@ -483,13 +535,28 @@
pending_newline = true;
}
}
+ if (closing_rtl_ltr_environment)
+ os << "}";
if (pending_newline) {
os << '\n';
texrow.newline();
}
- runparams_in.encoding = runparams.encoding;
+ // If this is the last paragraph, and a local_font was set upon entering
+ // the inset, the encoding should be set back to that local_font's
+ // encoding. We don't use switchEncoding(), because no explicit encoding
+ // switch command is needed, since latex will automatically revert to it
+ // when this inset closes.
+ if (boost::next(pit) == paragraphs.end() && runparams_in.local_font !=
0) {
+ runparams_in.encoding =
runparams_in.local_font->language()->encoding();
+ os << setEncoding(runparams_in.encoding->iconvName());
+ }
+ // Otherwise, the current encoding should be set for the next paragraph.
+ else
+ runparams_in.encoding = runparams.encoding;
+
+
// we don't need it for the last paragraph!!!
// Note from JMarc: we will re-add a \n explicitely in
// TeXEnvironment, because it is needed in this case
Index: src/Font.cpp
===================================================================
--- src/Font.cpp (revision 19080)
+++ src/Font.cpp (working copy)
@@ -875,7 +875,8 @@
int Font::latexWriteEndChanges(odocstream & os, BufferParams const & bparams,
OutputParams const & runparams,
Font const & base,
- Font const & next) const
+ Font const & next,
+ bool const & closeLanguage) const
{
int count = 0;
bool env = false;
@@ -953,7 +954,8 @@
open_encoding_ = false;
}
- if (language() != base.language() && language() != next.language()) {
+ if (closeLanguage &&
+ language() != base.language() && language() !=
next.language()) {
os << '}';
++count;
}
Index: src/Font.h
===================================================================
--- src/Font.h (revision 19080)
+++ src/Font.h (working copy)
@@ -309,7 +309,8 @@
int latexWriteEndChanges(odocstream &, BufferParams const & bparams,
OutputParams const & runparams,
Font const & base,
- Font const & next) const;
+ Font const & next,
+ bool const & closeLanguage = true) const;
/// Build GUI description of font state
Index: src/Paragraph.cpp
===================================================================
--- src/Paragraph.cpp (revision 19080)
+++ src/Paragraph.cpp (working copy)
@@ -191,7 +191,7 @@
///
void simpleTeXSpecialChars(Buffer const &, BufferParams const &,
odocstream &,
- TexRow & texrow, OutputParams const &,
+ TexRow & texrow, OutputParams &,
Font & running_font,
Font & basefont,
Font const & outerfont,
@@ -662,7 +662,7 @@
BufferParams const & bparams,
odocstream & os,
TexRow & texrow,
- OutputParams const & runparams,
+ OutputParams & runparams,
Font & running_font,
Font & basefont,
Font const & outerfont,
@@ -752,14 +752,32 @@
// right now, which means stupid latex code like \textsf{}. AFAIK,
// this does not harm dvi output. A minor bug, thus (JMarc)
#endif
- // some insets cannot be inside a font change command
+ // Some insets cannot be inside a font change command.
+ // However, even such insets *can* be placed in \L or \R
+ // or their equivalents (for RTL language switches), so we don't
+ // close the language in those cases.
if (open_font && inset->noFontChange()) {
- column += running_font.latexWriteEndChanges(
+ bool closeLanguage =
+ (basefont.isRightToLeft() ==
running_font.isRightToLeft());
+ unsigned int count = running_font.latexWriteEndChanges(
os, bparams, runparams,
- basefont, basefont);
- open_font = false;
- basefont = owner_->getLayoutFont(bparams, outerfont);
- running_font = basefont;
+ basefont, basefont,
closeLanguage);
+ column += count;
+ // if any font properties were closed, update the
running_font,
+ // making sure, however, to leave the language as it was
+ if (count > 0) {
+ // FIXME: probably a better way to keep track
of the old
+ // language, than copying the entire font?
+ Font const copy_font(running_font);
+ basefont = owner_->getLayoutFont(bparams,
outerfont);
+ running_font = basefont;
+ if (!closeLanguage)
+
running_font.setLanguage(copy_font.language());
+ // leave font open if language is still open
+ open_font = (running_font.language() ==
basefont.language());
+ if (closeLanguage)
+ runparams.local_font = &basefont;
+ }
}
int tmp = inset->latex(buf, os, runparams);