Continuing the discussion about the space issue here.
I have implemented Georg's idea/hint to allow spaces on both sides of the RTL/LTR boundary, but let the empty-paragraph-mechanism (EPM, the algorithm which among other things kills double spaces) take care of double spaces around boundaries. Of course this needs the vis2log/ log2vis functions from the bidi object to get the logical position of the character visually next to a space. I tried to make the usage as safe as possible, i.e. ask for the range of the bidi cache and so on. You will find the patches attached, to be applied in this order:
no_bidi_isboundary.patch no_bidi_setcurrentfont.patch cursor_get_font.patch rtl_spaces.patch @Dov: quilt is nice, thanks again for the hint The patch of interest here is the last one, inlined below.The basic idea is that the EPM considers the spaces in "abc [ WERBEH] ghi" to be next to each other. So starting with abc[ WERBEH]ghi" you can enter space behind the abc and continue writing, or change your mind after the space and the EPM takes away the new space:
"abc|[ WERBEH]ghi" => "abc |[ WERBEH]ghi" => "abc|[ WERBEH]ghi" Similary for "abc [|WERBEH]ghi". Opinions? Stefan Index: lyx-devel/src/Bidi.cpp =================================================================== --- lyx-devel.orig/src/Bidi.cpp 2007-06-06 10:16:43.000000000 +0200 +++ lyx-devel/src/Bidi.cpp 2007-06-06 10:38:19.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-06 10:18:59.000000000 +0200 +++ lyx-devel/src/Text.cpp 2007-06-06 10:38:19.000000000 +0200 @@ -732,8 +732,20 @@ 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; + bool ok = true; + if (cur.boundary()) + prevpos = cur.pos() - 1; + else + ok = getPosVisuallyAway(cur.pos(), cur.boundary(), -1, prevpos); + + // no space if previous was space (or newline), + if (ok + && 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-06 10:30:11.000000000 +0200 +++ lyx-devel/src/Text2.cpp 2007-06-06 10:38:19.000000000 +0200 @@ -1114,6 +1114,42 @@ } +bool Text::getPosVisuallyAway(pos_type const start, bool boundary, + int visualDist, pos_type & pos) +{ + if (!lyxrc.rtl_support) { + pos = start + visualDist; + return true; + } + + // go to previous character on boundary, and later correct that + pos_type corrected_start = start; + if (boundary) + --corrected_start; + + if (!bidi.inRange(corrected_start)) + return false; + + // Convert to visual position + pos_type vstart = bidi.log2vis(corrected_start); + + // Go to visually next char + bool backward = bidi.level(corrected_start) & 1;+ pos_type vpos = backward ? (vstart - visualDist) : (vstart + visualDist);
+ if (!bidi.inRange(vpos)) + return false; + + // And convert back to logical position + pos = bidi.vis2log(vpos); + + // and finally correct the boundary again + if (boundary) + ++pos; + + return true; +} + + bool Text::deleteEmptyParagraphMechanism(Cursor & cur, Cursor & old, bool & need_anchor_change) { @@ -1148,25 +1184,40 @@ // 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 following character position + pos_type nextpos;+ bool ok = old.text()->getPosVisuallyAway(spacepos, false, 1, nextpos);
+ + // Is a space following? + if (ok && 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-06 10:23:17.000000000 +0200 +++ lyx-devel/src/Text.h 2007-06-06 10:46:28.000000000 +0200 @@ -362,6 +362,11 @@ /// now because recordUndo() is called which needs a Cursor. static bool deleteEmptyParagraphMechanism(Cursor & cur, Cursor & old, bool & need_anchor_change); + + /// get position visualDist positions visually away from start, + /// returns true on success + bool getPosVisuallyAway(pos_type const start, bool boundary, + int visualDist, pos_type & pos); /// delete double spaces, leading spaces, and empty paragraphs /// from \first to \last paragraph
cursor_get_font.patch
Description: Binary data
rtl_spaces.patch
Description: Binary data
no_bidi_setcurrentfont.patch
Description: Binary data
no_bidi_isboundary.patch
Description: Binary data
PGP.sig
Description: Signierter Teil der Nachricht