Hi!

I cleaned up the patches a bit more.

* Finally removed Text::bidi (its global status was not necessary anymore after the no_bidi_isboundary patch), see local_bidi.patch
* Fixed the behavior if RTL is disabled in the preference dialog
* Fixed the EPM. Try out the "ABC[ DEF] ghi" example again that some of you reported * Fixed isRTLBoundary at paragraph end, as it was before (i.e. RTL at paragraph end will give a RTL boundary) * Added another isRTLBoundary variation that compares to a font (as it is also implemented in Bidi.cpp). That was the last missing piece to remove Text::bidi. * Rewrote the getPosVisuallyWay into a more general getPosVisually method of Text. @Dov: I think you should be able to implement visual cursor mode with that easily

Order to apply:

no_bidi_isboundary.patch
no_bidi_setcurrentfont.patch
local_bidi.patch
cursor_get_font.patch
rtl_spaces.patch

Stefan
Index: lyx-devel/src/Text.cpp
===================================================================
--- lyx-devel.orig/src/Text.cpp 2007-06-07 14:36:38.000000000 +0200
+++ lyx-devel/src/Text.cpp      2007-06-07 15:11:28.000000000 +0200
@@ -1524,7 +1524,7 @@
                // but for RTL boundaries don't, because: abc|DDEEFFghi -> 
abcDDEEF|Fghi
                if (cur.boundary()) {
                        cur.boundary(false);
-               }       else if (bidi.isBoundary(buffer, cur.paragraph(), 
cur.pos() + 1)) {
+               }       else if (isRTLBoundary(buffer, cur.paragraph(), 
cur.pos() + 1)) {
                        // in front of RTL boundary -> Stay on this side of the 
boundary because:
                        //   ab|cDDEEFFghi -> abc|DDEEFFghi
                        ++cur.pos();
Index: lyx-devel/src/Text.h
===================================================================
--- lyx-devel.orig/src/Text.h   2007-06-07 14:36:38.000000000 +0200
+++ lyx-devel/src/Text.h        2007-06-07 15:11:28.000000000 +0200
@@ -335,6 +335,13 @@
        bool isRTL(Buffer const &, Paragraph const & par) const;
        /// is this position in the paragraph right-to-left?
        bool isRTL(Buffer const & buffer, CursorSlice const & sl, bool 
boundary) const;
+       /// is between pos-1 and pos an RTL<->LTR boundary?
+       bool isRTLBoundary(Buffer const & buffer, Paragraph const & par,
+         pos_type pos) const;
+       /// would be a RTL<->LTR boundary between pos and the given font?
+       bool isRTLBoundary(Buffer const & buffer, Paragraph const & par,
+         pos_type pos, Font const & font) const;
+
        ///
        bool checkAndActivateInset(Cursor & cur, bool front);
 
Index: lyx-devel/src/Text2.cpp
===================================================================
--- lyx-devel.orig/src/Text2.cpp        2007-06-07 14:36:38.000000000 +0200
+++ lyx-devel/src/Text2.cpp     2007-06-07 15:11:44.000000000 +0200
@@ -795,7 +795,7 @@
        real_current_font = getFont(cur.buffer(), par, pos);
 
        if (cur.pos() == cur.lastpos()
-           && bidi.isBoundary(cur.buffer(), par, cur.pos())
+           && isRTLBoundary(cur.buffer(), par, cur.pos())
            && !cur.boundary()) {
                Language const * lang = par.getParLanguage(bufparams);
                current_font.setLanguage(lang);
@@ -1037,7 +1037,7 @@
                // if left of boundary -> just jump to right side
          // but for RTL boundaries don't, because: abc|DDEEFFghi -> 
abcDDEEF|Fghi
          if (cur.boundary() && 
-                               !bidi.isBoundary(cur.buffer(), cur.paragraph(), 
cur.pos()))
+                               !isRTLBoundary(cur.buffer(), cur.paragraph(), 
cur.pos()))
                        return setCursor(cur, cur.pit(), cur.pos(), true, 
false);
 
                // next position is left of boundary, 
@@ -1066,7 +1066,7 @@
                
                // in front of RTL boundary? Stay on this side of the boundary 
because:
                //   ab|cDDEEFFghi -> abc|DDEEFFghi
-               if (bidi.isBoundary(cur.buffer(), cur.paragraph(), cur.pos() + 
1))
+               if (isRTLBoundary(cur.buffer(), cur.paragraph(), cur.pos() + 1))
                        return setCursor(cur, cur.pit(), cur.pos() + 1, true, 
true);
                
                // move right
Index: lyx-devel/src/Text3.cpp
===================================================================
--- lyx-devel.orig/src/Text3.cpp        2007-06-07 14:36:38.000000000 +0200
+++ lyx-devel/src/Text3.cpp     2007-06-07 14:37:45.000000000 +0200
@@ -99,7 +99,6 @@
        Font freefont(Font::ALL_IGNORE);
        bool toggleall = false;
 
-
        void toggleAndShow(Cursor & cur, Text * text,
                Font const & font, bool toggleall = true)
        {
@@ -108,13 +107,10 @@
                if (font.language() != ignore_language ||
                                font.number() != Font::IGNORE) {
                        Paragraph & par = cur.paragraph();
-                       text->bidi.computeTables(par, cur.buffer(), 
cur.textRow());
-                       if (cur.boundary() !=
-                                       text->bidi.isBoundary(cur.buffer(), par,
-                                                       cur.pos(),
-                                                       
text->real_current_font))
+                       if (cur.boundary() != text->isRTLBoundary(cur.buffer(), 
par,
+                                               cur.pos(), 
text->real_current_font))
                                text->setCursor(cur, cur.pit(), cur.pos(),
-                                               false, !cur.boundary());
+                                               false, !cur.boundary());
                }
        }
 
@@ -301,7 +297,7 @@
 
 bool Text::isRTL(Buffer const & buffer, CursorSlice const & sl, bool boundary) 
const
 {
-       if (!sl.text())
+       if (!lyxrc.rtl_support && !sl.text())
                return false;
 
        int correction = 0;
@@ -313,6 +309,42 @@
 }
 
 
+bool Text::isRTLBoundary(Buffer const & buffer, Paragraph const & par,
+                         pos_type pos) const
+{
+       if (!lyxrc.rtl_support)
+               return false;
+
+       // no RTL boundary at line start
+       if (pos == 0)
+               return false;
+
+       bool left = getFont(buffer, par, pos - 1).isVisibleRightToLeft();
+       bool right;
+       if (pos == par.size())
+               right = par.isRightToLeftPar(buffer.params());
+       else
+               right = getFont(buffer, par, pos).isVisibleRightToLeft();
+       return left != right;
+}
+
+
+bool Text::isRTLBoundary(Buffer const & buffer, Paragraph const & par,
+                         pos_type pos, Font const & font) const
+{
+       if (!lyxrc.rtl_support)
+               return false;
+
+       bool left = font.isVisibleRightToLeft();
+       bool right;
+       if (pos == par.size())
+               right = par.isRightToLeftPar(buffer.params());
+       else
+               right = getFont(buffer, par, pos).isVisibleRightToLeft();
+       return left != right;
+}
+
+
 void Text::dispatch(Cursor & cur, FuncRequest & cmd)
 {
        LYXERR(Debug::ACTION) << "Text::dispatch: cmd: " << cmd << endl;
Index: lyx-devel/src/TextMetrics.cpp
===================================================================
--- lyx-devel.orig/src/TextMetrics.cpp  2007-06-07 14:36:38.000000000 +0200
+++ lyx-devel/src/TextMetrics.cpp       2007-06-07 15:11:28.000000000 +0200
@@ -893,7 +893,7 @@
                bool const rtl = (text_->bidi.level(c) % 2 == 1);
                if (left_side == rtl) {
                        ++c;
-                       boundary = text_->bidi.isBoundary(buffer, par, c);
+                       boundary = text_->isRTLBoundary(buffer, par, c);
                }
        }
 
Index: lyx-devel/src/Text.cpp
===================================================================
--- lyx-devel.orig/src/Text.cpp 2007-06-07 14:36:42.000000000 +0200
+++ lyx-devel/src/Text.cpp      2007-06-07 15:10:19.000000000 +0200
@@ -1695,6 +1695,8 @@
        Buffer const & buffer = *bv.buffer();
        RowMetrics const m = tm.computeRowMetrics(pit, row);
        double x = m.x;
+       Bidi bidi;
+       bidi.computeTables(par, buffer, row);
 
        pos_type const row_pos  = row.pos();
        pos_type const end      = row.endpos();
Index: lyx-devel/src/Text.h
===================================================================
--- lyx-devel.orig/src/Text.h   2007-06-07 14:36:42.000000000 +0200
+++ lyx-devel/src/Text.h        2007-06-07 15:10:19.000000000 +0200
@@ -379,8 +379,6 @@
        int background_color_;
 
        ///
-       mutable Bidi bidi;
-       ///
        ParagraphList pars_;
 
        /// our 'outermost' font. This is handed down from the surrounding
Index: lyx-devel/src/rowpainter.cpp
===================================================================
--- lyx-devel.orig/src/rowpainter.cpp   2007-06-07 14:36:21.000000000 +0200
+++ lyx-devel/src/rowpainter.cpp        2007-06-07 14:38:19.000000000 +0200
@@ -13,6 +13,7 @@
 
 #include "rowpainter.h"
 
+#include "Bidi.h"
 #include "Buffer.h"
 #include "CoordCache.h"
 #include "Cursor.h"
@@ -113,6 +114,9 @@
        ParagraphMetrics const & pm_;
        int max_width_;
 
+       ///
+       Bidi bidi_;
+
        /// is row erased? (change tracking)
        bool erased_;
 
@@ -135,10 +139,11 @@
          row_(row), pit_(pit), par_(text.paragraphs()[pit]),
          pm_(text_metrics_.parMetrics(pit)),
          max_width_(bv_.workWidth()),
-         erased_(pi.erased_),
+               bidi_(), erased_(pi.erased_),
          xo_(x), yo_(y), width_(text_metrics_.width())
 {
        RowMetrics m = text_metrics_.computeRowMetrics(pit_, row_);
+       bidi_.computeTables(par_, *bv_.buffer(), row_);
        x_ = m.x + xo_;
 
        //lyxerr << "RowPainter: x: " << x_ << " xo: " << xo_ << " yo: " << yo_ 
<< endl;
@@ -180,7 +185,7 @@
        pi.base.font = inset->noFontChange() ?
                bv_.buffer()->params().getFont() :
                font;
-       pi.ltr_pos = (text_.bidi.level(pos) % 2 == 0);
+       pi.ltr_pos = (bidi_.level(pos) % 2 == 0);
        pi.erased_ = erased_ || par_.isDeleted(pos);
 #ifdef DEBUG_METRICS
        int const x1 = int(x_);
@@ -233,7 +238,7 @@
 
 void RowPainter::paintHebrewComposeChar(pos_type & vpos, Font const & font)
 {
-       pos_type pos = text_.bidi.vis2log(vpos);
+       pos_type pos = bidi_.vis2log(vpos);
 
        docstring str;
 
@@ -267,7 +272,7 @@
 
 void RowPainter::paintArabicComposeChar(pos_type & vpos, Font const & font)
 {
-       pos_type pos = text_.bidi.vis2log(vpos);
+       pos_type pos = bidi_.vis2log(vpos);
        docstring str;
 
        // first char
@@ -299,7 +304,7 @@
                            bool hebrew, bool arabic)
 {
        // This method takes up 70% of time when typing
-       pos_type pos = text_.bidi.vis2log(vpos);
+       pos_type pos = bidi_.vis2log(vpos);
        pos_type const end = row_.endpos();
        FontSpan const font_span = par_.fontSpan(pos);
        Change::Type const prev_change = par_.lookupChange(pos).type;
@@ -320,7 +325,7 @@
 
        // collect as much similar chars as we can
        for (++vpos ; vpos < end ; ++vpos) {
-               pos = text_.bidi.vis2log(vpos);
+               pos = bidi_.vis2log(vpos);
                if (pos < font_span.first || pos > font_span.last)
                        break;
 
@@ -403,7 +408,7 @@
 
 void RowPainter::paintFromPos(pos_type & vpos)
 {
-       pos_type const pos = text_.bidi.vis2log(vpos);
+       pos_type const pos = bidi_.vis2log(vpos);
        Font orig_font = text_.getFont(*bv_.buffer(), par_, pos);
 
        double const orig_x = x_;
@@ -747,7 +752,7 @@
                if (x_ > bv_.workWidth())
                        break;
 
-               pos_type const pos = text_.bidi.vis2log(vpos);
+               pos_type const pos = bidi_.vis2log(vpos);
 
                if (pos >= par_.size()) {
                        ++vpos;
Index: lyx-devel/src/TextMetrics.cpp
===================================================================
--- lyx-devel.orig/src/TextMetrics.cpp  2007-06-07 14:36:42.000000000 +0200
+++ lyx-devel/src/TextMetrics.cpp       2007-06-07 14:38:19.000000000 +0200
@@ -375,7 +375,6 @@
                }
        }
 
-       text_->bidi.computeTables(par, buffer, row);
        if (is_rtl) {
                pos_type body_pos = par.beginOfBody();
                pos_type end = row.endpos();
@@ -812,6 +811,8 @@
        x -= xo;
        RowMetrics const r = computeRowMetrics(pit, row);
        Paragraph const & par = text_->getPar(pit);
+       Bidi bidi;
+       bidi.computeTables(par, buffer, row);
 
        pos_type vc = row.pos();
        pos_type end = row.endpos();
@@ -839,7 +840,7 @@
                = theFontMetrics(text_->getLabelFont(buffer, par));
 
        while (vc < end && tmpx <= x) {
-               c = text_->bidi.vis2log(vc);
+               c = bidi.vis2log(vc);
                last_tmpx = tmpx;
                if (body_pos > 0 && c == body_pos - 1) {
                        // FIXME UNICODE
@@ -885,12 +886,12 @@
             (!rtl && !left_side && vc == end  && x > tmpx + 5)))
                c = end;
        else if (vc == row.pos()) {
-               c = text_->bidi.vis2log(vc);
-               if (text_->bidi.level(c) % 2 == 1)
+               c = bidi.vis2log(vc);
+               if (bidi.level(c) % 2 == 1)
                        ++c;
        } else {
-               c = text_->bidi.vis2log(vc - 1);
-               bool const rtl = (text_->bidi.level(c) % 2 == 1);
+               c = bidi.vis2log(vc - 1);
+               bool const rtl = (bidi.level(c) % 2 == 1);
                if (left_side == rtl) {
                        ++c;
                        boundary = text_->isRTLBoundary(buffer, par, c);
@@ -906,7 +907,7 @@
        // specially, so cursor up/down doesn't get stuck in an air gap -- MV
        // Newline inset, air gap below:
        if (row.pos() < end && c >= end && par.isNewline(end - 1)) {
-               if (text_->bidi.level(end -1) % 2 == 0)
+               if (bidi.level(end -1) % 2 == 0)
                        tmpx -= text_->singleWidth(buffer, par, end - 1);
                else
                        tmpx += text_->singleWidth(buffer, par, end - 1);
Index: lyx-devel/src/Cursor.cpp
===================================================================
--- lyx-devel.orig/src/Cursor.cpp       2007-06-06 10:16:43.000000000 +0200
+++ lyx-devel/src/Cursor.cpp    2007-06-06 10:37:01.000000000 +0200
@@ -1438,18 +1438,36 @@
 
 Font Cursor::getFont() const
 {
+       // The logic here should more or less match to the Text::setCurrentFont
+       // logic, i.e. the cursor height should give a hint what will happen
+       // if a character is entered.
+       
        // HACK. far from being perfect...
-       int s = 0;
        // go up until first non-0 text is hit
        // (innermost text is 0 in mathed)
+       int s = 0;
        for (s = depth() - 1; s >= 0; --s)
                if (operator[](s).text())
                        break;
        CursorSlice const & sl = operator[](s);
        Text const & text = *sl.text();
-       Font font = text.getPar(sl.pit()).getFont(
-               bv().buffer()->params(),
-               sl.pos(),
+       Paragraph const & par = text.getPar(sl.pit());
+       
+       // on boundary, so we are really at the character before
+       pos_type pos = sl.pos();
+       if (pos > 0 && boundary())
+               --pos;
+       
+       // on space? Take the font before (only for RTL boundary stay)
+       if (pos > 0) {
+               if (pos == sl.lastpos()
+                               || (par.isSeparator(pos) && 
+                                               !text.isRTLBoundary(buffer(), 
par, pos)))
+                       --pos;
+       }
+       
+       // get font at the position
+       Font font = par.getFont(bv().buffer()->params(), pos,
                outerFont(sl.pit(), text.paragraphs()));
 
        return font;
no_bidi_isboundary.patch
no_bidi_setcurrentfont.patch
local_bidi.patch
cursor_get_font.patch
rtl_spaces.patch
Index: lyx-devel/src/Text2.cpp
===================================================================
--- lyx-devel.orig/src/Text2.cpp        2007-06-07 14:37:55.000000000 +0200
+++ lyx-devel/src/Text2.cpp     2007-06-07 15:10:19.000000000 +0200
@@ -11,6 +11,7 @@
  * \author John Levon
  * \author André Pönitz
  * \author Allan Rae
+ * \author Stefan Schimanski
  * \author Dekel Tsur
  * \author Jürgen Vigna
  *
@@ -760,40 +761,31 @@
        pos_type pos = cur.pos();
        Paragraph & par = cur.paragraph();
 
-       // ignore empty paragraph
-       if (par.empty())
-               return;
-       
-       // if on boundary or at paragraph end, set font of previous char
-       if ((pos > 0 && cur.boundary()) || pos == cur.lastpos())
+       // are we behind previous char in fact? -> go to that char
+       if (pos > 0 && cur.boundary())
                --pos;
-       
-       // we changed the line and the bidi tables are outdated?
-       if (!bidi.inRange(pos))
-               bidi.computeTables(par, cur.buffer(), cur.textRow());
-
-       // now in range?
-       if (!bidi.inRange(pos))
-               return;
 
-       if (pos > 0) {
+       // find position to take the font from
+       if (pos != 0) {
+               // paragraph end? -> font of last char
                if (pos == cur.lastpos())
                        --pos;
-               else // potentional bug... BUG (Lgb)
-                       if (par.isSeparator(pos)) {
-                               if (pos > cur.textRow().pos() &&
-                                   bidi.level(pos) % 2 ==
-                                   bidi.level(pos - 1) % 2)
-                                       --pos;
-                               else if (pos + 1 < cur.lastpos())
-                                       ++pos;
-                       }
+               // on space? -> look at the words in front of space
+               else if (pos > 0 && par.isSeparator(pos))       {
+                       // abc| def -> font of c
+                       // abc |[WERBEH], i.e. boundary==true -> font of c
+                       // abc [WERBEH]| def, font of the space
+                       if (!isRTLBoundary(cur.buffer(), par, pos))
+                               --pos;
+               }
        }
 
+       // get font
        BufferParams const & bufparams = cur.buffer().params();
        current_font = par.getFontSettings(bufparams, pos);
        real_current_font = getFont(cur.buffer(), par, pos);
 
+       // special case for paragraph end
        if (cur.pos() == cur.lastpos()
            && isRTLBoundary(cur.buffer(), par, cur.pos())
            && !cur.boundary()) {
Index: lyx-devel/src/Bidi.cpp
===================================================================
--- lyx-devel.orig/src/Bidi.cpp 2007-06-07 15:10:19.000000000 +0200
+++ lyx-devel/src/Bidi.cpp      2007-06-07 15:12:35.000000000 +0200
@@ -95,7 +95,11 @@
        pos_type const body_pos = par.beginOfBody();
 
        for (pos_type lpos = start_; lpos <= end_; ++lpos) {
-               bool is_space = par.isLineSeparator(lpos);
+               bool is_space = false;
+               // We do not handle spaces around an RTL segment in a special 
way anymore.
+               // Neither does LaTeX, so setting is_spacs to false makes the 
view in LyX
+               // consistent with the output of LaTeX later. The old setting 
was:
+               // is_space = par.isLineSeparator(lpos);
                pos_type const pos =
                        (is_space && lpos + 1 <= end_ &&
                         !par.isLineSeparator(lpos + 1) &&
Index: lyx-devel/src/Text.cpp
===================================================================
--- lyx-devel.orig/src/Text.cpp 2007-06-07 15:12:34.000000000 +0200
+++ lyx-devel/src/Text.cpp      2007-06-07 15:12:35.000000000 +0200
@@ -732,8 +732,22 @@
                        return;
                }
                BOOST_ASSERT(cur.pos() > 0);
-               if ((par.isLineSeparator(cur.pos() - 1) || 
par.isNewline(cur.pos() - 1))
-                   && !par.isDeleted(cur.pos() - 1)) {
+               
+               // get character position visually in front of cur.pos()
+               pos_type prevpos;
+               if (cur.boundary())
+                       prevpos = cur.pos() - 1;
+               else {
+                       bool rtl = isRTL(cur.buffer(), cur.top(), 
cur.boundary());
+                       prevpos = getPosVisually(cur.bv(), cur.pit(), 
cur.pos(), false, 
+                                                                               
                                         rtl ? 1 : -1);
+               }
+                       
+               // no space if previous was space (or newline),
+               if (prevpos != cur.pos()
+                               && 0 <= prevpos && prevpos < par.size()
+                               && (par.isLineSeparator(prevpos) || 
par.isNewline(prevpos))
+                   && !par.isDeleted(prevpos)) {
                        static bool sent_space_message = false;
                        if (!sent_space_message) {
                                cur.message(_("You cannot type two spaces this 
way. "
Index: lyx-devel/src/Text2.cpp
===================================================================
--- lyx-devel.orig/src/Text2.cpp        2007-06-07 15:12:34.000000000 +0200
+++ lyx-devel/src/Text2.cpp     2007-06-07 15:12:35.000000000 +0200
@@ -1114,6 +1114,72 @@
 }
 
 
+pos_type Text::getPosVisually(BufferView const & bv, pit_type pit,
+  pos_type pos, bool boundary, int visualDist) const
+{
+       Paragraph const & par = getPar(pit);
+       ParagraphMetrics const & pm = bv.parMetrics(this, pit);
+       pos_type oldpos = pos;
+       
+       // if RTL support is not enabled
+       if (!lyxrc.rtl_support) {
+               pos += visualDist;
+               if (pos < 0)
+                       return 0;
+               if (pos > par.size())
+                       return par.size();
+               return pos;
+       }
+       
+       // initialize the starting row and bidi tables
+       Bidi bidi;
+       Row const & row = pm.getRow(pos, boundary);
+       bidi.computeTables(par, *bv.buffer(), row);
+       
+       // try to find position
+       while (true) {
+               // Convert to visual position
+               if (!bidi.inRange(pos))
+                       return oldpos;
+               pos_type vstart = bidi.log2vis(pos);
+               
+               // Go to the character visualDist away
+               //bool backward = bidi.level(corrected_pos) & 1;
+               pos_type vpos = vstart + visualDist; //backward ? (vstart - 
visualDist) : (vstart + visualDist);
+               if (!bidi.inRange(vpos)) {
+                       // end of paragraph?
+                       if (vpos == par.size())
+                               return par.size();
+                       
+                       // out of paragraph? Return oldpos, i.e. we couldn't 
find the position
+                       if (vpos < 0 || vpos > par.size())
+                               return oldpos;
+                       
+                       // we might have changed the row. Try in the next/prev 
one
+                       if (visualDist > 0) {
+                               vstart = row.endpos();
+                               boundary = false;
+                               visualDist -= row.endpos() - vstart;
+                       } else {
+                               vstart = row.pos();
+                               boundary = true;
+                               visualDist -= vstart - row.pos();
+                       }
+               } else {
+                       // We found it -> convert back to logical position
+                       pos = bidi.vis2log(vpos);
+                       break;
+               }
+               
+               // update the bidi tables for next iteration
+               Row const & row = pm.getRow(vstart, boundary);
+               bidi.computeTables(par, *bv.buffer(), row);
+       }
+       
+       return pos;
+}
+
+
 bool Text::deleteEmptyParagraphMechanism(Cursor & cur,
                Cursor & old, bool & need_anchor_change)
 {
@@ -1144,29 +1210,48 @@
 
        bool const same_inset = &old.inset() == &cur.inset();
        bool const same_par = same_inset && old.pit() == cur.pit();
-       bool const same_par_pos = same_par && old.pos() == cur.pos();
+       bool const same_par_pos = same_par && old.pos() == cur.pos() &&
+               old.boundary() == cur.boundary();
 
        // If the chars around the old cursor were spaces, delete one of them.
        if (!same_par_pos) {
-               // Only if the cursor has really moved.
-               if (old.pos() > 0
-                   && old.pos() < oldpar.size()
-                   && oldpar.isLineSeparator(old.pos())
-                   && oldpar.isLineSeparator(old.pos() - 1)
-                   && !oldpar.isDeleted(old.pos() - 1)) {
-                       oldpar.eraseChar(old.pos() - 1, 
cur.buffer().params().trackChanges);
+               // What is position of the char visually after the entered 
space? 
+               // Non-trivial on bidi boundaries:
+               // Case 1: "abc [|WERBEH] ghi" ==> "abc [| WERBEH] ghi"
+               // Case 2: "abc|[ WERBEH] ghi" ==> "abc |[ WERBEH] ghi"
+               // Case 3: "abc [WERBEH ]|ghi" ==> "abc [WERBEH ] |ghi"
+               // Case 4: "abc [WERBEH|] ghi" ==> "abc [WERBEH| ] ghi"
+               
+               // Was a space entered?
+               pos_type spacepos = old.pos() - 1;
+               if (spacepos >= 0 && spacepos < oldpar.size()
+                               && oldpar.isLineSeparator(spacepos)
+                               && !oldpar.isDeleted(spacepos)) {
+                       
+                       // Get visually following character position
+                       pos_type nextpos;
+                       bool rtl = old.text()->isRTL(old.buffer(), old.top(), 
old.boundary());
+                       nextpos = old.text()->getPosVisually(old.bv(), 
old.pit(), spacepos, 
+                                                            false, rtl ? -1 : 
1);
+                       
+                       // Is a space following?
+                       if (nextpos != spacepos 
+                                       && nextpos >= 0 && nextpos < 
oldpar.size()
+                                       && oldpar.isLineSeparator(nextpos)) {
+                               oldpar.eraseChar(spacepos, 
cur.buffer().params().trackChanges);
 #ifdef WITH_WARNINGS
 #warning This will not work anymore when we have multiple views of the same 
buffer
 // In this case, we will have to correct also the cursors held by
 // other bufferviews. It will probably be easier to do that in a more
 // automated way in CursorSlice code. (JMarc 26/09/2001)
 #endif
-                       // correct all cursor parts
-                       if (same_par) {
-                               fixCursorAfterDelete(cur.top(), old.top());
-                               need_anchor_change = true;
+                               // correct all cursor parts
+                               if (same_par) {
+                                       fixCursorAfterDelete(cur.top(), 
old.top());
+                                       need_anchor_change = true;
+                               }
+                               return true;
                        }
-                       return true;
                }
        }
 
Index: lyx-devel/src/Text.h
===================================================================
--- lyx-devel.orig/src/Text.h   2007-06-07 15:12:34.000000000 +0200
+++ lyx-devel/src/Text.h        2007-06-07 15:12:35.000000000 +0200
@@ -365,6 +365,11 @@
        /// now because recordUndo() is called which needs a Cursor.
        static bool deleteEmptyParagraphMechanism(Cursor & cur,
                Cursor & old, bool & need_anchor_change);
+       
+       /// Get logical position visualDist positions visually away from pos, 
+       /// If there is no position like that, the old value of pos is returned
+       pos_type getPosVisually(BufferView const & bv, pit_type pit,
+               pos_type pos, bool boundary, int visualDist) const;
 
        /// delete double spaces, leading spaces, and empty paragraphs
        /// from \first to \last paragraph

Reply via email to