]> git.lyx.org Git - lyx.git/blobdiff - src/lyxfind.cpp
fix Row::findElement when there is a Virtual element
[lyx.git] / src / lyxfind.cpp
index 94a54bc37a203e62fc55a6818add4320a723079f..1c8cdb3b66ff730320bea95bdb5a04067b4947a4 100644 (file)
@@ -745,6 +745,7 @@ string escape_for_regex(string s, bool match_latex)
                        new_pos = s.size();
                string t;
                if (new_pos > pos) {
+                       // outside regexp
                        LYXERR(Debug::FIND, "new_pos: " << new_pos);
                        t = apply_escapes(s.substr(pos, new_pos - pos), get_lyx_unescapes());
                        LYXERR(Debug::FIND, "t [lyx]: " << t);
@@ -869,12 +870,17 @@ public:
 
 static MatchResult::range interpretMatch(MatchResult &oldres, MatchResult &newres)
 {
-  if (newres.match2end < oldres.match2end)
+  int range = oldres.match_len;
+  if (range < 2) range = 2;
+  if (newres.match2end < oldres.match2end - oldres.match_len)
     return MatchResult::newIsTooFar;
   if (newres.match_len < oldres.match_len)
     return MatchResult::newIsTooFar;
-  if ((newres.match_len == oldres.match_len) && (newres.match2end == oldres.match2end))
+  if ((newres.match_len == oldres.match_len) &&
+      (newres.match2end < oldres.match2end + range) &&
+      (newres.match2end > oldres.match2end - range)) {
     return MatchResult::newIsBetter;
+  }
   return MatchResult::newIsInvalid;
 }
 
@@ -947,6 +953,7 @@ private:
        // number of (.*?) subexpressions added at end of search regexp for closing
        // environments, math mode, styles, etc...
        int close_wildcards;
+public:
        // Are we searching with regular expressions ?
        bool use_regexp;
 };
@@ -1415,6 +1422,7 @@ static void buildAccentsMap()
   accents["LaTeX"]         = getutf8(0xf0012);
   accents["latexe"]        = getutf8(0xf0013);
   accents["LaTeXe"]        = getutf8(0xf0013);
+  accents["lyxarrow"]      = getutf8(0xf0020);
   accents["backslash lyx"]           = getutf8(0xf0010);       // Used logos inserted with starting \backslash
   accents["backslash LyX"]           = getutf8(0xf0010);
   accents["backslash tex"]           = getutf8(0xf0011);
@@ -1423,6 +1431,7 @@ static void buildAccentsMap()
   accents["backslash LaTeX"]         = getutf8(0xf0012);
   accents["backslash latexe"]        = getutf8(0xf0013);
   accents["backslash LaTeXe"]        = getutf8(0xf0013);
+  accents["backslash lyxarrow"]      = getutf8(0xf0020);
   accents["ddot{\\imath}"] = "ï";
   buildaccent("ddot", "aAeEhHiIioOtuUwWxXyY",
                       "äÄëËḧḦïÏïöÖẗüÜẅẄẍẌÿŸ");      // umlaut
@@ -1488,7 +1497,7 @@ void Intervall::removeAccents()
     buildAccentsMap();
   static regex const accre("\\\\(([\\S]|grave|breve|ddot|dot|acute|dacute|mathring|check|hat|bar|tilde|subdot|ogonek|"
          "cedilla|subring|textsubring|subhat|textsubcircum|subtilde|textsubtilde|dgrave|textdoublegrave|rcap|textroundcap|slashed)\\{[^\\{\\}]+\\}"
-      "|((i|imath|jmath|cdot|[a-z]+space)|((backslash )?([lL]y[xX]|[tT]e[xX]|[lL]a[tT]e[xX]e?)))(?![a-zA-Z]))");
+      "|((i|imath|jmath|cdot|[a-z]+space)|((backslash )?([lL]y[xX]|[tT]e[xX]|[lL]a[tT]e[xX]e?|lyxarrow)))(?![a-zA-Z]))");
   smatch sub;
   for (sregex_iterator itacc(par.begin(), par.end(), accre), end; itacc != end; ++itacc) {
     sub = *itacc;
@@ -1731,8 +1740,8 @@ class MathInfo {
 
 void LatexInfo::buildEntries(bool isPatternString)
 {
-  static regex const rmath("\\$|\\\\\\[|\\\\\\]|\\\\(begin|end)\\{((eqnarray|equation|flalign|gather|multline|align|alignat)\\*?)\\}");
-  static regex const rkeys("\\$|\\\\\\[|\\\\\\]|\\\\((([a-zA-Z]+\\*?)(\\{([a-z]+\\*?)\\}|=[0-9]+[a-z]+)?))");
+  static regex const rmath("(\\\\)*(\\$|\\\\\\[|\\\\\\]|\\\\(begin|end)\\{((eqnarray|equation|flalign|gather|multline|align|alignat)\\*?)\\})");
+  static regex const rkeys("(\\\\)*(\\$|\\\\\\[|\\\\\\]|\\\\((([a-zA-Z]+\\*?)(\\{([a-z]+\\*?)\\}|=[0-9]+[a-z]+)?)))");
   static bool disableLanguageOverride = false;
   smatch sub, submath;
   bool evaluatingRegexp = false;
@@ -1753,45 +1762,46 @@ void LatexInfo::buildEntries(bool isPatternString)
 
   for (sregex_iterator itmath(interval_.par.begin(), interval_.par.end(), rmath), end; itmath != end; ++itmath) {
     submath = *itmath;
+    if ((submath.position(2) - submath.position(0)) %2 == 1) {
+      // prefixed by odd count of '\\'
+      continue;
+    }
     if (math_end_waiting) {
-      size_t pos = submath.position(size_t(0));
+      size_t pos = submath.position(size_t(2));
       if ((math_end == "$") &&
-          (submath.str(0) == "$") &&
-          (interval_.par[pos-1] != '\\')) {
+          (submath.str(2) == "$")) {
         mi.insert("$", math_pos, pos + 1);
         math_end_waiting = false;
       }
       else if ((math_end == "\\]") &&
-               (submath.str(0) == "\\]")) {
+               (submath.str(2) == "\\]")) {
         mi.insert("\\]", math_pos, pos + 2);
         math_end_waiting = false;
       }
-      else if ((submath.str(1).compare("end") == 0) &&
-          (submath.str(2).compare(math_end) == 0)) {
-        mi.insert(math_end, math_pos, pos + submath.str(0).length());
+      else if ((submath.str(3).compare("end") == 0) &&
+          (submath.str(4).compare(math_end) == 0)) {
+        mi.insert(math_end, math_pos, pos + submath.str(2).length());
         math_end_waiting = false;
       }
       else
         continue;
     }
     else {
-      if (submath.str(1).compare("begin") == 0) {
+      if (submath.str(3).compare("begin") == 0) {
         math_end_waiting = true;
-        math_end = submath.str(2);
-        math_pos = submath.position(size_t(0));
+        math_end = submath.str(4);
+        math_pos = submath.position(size_t(2));
       }
-      else if (submath.str(0).compare("\\[") == 0) {
+      else if (submath.str(2).compare("\\[") == 0) {
         math_end_waiting = true;
         math_end = "\\]";
-        math_pos = submath.position(size_t(0));
+        math_pos = submath.position(size_t(2));
       }
-      else if (submath.str(0) == "$") {
-        size_t pos = submath.position(size_t(0));
-        if ((pos == 0) || (interval_.par[pos-1] != '\\')) {
-          math_end_waiting = true;
-          math_end = "$";
-          math_pos = pos;
-        }
+      else if (submath.str(2) == "$") {
+        size_t pos = submath.position(size_t(2));
+        math_end_waiting = true;
+        math_end = "$";
+        math_pos = pos;
       }
     }
   }
@@ -1818,27 +1828,31 @@ void LatexInfo::buildEntries(bool isPatternString)
   math_pos = mi.getFirstPos();
   for (sregex_iterator it(interval_.par.begin(), interval_.par.end(), rkeys), end; it != end; ++it) {
     sub = *it;
-    string key = sub.str(3);
+    if ((sub.position(2) - sub.position(0)) %2 == 1) {
+      // prefixed by odd count of '\\'
+      continue;
+    }
+    string key = sub.str(5);
     if (key == "") {
-      if (sub.str(0)[0] == '\\')
-        key = sub.str(0)[1];
+      if (sub.str(2)[0] == '\\')
+        key = sub.str(2)[1];
       else {
-        key = sub.str(0);
+        key = sub.str(2);
         if (key == "$") {
-          size_t k_pos = sub.position(size_t(0));
+          size_t k_pos = sub.position(size_t(2));
           if ((k_pos > 0) && (interval_.par[k_pos - 1] == '\\')) {
             // Escaped '$', ignoring
             continue;
           }
         }
       }
-    };
+    }
     if (keys.find(key) != keys.end()) {
       if (keys[key].keytype == KeyInfo::headRemove) {
         KeyInfo found1 = keys[key];
         found1.disabled = true;
         found1.head = "\\" + key + "{";
-        found1._tokenstart = sub.position(size_t(0));
+        found1._tokenstart = sub.position(size_t(2));
         found1._tokensize = found1.head.length();
         found1._dataStart = found1._tokenstart + found1.head.length();
         int endpos = interval_.findclosing(found1._dataStart, interval_.par.length(), '{', '}', 1);
@@ -1848,10 +1862,10 @@ void LatexInfo::buildEntries(bool isPatternString)
       }
     }
     if (evaluatingRegexp) {
-      if (sub.str(1).compare("endregexp") == 0) {
+      if (sub.str(3).compare("endregexp") == 0) {
         evaluatingRegexp = false;
         // found._tokenstart already set
-        found._dataEnd = sub.position(size_t(0)) + 13;
+        found._dataEnd = sub.position(size_t(2)) + 13;
         found._dataStart = found._dataEnd;
         found._tokensize = found._dataEnd - found._tokenstart;
         found.parenthesiscount = 0;
@@ -1863,7 +1877,7 @@ void LatexInfo::buildEntries(bool isPatternString)
     }
     else {
       if (evaluatingMath) {
-        if (size_t(sub.position(size_t(0))) < mi.getEndPos())
+        if (size_t(sub.position(size_t(2))) < mi.getEndPos())
           continue;
         evaluatingMath = false;
         mi.incrEntry();
@@ -1885,7 +1899,7 @@ void LatexInfo::buildEntries(bool isPatternString)
         found = keys[key];
       if (key.compare("regexp") == 0) {
         evaluatingRegexp = true;
-        found._tokenstart = sub.position(size_t(0));
+        found._tokenstart = sub.position(size_t(2));
         found._tokensize = 0;
         continue;
       }
@@ -1894,9 +1908,9 @@ void LatexInfo::buildEntries(bool isPatternString)
     if (found.keytype == KeyInfo::isIgnored)
       continue;
     else if (found.keytype == KeyInfo::isMath) {
-      if (size_t(sub.position(size_t(0))) == math_pos) {
+      if (size_t(sub.position(size_t(2))) == math_pos) {
         found = keys[key];
-        found._tokenstart = sub.position(size_t(0));
+        found._tokenstart = sub.position(size_t(2));
         found._tokensize = mi.getSize();
         found._dataEnd = found._tokenstart + found._tokensize;
         found._dataStart = found._dataEnd;
@@ -1911,21 +1925,21 @@ void LatexInfo::buildEntries(bool isPatternString)
         bool discardComment;
         found = keys[key];
         found.keytype = KeyInfo::doRemove;
-        if ((sub.str(5).compare("longtable") == 0) ||
-            (sub.str(5).compare("tabular") == 0)) {
+        if ((sub.str(7).compare("longtable") == 0) ||
+            (sub.str(7).compare("tabular") == 0)) {
           discardComment = true;        /* '%' */
         }
         else {
           discardComment = false;
           static regex const removeArgs("^(multicols|multipar|sectionbox|subsectionbox|tcolorbox)$");
           smatch sub2;
-          string token = sub.str(5);
+          string token = sub.str(7);
           if (regex_match(token, sub2, removeArgs)) {
             found.keytype = KeyInfo::removeWithArg;
           }
         }
-        // discard spaces before pos(0)
-        int pos = sub.position(size_t(0));
+        // discard spaces before pos(2)
+        int pos = sub.position(size_t(2));
         int count;
         for (count = 0; pos - count > 0; count++) {
           char c = interval_.par[pos-count-1];
@@ -1937,9 +1951,9 @@ void LatexInfo::buildEntries(bool isPatternString)
             break;
         }
         found._tokenstart = pos - count;
-        if (sub.str(1).compare(0, 5, "begin") == 0) {
-          size_t pos1 = pos + sub.str(0).length();
-          if (sub.str(5).compare("cjk") == 0) {
+        if (sub.str(3).compare(0, 5, "begin") == 0) {
+          size_t pos1 = pos + sub.str(2).length();
+          if (sub.str(7).compare("cjk") == 0) {
             pos1 = interval_.findclosing(pos1+1, interval_.par.length()) + 1;
             if ((interval_.par[pos1] == '{') && (interval_.par[pos1+1] == '}'))
               pos1 += 2;
@@ -1972,7 +1986,7 @@ void LatexInfo::buildEntries(bool isPatternString)
         }
         else {
           // Handle "\end{...}"
-          found._dataStart = pos + sub.str(0).length();
+          found._dataStart = pos + sub.str(2).length();
           found._dataEnd = found._dataStart;
           found._tokensize = count + found._dataEnd - pos;
           found.parenthesiscount = 0;
@@ -1982,16 +1996,16 @@ void LatexInfo::buildEntries(bool isPatternString)
       }
     }
     else if (found.keytype != KeyInfo::isRegex) {
-      found._tokenstart = sub.position(size_t(0));
+      found._tokenstart = sub.position(size_t(2));
       if (found.parenthesiscount == 0) {
         // Probably to be discarded
-        size_t following_pos = sub.position(size_t(0)) + sub.str(3).length() + 1;
+        size_t following_pos = sub.position(size_t(2)) + sub.str(5).length() + 1;
         char following = interval_.par[following_pos];
         if (following == ' ')
-          found.head = "\\" + sub.str(3) + " ";
+          found.head = "\\" + sub.str(5) + " ";
         else if (following == '=') {
           // like \uldepth=1000pt
-          found.head = sub.str(0);
+          found.head = sub.str(2);
         }
         else
           found.head = "\\" + key;
@@ -2019,11 +2033,12 @@ void LatexInfo::buildEntries(bool isPatternString)
           evaluatingOptional = true;
           optionalEnd = optend;
         }
-        string token = sub.str(5);
+        string token = sub.str(7);
         int closings;
         if (interval_.par[optend] != '{') {
           closings = 0;
           found.parenthesiscount = 0;
+          found.head = "\\" + key;
         }
         else
           closings = found.parenthesiscount;
@@ -2032,7 +2047,7 @@ void LatexInfo::buildEntries(bool isPatternString)
         }
         else if (found.parenthesiscount > 1) {
           if (token != "") {
-            found.head = sub.str(0) + "{";
+            found.head = sub.str(2) + "{";
             closings = found.parenthesiscount - 1;
           }
           else {
@@ -2042,9 +2057,17 @@ void LatexInfo::buildEntries(bool isPatternString)
         found._tokensize = found.head.length();
         found._dataStart = found._tokenstart + found.head.length();
         if (found.keytype == KeyInfo::doRemove) {
-          int endpar = 2 + interval_.findclosing(found._dataStart, interval_.par.length(), '{', '}', closings);
-          found._dataStart = endpar;
-          found._tokensize = found._dataStart - found._tokenstart;
+          if (closings > 0) {
+            size_t endpar = 2 + interval_.findclosing(found._dataStart, interval_.par.length(), '{', '}', closings);
+            if (endpar >= interval_.par.length())
+              found._dataStart = interval_.par.length();
+            else
+              found._dataStart = endpar;
+            found._tokensize = found._dataStart - found._tokenstart;
+          }
+          else {
+            found._dataStart = found._tokenstart + found._tokensize;
+          } 
           closings = 0;
         }
         if (interval_.par.substr(found._dataStart-1, 15).compare("\\endarguments{}") == 0) {
@@ -2420,8 +2443,11 @@ int LatexInfo::dispatch(ostringstream &os, int previousStart, KeyInfo &actual)
     }
     case KeyInfo::isSize: {
       if (actual.disabled || (interval_.par[actual._dataStart] != '{') || (interval_.par[actual._dataStart-1] == ' ')) {
-        processRegion(actual._dataEnd, actual._dataEnd+1); /* remove possibly following {} */
-        interval_.addIntervall(actual._tokenstart, actual._dataEnd+1);
+        if (actual.parenthesiscount == 0)
+          interval_.addIntervall(actual._tokenstart, actual._dataEnd);
+        else {
+          interval_.addIntervall(actual._tokenstart, actual._dataEnd+1);
+        }
         nextKeyIdx = getNextKey();
       } else {
         // Here _dataStart points to '{', so correct it
@@ -2921,7 +2947,9 @@ MatchStringAdv::MatchStringAdv(lyx::Buffer & buf, FindAndReplaceOptions const &
                string lead_as_regexp;
                if (lead_size > 0) {
                        // @todo No need to search for \regexp{} insets in leading material
-                       lead_as_regexp = escape_for_regex(par_as_string.substr(0, lead_size), !opt.ignoreformat);
+                       static std::regex specialChars { R"([-[\]{}()*+?.,\^$|#\s\\])" };
+                       lead_as_regexp = std::regex_replace(par_as_string.substr(0, lead_size), specialChars,  R"(\$&)" );
+                       // lead_as_regexp = escape_for_regex(par_as_string.substr(0, lead_size), !opt.ignoreformat);
                        par_as_string = par_as_string_nolead;
                        LYXERR(Debug::FIND, "lead_as_regexp is '" << lead_as_regexp << "'");
                        LYXERR(Debug::FIND, "par_as_string now is '" << par_as_string << "'");
@@ -3050,7 +3078,7 @@ MatchStringAdv::MatchStringAdv(lyx::Buffer & buf, FindAndReplaceOptions const &
        }
 }
 
-
+#if 0
 // Count number of characters in string
 // {]} ==> 1
 // \&  ==> 1
@@ -3110,6 +3138,7 @@ static int computeSize(string s, int len)
        }
        return count;
 }
+#endif
 
 MatchResult MatchStringAdv::findAux(DocIterator const & cur, int len, bool at_begin) const
 {
@@ -3213,19 +3242,61 @@ MatchResult MatchStringAdv::findAux(DocIterator const & cur, int len, bool at_be
                        result = 0;
 #if QTSEARCH
                mres.match_prefix = match.capturedEnd(2) - match.capturedStart(2);
-               // mres.match_len = computeSize(QStringRef(&qstr, pos+leadingsize,result), result) - mres.match_prefix;
                mres.match_len = match.capturedEnd(0) - match.capturedEnd(2);
-               // mres.match2end = qstr.size() - pos - leadingsize - mres.match_prefix;
-               mres.match2end = qstr.size() - match.capturedEnd(0);
+               // because of different number of closing at end of string
+               // we have to 'unify' the length of the post-match.
+               // Done by ignoring closing parenthesis and linefeeds at string end
+               int matchend = match.capturedEnd(0);
+               while (mres.match_len > 0) {
+                 QChar c = qstr.at(matchend - 1);
+                 if ((c == '\n') || (c == '}') || (c == '{')) {
+                   mres.match_len--;
+                   matchend--;
+                 }
+                 else
+                   break;
+               }
+               size_t strsize = qstr.size();
+               while (strsize > (size_t) match.capturedEnd(0)) {
+                       QChar c = qstr.at(strsize-1);
+                       if ((c == '\n') || (c == '}')) {
+                               --strsize;
+                       }
+                       else
+                               break;
+               }
+               // LYXERR0(qstr.toStdString());
+               mres.match2end = strsize - matchend;
                mres.pos = match.capturedStart(2);
 #else
                mres.match_prefix = m[2].second - m[2].first;
-               // mres.match_len = computeSize(str.substr(pos+leadingsize,result), result) - mres.match_prefix;
                mres.match_len = m[0].second - m[2].second;
-               // mres.match2end = str.size() - pos - leadingsize - mres.match_prefix;
-               mres.match2end = str.size() - m[0].second;
-               mres.pos = m[2].first;
+               // ignore closing parenthesis and linefeeds at string end
+               size_t strend = m[0].second - m[0].first;
+               int matchend = strend;
+               while (mres.match_len > 0) {
+                 char c = str.at(matchend - 1);
+                 if ((c == '\n') || (c == '}') || (c == '{')) {
+                   mres.match_len--;
+                   matchend--;
+                 }
+                 else
+                   break;
+               }
+               size_t strsize = str.size();
+               while (strsize > strend) {
+                       if ((str.at(strsize-1) == '}') || (str.at(strsize-1) == '\n')) {
+                               --strsize;
+                       }
+                       else
+                               break;
+               }
+               // LYXERR0(str);
+               mres.match2end = strsize - matchend;
+               mres.pos = m[2].first - m[0].first;;
 #endif
+               if (mres.match2end < 0)
+                 mres.match_len = 0;
                mres.leadsize = leadingsize;
                return mres;
        }
@@ -3305,6 +3376,28 @@ MatchResult MatchStringAdv::operator()(DocIterator const & cur, int len, bool at
        return mres;
 }
 
+static bool simple_replace(string &t, string from, string to)
+{
+  regex repl("(\\\\)*(" + from + ")");
+  string s("");
+  size_t lastpos = 0;
+  smatch sub;
+  for (sregex_iterator it(t.begin(), t.end(), repl), end; it != end; ++it) {
+    sub = *it;
+    if ((sub.position(2) - sub.position(0)) % 2 == 1)
+      continue;
+    if (lastpos < (size_t) sub.position(2))
+      s += t.substr(lastpos, sub.position(2) - lastpos);
+    s += to;
+    lastpos = sub.position(2) + sub.length(2);
+  }
+  if (lastpos == 0)
+    return false;
+  else if (lastpos < t.length())
+    s += t.substr(lastpos, t.length() - lastpos);
+  t = s;
+  return true;
+}
 
 string MatchStringAdv::normalize(docstring const & s, bool hack_braces) const
 {
@@ -3352,10 +3445,11 @@ string MatchStringAdv::normalize(docstring const & s, bool hack_braces) const
                        while (regex_replace(t, t, "\\{", "_x_<")
                               || regex_replace(t, t, "\\}", "_x_>"))
                                LYXERR(Debug::FIND, "After {} replacement: '" << t << "'");
-               else
-                       while (regex_replace(t, t, "\\\\\\{", "_x_<")
-                              || regex_replace(t, t, "\\\\\\}", "_x_>"))
-                               LYXERR(Debug::FIND, "After {} replacement: '" << t << "'");
+               else {
+                       simple_replace(t, "\\\\\\{", "_x_<");
+                       simple_replace(t, "\\\\\\}", "_x_>");
+                       LYXERR(Debug::FIND, "After {} replacement: '" << t << "'");
+               }
        }
 
        return t;
@@ -3477,25 +3571,87 @@ docstring latexifyFromCursor(DocIterator const & cur, int len)
        return ods.str();
 }
 
+#if 0
+// Debugging output
+static void displayMResult(MatchResult &mres, int increment)
+{
+  LYXERR0( "pos: " << mres.pos << " increment " << increment);
+  LYXERR0( "leadsize: " << mres.leadsize);
+  LYXERR0( "match_len: " << mres.match_len);
+  LYXERR0( "match_prefix: " << mres.match_prefix);
+  LYXERR0( "match2end: " << mres.match2end);
+}
+       #define displayMres(s,i) displayMResult(s,i);
+#else
+       #define displayMres(s,i)
+#endif
 
-/** Finalize an advanced find operation, advancing the cursor to the innermost
- ** position that matches, plus computing the length of the matching text to
- ** be selected
- **/
-int findAdvFinalize(DocIterator & cur, MatchStringAdv const & match)
+static bool findAdvForwardInnermost(DocIterator & cur)
 {
-       // Search the foremost position that matches (avoids find of entire math
-       // inset when match at start of it)
        size_t d;
        DocIterator old_cur(cur.buffer());
+       int forwardCount = 0;
        do {
-               LYXERR(Debug::FIND, "Forwarding one step (searching for innermost match)");
                d = cur.depth();
                old_cur = cur;
                cur.forwardPos();
-       } while (cur && cur.depth() > d && match(cur).match_len > 0);
+               if (!cur) {
+                       break;
+               }
+               if (cur.depth() > d) {
+                       forwardCount++;
+                       continue;
+               }
+               if (cur.depth() == d)
+                       break;
+       } while(1);
        cur = old_cur;
-       int max_match = match(cur).match_len;     /* match valid only if not searching whole words */
+       if (forwardCount > 0) {
+               LYXERR(Debug::FIND, "Forwarded " << forwardCount << " step(s) (searching for innermost match)");
+               return true;;
+       }
+       else
+               return false;
+}
+
+/** Finalize an advanced find operation, advancing the cursor to the innermost
+ ** position that matches, plus computing the length of the matching text to
+ ** be selected
+ **/
+int findAdvFinalize(DocIterator & cur, MatchStringAdv const & match, int expected_len, int prefix_len = 0)
+{
+       // Search the foremost position that matches (avoids find of entire math
+       // inset when match at start of it)
+       DocIterator old_cur(cur.buffer());
+       MatchResult mres;
+       int max_match;
+       // If (prefix_len > 0) means that forwarding 1 position will remove the complete entry
+       // Happens with e.g. hyperlinks
+       // either one sees "http://www.bla.bla" or nothing
+       // so the search for "www" gives prefix_len = 7 (== sizeof("http://")
+       // and although we search for only 3 chars, we find the whole hyperlink inset
+       bool at_begin = (prefix_len == 0);
+       if (findAdvForwardInnermost(cur)) {
+               mres = match(cur, -1, at_begin);
+               displayMres(mres, 0);
+               if (expected_len > 0) {
+                       if (mres.match_len < expected_len)
+                               return 0;
+               }
+               else {
+                       if (mres.match_len <= 0)
+                               return 0;
+               }
+               max_match = mres.match_len;
+       }
+       else if (expected_len < 0) {
+               mres = match(cur);      /* match valid only if not searching whole words */
+               displayMres(mres, 0);
+               max_match = mres.match_len;
+       }
+       else {
+               max_match = expected_len;
+       }
        if (max_match <= 0) return 0;
        LYXERR(Debug::FIND, "Ok");
 
@@ -3503,19 +3659,21 @@ int findAdvFinalize(DocIterator & cur, MatchStringAdv const & match)
         int len = 1;
        if (cur.pos() + len > cur.lastpos())
          return 0;
-       if (match.opt.matchword) {
+       // regexp should use \w+, \S+, or \b(some string)\b
+       // to search for whole words
+       if (match.opt.matchword && !match.use_regexp) {
           LYXERR(Debug::FIND, "verifying unmatch with len = " << len);
           while (cur.pos() + len <= cur.lastpos() && match(cur, len).match_len <= 0) {
             ++len;
             LYXERR(Debug::FIND, "verifying unmatch with len = " << len);
           }
           // Length of matched text (different from len param)
-          int old_match = match(cur, len).match_len;
+          int old_match = match(cur, len, at_begin).match_len;
           if (old_match < 0)
             old_match = 0;
           int new_match;
           // Greedy behaviour while matching regexps
-          while ((new_match = match(cur, len + 1).match_len) > old_match) {
+          while ((new_match = match(cur, len + 1, at_begin).match_len) > old_match) {
             ++len;
             old_match = new_match;
             LYXERR(Debug::FIND, "verifying   match with len = " << len);
@@ -3523,28 +3681,34 @@ int findAdvFinalize(DocIterator & cur, MatchStringAdv const & match)
           if (old_match == 0)
             len = 0;
         }
-       else {
-         int minl = 1;
-         int maxl = cur.lastpos() - cur.pos();
-         // Greedy behaviour while matching regexps
-         while (maxl > minl) {
-           int actual_match = match(cur, len).match_len;
-           if (actual_match >= max_match) {
-             // actual_match > max_match _can_ happen,
-             // if the search area splits
-             // some following word so that the regex
-             // (e.g. 'r.*r\b' matches 'r' from the middle of the
-             // splitted word)
-             // This means, the len value is too big
-             maxl = len;
-             len = (int)((maxl + minl)/2);
-           }
-           else {
-             // (actual_match < max_match)
-             minl = len + 1;
-             len = (int)((maxl + minl)/2);
-           }
-         }
+        else {
+          int minl = 1;
+          int maxl = cur.lastpos() - cur.pos();
+          // Greedy behaviour while matching regexps
+          while (maxl > minl) {
+           MatchResult mres2;
+           mres2 = match(cur, len, at_begin);
+           displayMres(mres2, len);
+            int actual_match = mres2.match_len;
+            if (actual_match >= max_match) {
+              // actual_match > max_match _can_ happen,
+              // if the search area splits
+              // some following word so that the regex
+              // (e.g. 'r.*r\b' matches 'r' from the middle of the
+              // splitted word)
+              // This means, the len value is too big
+              maxl = len;
+              if (maxl - minl < 4)
+                len = (int)((maxl + minl)/2);
+              else
+                len = (int)(minl + (maxl - minl + 3)/4);
+            }
+            else {
+              // (actual_match < max_match)
+              minl = len + 1;
+              len = (int)((maxl + minl)/2);
+            }
+          }
           old_cur = cur;
           // Search for real start of matched characters
           while (len > 1) {
@@ -3559,7 +3723,7 @@ int findAdvFinalize(DocIterator & cur, MatchStringAdv const & match)
             }
             if (cur.pos() != old_cur.pos()) {
               // OK, forwarded 1 pos in actual inset
-              actual_match = match(cur, len-1).match_len;
+              actual_match = match(cur, len-1, at_begin).match_len;
               if (actual_match == max_match) {
                 // Ha, got it! The shorter selection has the same match length
                 len--;
@@ -3573,7 +3737,7 @@ int findAdvFinalize(DocIterator & cur, MatchStringAdv const & match)
             }
             else {
               LYXERR(Debug::INFO, "cur.pos() == old_cur.pos(), this should never happen");
-              actual_match = match(cur, len).match_len;
+              actual_match = match(cur, len, at_begin).match_len;
               if (actual_match == max_match)
                 old_cur = cur;
             }
@@ -3582,29 +3746,16 @@ int findAdvFinalize(DocIterator & cur, MatchStringAdv const & match)
        return len;
 }
 
-#if 0
-static void displayMResult(MatchResult &mres)
-{
-  LYXERR0( "pos: " << mres.pos);
-  LYXERR0( "leadsize: " << mres.leadsize);
-  LYXERR0( "match_len: " << mres.match_len);
-  LYXERR0( "match_prefix: " << mres.match_prefix);
-  LYXERR0( "match2end: " << mres.match2end);
-}
-       #define displayMres(s) displayMResult(s);
-#else
-       #define displayMres(s)
-#endif
-
 /// Finds forward
 int findForwardAdv(DocIterator & cur, MatchStringAdv const & match)
 {
        if (!cur)
                return 0;
        while (!theApp()->longOperationCancelled() && cur) {
+               (void) findAdvForwardInnermost(cur);
                LYXERR(Debug::FIND, "findForwardAdv() cur: " << cur);
                MatchResult mres = match(cur, -1, false);
-               displayMres(mres)
+               displayMres(mres,-1)
                int match_len = mres.match_len;
                if ((mres.pos > 100000) || (mres.match2end > 100000) || (match_len > 100000)) {
                        LYXERR(Debug::INFO, "BIG LENGTHS: " << mres.pos << ", " << match_len << ", " << mres.match2end);
@@ -3613,11 +3764,11 @@ int findForwardAdv(DocIterator & cur, MatchStringAdv const & match)
                if (match_len > 0) {
                        // Try to find the begin of searched string
                        int increment;
-                        int firstInvalid = 100000;
-                        if (mres.match_prefix + mres.pos - mres.leadsize > 0)
-                          increment = (mres.match_prefix + mres.pos - mres.leadsize)/2;
-                        else
-                          increment = 10;
+                       int firstInvalid = 100000;
+                       if (mres.match_prefix + mres.pos - mres.leadsize > 1)
+                         increment = (mres.match_prefix + mres.pos - mres.leadsize + 1)*3/4;
+                       else
+                         increment = 10;
                        LYXERR(Debug::FIND, "Set increment to " << increment);
                        while (increment > 0) {
                                DocIterator old_cur = cur;
@@ -3631,38 +3782,56 @@ int findForwardAdv(DocIterator & cur, MatchStringAdv const & match)
                                }
                                else {
                                        MatchResult mres2 = match(cur, -1, false);
-                                       displayMres(mres2)
-                                          switch (interpretMatch(mres, mres2)) {
-                                          case MatchResult::newIsTooFar:
-                                            // behind the expected match
-                                            firstInvalid = increment;
-                                            cur = old_cur;
-                                            increment /= 2;
-                                            break;
-                                          case MatchResult::newIsBetter:
-                                            // not reached yet
-                                            mres = mres2;
-                                            firstInvalid -= increment;
-                                            if (increment > firstInvalid/2)
-                                              increment = firstInvalid/2;
-                                            break;
-                                          default:
-                                            // Handle not like MatchResult::newIsTooFar
-                                            LYXERR0( "Something is wrong: Increment = " << increment << " match_prefix = " << mres.match_prefix);
-                                            firstInvalid--;
-                                            increment = firstInvalid -1;
-                                            cur = old_cur;
-                                            break;
-                                          }
+                                       displayMres(mres2,increment)
+                                       switch (interpretMatch(mres, mres2)) {
+                                       case MatchResult::newIsTooFar:
+                                         // behind the expected match
+                                         firstInvalid = increment;
+                                         cur = old_cur;
+                                         increment /= 2;
+                                         break;
+                                       case MatchResult::newIsBetter:
+                                         // not reached ye, but cur.pos()+increment is bettert
+                                         mres = mres2;
+                                         firstInvalid -= increment;
+                                         if (increment > firstInvalid*3/4)
+                                           increment = firstInvalid*3/4;
+                                         if ((mres2.pos == mres2.leadsize) && (increment >= mres2.match_prefix)) {
+                                           if (increment >= mres2.match_prefix)
+                                             increment = (mres2.match_prefix+1)*3/4;
+                                         }
+                                         break;
+                                       default:
+                                         // Todo@
+                                         // Handle not like MatchResult::newIsTooFar
+                                         // LYXERR0( "Something is wrong: Increment = " << increment << " match_prefix = " << mres.match_prefix);
+                                         firstInvalid--;
+                                         increment = increment*3/4;
+                                         cur = old_cur;
+                                         break;
+                                       }
                                }
                        }
-                        // LYXERR0("Leaving first loop");
+                       // LYXERR0("Leaving first loop");
+                       {
+                         LYXERR(Debug::FIND, "Finalizing 1");
+                         int len = findAdvFinalize(cur, match, mres.match_len, mres.match_prefix);
+                         if (len > 0)
+                           return len;
+                         else {
+                           // try next possible match
+                           cur.forwardPos();
+                           continue;
+                         }
+                       }
+                       // The following code is newer reached
+                       // but parts of it may be needed in future
                        int match_len_zero_count = 0;
                        MatchResult mres3;
                        for (int i = 0; !theApp()->longOperationCancelled() && cur; cur.forwardPos()) {
                                if (i++ > 3) {
                                        mres3 = match(cur, -1, false);
-                                       displayMres(mres3)
+                                       displayMres(mres3, 1)
                                        int remaining_len = mres3.match_len;
                                        if (remaining_len <= 0) {
                                                // Apparently the searched string is not in the remaining part
@@ -3674,19 +3843,19 @@ int findForwardAdv(DocIterator & cur, MatchStringAdv const & match)
                                }
                                LYXERR(Debug::FIND, "Advancing cur: " << cur);
                                mres3 = match(cur, 1);
-                               displayMres(mres3)
+                               displayMres(mres3, 1)
                                int match_len3 = mres3.match_len;
                                if (match_len3 < 0)
                                        continue;
                                mres3 = match(cur);
-                               displayMres(mres3)
+                               displayMres(mres3, 1)
                                int match_len2 = mres3.match_len;
                                LYXERR(Debug::FIND, "match_len2: " << match_len2);
                                if (match_len2 > 0) {
                                        // Sometimes in finalize we understand it wasn't a match
                                        // and we need to continue the outest loop
-                                       LYXERR(Debug::FIND, "Finalizing");
-                                       int len = findAdvFinalize(cur, match);
+                                       LYXERR(Debug::FIND, "Finalizing 2");
+                                       int len = findAdvFinalize(cur, match, mres.match_len);
                                        if (len > 0) {
                                                return len;
                                        }
@@ -3724,7 +3893,7 @@ int findMostBackwards(DocIterator & cur, MatchStringAdv const & match)
 {
        DocIterator cur_begin = doc_iterator_begin(cur.buffer());
        DocIterator tmp_cur = cur;
-       int len = findAdvFinalize(tmp_cur, match);
+       int len = findAdvFinalize(tmp_cur, match, -1);
        Inset & inset = cur.inset();
        for (; cur != cur_begin; cur.backwardPos()) {
                LYXERR(Debug::FIND, "findMostBackwards(): cur=" << cur);
@@ -3732,7 +3901,7 @@ int findMostBackwards(DocIterator & cur, MatchStringAdv const & match)
                new_cur.backwardPos();
                if (new_cur == cur || &new_cur.inset() != &inset || !match(new_cur).match_len)
                        break;
-               int new_len = findAdvFinalize(new_cur, match);
+               int new_len = findAdvFinalize(new_cur, match, -1);
                if (new_len == len)
                        break;
                len = new_len;
@@ -3991,9 +4160,8 @@ bool findAdv(BufferView * bv, FindAndReplaceOptions const & opt)
                        match_len = findForwardAdv(cur, matchAdv);
                else
                        match_len = findBackwardsAdv(cur, matchAdv);
-       } catch (...) {
-               // This may only be raised by lyx::regex()
-               bv->message(_("Invalid regular expression!"));
+       } catch (exception & ex) {
+               bv->message(from_utf8(ex.what()));
                return false;
        }