The main goal of those patches is to fix bug 2068:
[Bug 2068] Spellcheck correction of words with ligatures doubles initial 
character
http://bugzilla.lyx.org/show_bug.cgi?id=2068

The 1.4 version does just that, but the 1.5 version does some cleanup
in some code from CutAndPaste.C that was used in spell and find (and
which should not have lived there).

Comments welcome.

        * src/CutAndPaste.C (setSelectionRange, replaceWord): remove.
        (replaceSelectionWithString): select the new string after
        replacement; add a bool parameter indicating in which sense the
        selection is made.

        * src/lyxfind.C (replace): adapt to above changes.
        (find): comment out debug message.

        * src/frontends/controllers/ControlSpellchecker.C (isLetter):
        rename parameter.
        (nextWord): take a LCursor as parameter; set the selection over
        the word that has been found.
        (check): adapt to changes above (the length of the word is not
        necessarily the length of the selection -- fixes bug 2068).
        (replace): use cap::replaceSelectionWithString

JMarc

Index: src/lyxfind.C
===================================================================
--- src/lyxfind.C	(revision 14684)
+++ src/lyxfind.C	(working copy)
@@ -274,7 +274,7 @@ void find(BufferView * bv, FuncRequest c
 	if (!bv || ev.action != LFUN_WORD_FIND)
 		return;
 
-	lyxerr << "find called, cmd: " << ev << std::endl;
+	//lyxerr << "find called, cmd: " << ev << std::endl;
 
 	// data is of the form
 	// "<search>
Index: src/frontends/controllers/ControlSpellchecker.C
===================================================================
--- src/frontends/controllers/ControlSpellchecker.C	(revision 14684)
+++ src/frontends/controllers/ControlSpellchecker.C	(working copy)
@@ -140,11 +140,12 @@ bool isLetter(DocIterator const & cur)
 }
 
 
-WordLangTuple nextWord(DocIterator & cur, ptrdiff_t & progress,
-	BufferParams & bp)
+WordLangTuple nextWord(LCursor & cur, ptrdiff_t & progress)
 {
+	BufferParams const & bp = cur.bv().buffer()->params();
 	bool inword = false;
 	bool ignoreword = false;
+	cur.resetAnchor();
 	string word, lang_code;
 
 	while (cur.depth()) {
@@ -152,6 +153,7 @@ WordLangTuple nextWord(DocIterator & cur
 			if (!inword) {
 				inword = true;
 				ignoreword = false;
+				cur.resetAnchor();
 				word.clear();
 				lang_code = cur.paragraph().getFontSettings(bp, cur.pos()).language()->code();
 			}
@@ -166,9 +168,10 @@ WordLangTuple nextWord(DocIterator & cur
 			}
 		} else { // !isLetter(cur)
 			if (inword)
-				if (!word.empty() && !ignoreword)
+				if (!word.empty() && !ignoreword) {
+					cur.setSelection();
 					return WordLangTuple(word, lang_code);
-				else
+				} else
 					inword = false;
 		}
 
@@ -189,7 +192,7 @@ void ControlSpellchecker::check()
 
 	SpellBase::Result res = SpellBase::OK;
 
-	DocIterator cur = kernel().bufferview()->cursor();
+	LCursor cur = kernel().bufferview()->cursor();
 	while (cur && cur.pos() && isLetter(cur)) {
 		cur.backwardPos();
 	}
@@ -202,11 +205,10 @@ void ControlSpellchecker::check()
 	for (total = start; it; it.forwardPos())
 		++total;
 
-	BufferParams & bufferparams = kernel().buffer().params();
 	exitEarly_ = false;
 
 	while (res == SpellBase::OK || res == SpellBase::IGNORED_WORD) {
-		word_ = nextWord(cur, start, bufferparams);
+		word_ = nextWord(cur, start);
 
 		// end of document
 		if (getWord().empty()) {
@@ -240,7 +242,7 @@ void ControlSpellchecker::check()
 
 	lyxerr[Debug::GUI] << "Found word \"" << getWord() << "\"" << endl;
 
-	int const size = getWord().size();
+	int const size = cur.selEnd().pos() - cur.selBegin().pos();
 	cur.pos() -= size;
 	kernel().bufferview()->putSelectionAt(cur, size, false);
 	// if we used a lfun like in find/replace, dispatch would do
Index: src/CutAndPaste.C
===================================================================
--- src/CutAndPaste.C	(revision 14694)
+++ src/CutAndPaste.C	(working copy)
@@ -651,33 +651,19 @@ void pasteSelection(LCursor & cur, Error
 }
 
 
-void setSelectionRange(LCursor & cur, pos_type length)
-{
-	LyXText * text = cur.text();
-	BOOST_ASSERT(text);
-	if (!length)
-		return;
-	cur.resetAnchor();
-	while (length--)
-		text->cursorRight(cur);
-	cur.setSelection();
-}
-
-
 // simple replacing. The font of the first selected character is used
-void replaceSelectionWithString(LCursor & cur, string const & str)
+void replaceSelectionWithString(LCursor & cur, string const & str, bool backwards)
 {
-	LyXText * text = cur.text();
-	BOOST_ASSERT(text);
 	recordUndo(cur);
+	DocIterator selbeg = cur.selectionBegin();
 
 	// Get font setting before we cut
-	pos_type pos = cur.selEnd().pos();
-	Paragraph & par = text->getPar(cur.selEnd().pit());
 	LyXFont const font =
-		par.getFontSettings(cur.buffer().params(), cur.selBegin().pos());
+		selbeg.paragraph().getFontSettings(cur.buffer().params(), selbeg.pos());
 
 	// Insert the new string
+	pos_type pos = cur.selEnd().pos();
+	Paragraph & par = cur.selEnd().paragraph();
 	string::const_iterator cit = str.begin();
 	string::const_iterator end = str.end();
 	for (; cit != end; ++cit, ++pos)
@@ -685,6 +671,13 @@ void replaceSelectionWithString(LCursor 
 
 	// Cut the selection
 	cutSelection(cur, true, false);
+
+	// select the replacement
+	if (backwards) {
+		selbeg.pos() += str.length();
+		cur.setSelection(selbeg, -str.length());
+	} else
+		cur.setSelection(selbeg, str.length());
 }
 
 
@@ -695,21 +688,6 @@ void replaceSelection(LCursor & cur)
 }
 
 
-// only used by the spellchecker
-void replaceWord(LCursor & cur, string const & replacestring)
-{
-	LyXText * text = cur.text();
-	BOOST_ASSERT(text);
-
-	replaceSelectionWithString(cur, replacestring);
-	setSelectionRange(cur, replacestring.length());
-
-	// Go back so that replacement string is also spellchecked
-	for (string::size_type i = 0; i < replacestring.length() + 1; ++i)
-		text->cursorLeft(cur);
-}
-
-
 void eraseSelection(LCursor & cur)
 {
 	//lyxerr << "LCursor::eraseSelection begin: " << cur << endl;
Index: src/CutAndPaste.h
===================================================================
--- src/CutAndPaste.h	(revision 14694)
+++ src/CutAndPaste.h	(working copy)
@@ -41,13 +41,12 @@ std::string getSelection(Buffer const & 
 ///
 void cutSelection(LCursor & cur, bool doclear, bool realcut);
 
-/**
- * Sets the selection from the current cursor position to length
- * characters to the right. No safety checks.
+/* Replace using the font of the first selected character and select
+ * the new string. When \c backwards == false, set anchor before
+ * cursor; otherwise set cursor before anchor.
  */
-void setSelectionRange(LCursor & cur, lyx::pos_type length);
-/// simply replace using the font of the first selected character
-void replaceSelectionWithString(LCursor & cur, std::string const & str);
+void replaceSelectionWithString(LCursor & cur, std::string const & str, 
+				bool backwards);
 /// replace selection helper
 void replaceSelection(LCursor & cur);
 
@@ -71,9 +70,6 @@ void switchBetweenClasses(lyx::textclass
                           lyx::textclass_type c2,
                           InsetText & in, ErrorList &);
 
-// only used by the spellchecker
-void replaceWord(LCursor & cur, std::string const & replacestring);
-
 ///
 std::string grabSelection(LCursor const & cur);
 ///
Index: src/frontends/controllers/ControlSpellchecker.C
===================================================================
--- src/frontends/controllers/ControlSpellchecker.C	(revision 14694)
+++ src/frontends/controllers/ControlSpellchecker.C	(working copy)
@@ -127,24 +127,25 @@ void ControlSpellchecker::clearParams()
 
 namespace {
 
-bool isLetter(DocIterator const & cur)
+bool isLetter(DocIterator const & dit)
 {
-	return cur.inTexted()
-		&& cur.inset().allowSpellCheck()
-		&& cur.pos() != cur.lastpos()
-		&& (cur.paragraph().isLetter(cur.pos())
+	return dit.inTexted()
+		&& dit.inset().allowSpellCheck()
+		&& dit.pos() != dit.lastpos()
+		&& (dit.paragraph().isLetter(dit.pos())
 		    // We want to pass the ' and escape chars to ispell
 		    || contains(lyxrc.isp_esc_chars + '\'',
-				cur.paragraph().getChar(cur.pos())))
-		&& !isDeletedText(cur.paragraph(), cur.pos());
+				dit.paragraph().getChar(dit.pos())))
+		&& !isDeletedText(dit.paragraph(), dit.pos());
 }
 
 
-WordLangTuple nextWord(DocIterator & cur, ptrdiff_t & progress,
-	BufferParams & bp)
+WordLangTuple nextWord(LCursor & cur, ptrdiff_t & progress)
 {
+	BufferParams const & bp = cur.bv().buffer()->params();
 	bool inword = false;
 	bool ignoreword = false;
+	cur.resetAnchor();
 	string word, lang_code;
 
 	while (cur.depth()) {
@@ -152,6 +153,7 @@ WordLangTuple nextWord(DocIterator & cur
 			if (!inword) {
 				inword = true;
 				ignoreword = false;
+				cur.resetAnchor();
 				word.clear();
 				lang_code = cur.paragraph().getFontSettings(bp, cur.pos()).language()->code();
 			}
@@ -166,9 +168,10 @@ WordLangTuple nextWord(DocIterator & cur
 			}
 		} else { // !isLetter(cur)
 			if (inword)
-				if (!word.empty() && !ignoreword)
+				if (!word.empty() && !ignoreword) {
+					cur.setSelection();
 					return WordLangTuple(word, lang_code);
-				else
+				} else
 					inword = false;
 		}
 
@@ -189,7 +192,7 @@ void ControlSpellchecker::check()
 
 	SpellBase::Result res = SpellBase::OK;
 
-	DocIterator cur = kernel().bufferview()->cursor();
+	LCursor cur = kernel().bufferview()->cursor();
 	while (cur && cur.pos() && isLetter(cur)) {
 		cur.backwardPos();
 	}
@@ -202,11 +205,10 @@ void ControlSpellchecker::check()
 	for (total = start; it; it.forwardPos())
 		++total;
 
-	BufferParams & bufferparams = kernel().buffer().params();
 	exitEarly_ = false;
 
 	while (res == SpellBase::OK || res == SpellBase::IGNORED_WORD) {
-		word_ = nextWord(cur, start, bufferparams);
+		word_ = nextWord(cur, start);
 
 		// end of document
 		if (getWord().empty()) {
@@ -240,7 +242,7 @@ void ControlSpellchecker::check()
 
 	lyxerr[Debug::GUI] << "Found word \"" << getWord() << "\"" << endl;
 
-	int const size = getWord().size();
+	int const size = cur.selEnd().pos() - cur.selBegin().pos();
 	cur.pos() -= size;
 	kernel().bufferview()->putSelectionAt(cur, size, false);
 	// if we used a lfun like in find/replace, dispatch would do
@@ -298,7 +300,7 @@ void ControlSpellchecker::replace(string
 	lyxerr[Debug::GUI] << "ControlSpellchecker::replace("
 			   << replacement << ")" << std::endl;
 	BufferView & bufferview = *kernel().bufferview();
-	cap::replaceWord(bufferview.cursor(), replacement);
+	cap::replaceSelectionWithString(bufferview.cursor(), replacement, true);
 	kernel().buffer().markDirty();
 	bufferview.update();
 	// fix up the count
Index: src/lyxfind.C
===================================================================
--- src/lyxfind.C	(revision 14694)
+++ src/lyxfind.C	(working copy)
@@ -226,9 +226,7 @@ int replace(BufferView * bv, string cons
 		return 0;
 
 	LCursor & cur = bv->cursor();
-	lyx::cap::replaceSelectionWithString(cur, replacestr);
-	lyx::cap::setSelectionRange(cur, replacestr.length());
-	cur.top() = fw ? cur.selEnd() : cur.selBegin();
+	lyx::cap::replaceSelectionWithString(cur, replacestr, fw);
 	bv->buffer()->markDirty();
 	find(bv, searchstr, cs, mw, fw);
 	bv->update();
@@ -274,7 +272,7 @@ void find(BufferView * bv, FuncRequest c
 	if (!bv || ev.action != LFUN_WORD_FIND)
 		return;
 
-	lyxerr << "find called, cmd: " << ev << std::endl;
+	//lyxerr << "find called, cmd: " << ev << std::endl;
 
 	// data is of the form
 	// "<search>

Reply via email to