]> git.lyx.org Git - lyx.git/blobdiff - src/lyxfind.cpp
Do not search in deleted text in change tracking mode
[lyx.git] / src / lyxfind.cpp
index 83d99a10e4fb11eedd1767e4dd9df98f9d191426..139e7b398e4ae7b9d47a470e8062abd39e2dc68e 100644 (file)
@@ -93,7 +93,7 @@ class IgnoreFormats {
        ///
        bool getLanguage() { return ignoreLanguage_; };
        ///
-       void setIgnoreFormat(string type, bool value);
+       void setIgnoreFormat(string const & type, bool value);
 
 private:
        ///
@@ -119,7 +119,7 @@ private:
 };
 
 
-void IgnoreFormats::setIgnoreFormat(string type, bool value)
+void IgnoreFormats::setIgnoreFormat(string const & type, bool value)
 {
        if (type == "color") {
                ignoreColor_ = value;
@@ -160,9 +160,9 @@ void IgnoreFormats::setIgnoreFormat(string type, bool value)
 IgnoreFormats ignoreFormats;
 
 
-void setIgnoreFormat(string type, bool value)
+void setIgnoreFormat(string const & type, bool value)
 {
-       ignoreFormats.setIgnoreFormat(type, value);
+  ignoreFormats.setIgnoreFormat(type, value);
 }
 
 
@@ -181,8 +181,8 @@ bool parse_bool(docstring & howto)
 class MatchString : public binary_function<Paragraph, pos_type, int>
 {
 public:
-       MatchString(docstring const & str, bool cs, bool mw)
-               : str(str), case_sens(cs), whole_words(mw)
+       MatchString(docstring const & s, bool cs, bool mw)
+               : str(s), case_sens(cs), whole_words(mw)
        {}
 
        // returns true if the specified string is at the specified position
@@ -1023,7 +1023,7 @@ static Features identifyFeatures(string const & s)
                        }
                }
        }
-       return(info);
+       return info;
 }
 
 /*
@@ -1111,18 +1111,22 @@ class Border {
 
 #define MAXOPENED 30
 class Intervall {
-  bool isPatternString;
- public:
- explicit Intervall(bool isPattern) :
-  isPatternString(isPattern),
-    ignoreidx(-1),
-    actualdeptindex(0) { depts[0] = 0; closes[0] = 0;};
+  bool isPatternString_;
+public:
+  explicit Intervall(bool isPattern, string const & p) :
+        isPatternString_(isPattern), par(p), ignoreidx(-1), actualdeptindex(0),
+        hasTitle(false), langcount(0)
+  {
+    depts[0] = 0;
+    closes[0] = 0;
+  }
+
   string par;
   int ignoreidx;
+  static vector<Border> borders;
   int depts[MAXOPENED];
   int closes[MAXOPENED];
   int actualdeptindex;
-  Border borders[2*MAXOPENED];
   int previousNotIgnored(int);
   int nextNotIgnored(int);
   void handleOpenP(int i);
@@ -1135,12 +1139,15 @@ class Intervall {
   int findclosing(int start, int end, char up, char down, int repeat);
   void handleParentheses(int lastpos, bool closingAllowed);
   bool hasTitle;
+  int langcount;       // Number of disabled language specs up to current position in actual interval
   int isOpeningPar(int pos);
   string titleValue;
   void output(ostringstream &os, int lastpos);
   // string show(int lastpos);
 };
 
+vector<Border> Intervall::borders = vector<Border>(30);
+
 int Intervall::isOpeningPar(int pos)
 {
   if ((pos < 0) || (size_t(pos) >= par.size()))
@@ -1173,20 +1180,28 @@ void Intervall::setForDefaultLang(KeyInfo &defLang)
 static void checkDepthIndex(int val)
 {
   static int maxdepthidx = MAXOPENED-2;
+  static int lastmaxdepth = 0;
+  if (val > lastmaxdepth) {
+    LYXERR0("Depth reached " << val);
+    lastmaxdepth = val;
+  }
   if (val > maxdepthidx) {
     maxdepthidx = val;
     LYXERR0("maxdepthidx now " << val);
   }
 }
 
+#if 0
+// Not needed, because borders are now dynamically expanded
 static void checkIgnoreIdx(int val)
 {
-  static int maxignoreidx = 2*MAXOPENED - 4;
-  if (val > maxignoreidx) {
-    maxignoreidx = val;
-    LYXERR0("maxignoreidx now " << val);
+  static int lastmaxignore = -1;
+  if ((lastmaxignore < val) && (size_t(val+1) >= borders.size())) {
+    LYXERR0("IgnoreIdx reached " << val);
+    lastmaxignore = val;
   }
 }
+#endif
 
 /*
  * Expand the region of ignored parts of the input latex string
@@ -1203,9 +1218,14 @@ void Intervall::addIntervall(int low, int upper)
   }
   Border br(low, upper);
   if (idx > ignoreidx) {
-    borders[idx] = br;
+    if (borders.size() <= size_t(idx)) {
+      borders.push_back(br);
+    }
+    else {
+      borders[idx] = br;
+    }
     ignoreidx = idx;
-    checkIgnoreIdx(ignoreidx);
+    // checkIgnoreIdx(ignoreidx);
     return;
   }
   else {
@@ -1213,12 +1233,18 @@ void Intervall::addIntervall(int low, int upper)
     // We know here that br.low > borders[idx-1].upper
     if (br.upper < borders[idx].low) {
       // We have to insert at this pos
-      for (int i = ignoreidx+1; i > idx; --i) {
+      if (size_t(ignoreidx+1) >= borders.size()) {
+        borders.push_back(borders[ignoreidx]);
+      }
+      else {
+        borders[ignoreidx+1] = borders[ignoreidx];
+      }
+      for (int i = ignoreidx; i > idx; --i) {
         borders[i] = borders[i-1];
       }
       borders[idx] = br;
       ignoreidx += 1;
-      checkIgnoreIdx(ignoreidx);
+      // checkIgnoreIdx(ignoreidx);
       return;
     }
     // Here we know, that we are overlapping
@@ -1263,6 +1289,12 @@ static void buildaccent(string n, string param, string values)
       // get the corresponding utf8-value
       if ((values[start] & 0xc0) != 0xc0) {
         // should not happen, utf8 encoding starts at least with 11xxxxxx
+        // but value for '\dot{i}' is 'i', which is ascii
+        if ((values[start] & 0x80) == 0) {
+          // is ascii
+          accents[key] = values.substr(start, 1);
+          // LYXERR0("" << key << "=" << accents[key]);
+        }
         start++;
         continue;
       }
@@ -1272,10 +1304,11 @@ static void buildaccent(string n, string param, string values)
           start = values.size() - 1;
           break;
         }
-        else if ((values[start+j] & 0xc0) == 0xc0) {
+        else if ((values[start+j] & 0xc0) != 0x80) {
           // This is the first byte of following utf8 char
           accents[key] = values.substr(start, j);
           start += j;
+          // LYXERR0("" << key << "=" << accents[key]);
           break;
         }
       }
@@ -1289,36 +1322,60 @@ static void buildAccentsMap()
   accents["i"] = "ı";
   accents["jmath"] = "ȷ";
   accents["lyxmathsym{ß}"] = "ß";
+  accents["text{ß}"] = "ß";
   accents["ddot{\\imath}"] = "ï";
-  buildaccent("ddot", "aAeEiIoOuUyY",
-                      "äÄëËïÏöÖüÜÿŸ");     // umlaut
-  buildaccent("dot|.", "cCeEgGiIzZaAoObBdDfFyY",
-                       "ċĊėĖġĠiİżŻȧȦȯȮḃḂḋḊḟḞẏẎ");
+  buildaccent("ddot", "aAeEhHiIioOtuUwWxXyY",
+                      "äÄëËḧḦïÏïöÖẗüÜẅẄẍẌÿŸ");      // umlaut
+  buildaccent("dot|.", "aAbBcCdDeEfFGghHIimMnNoOpPrRsStTwWxXyYzZ",
+                       "ȧȦḃḂċĊḋḊėĖḟḞĠġḣḢİİṁṀṅṄȯȮṗṖṙṘṡṠṫṪẇẆẋẊẏẎżŻ");  // dot{i} can only happen if ignoring case, but there is no lowercase of 'İ'
   accents["acute{\\imath}"] = "í";
-  buildaccent("acute", "aAcCeElLoOnNrRsSuUyYzZiI",
-                       "áÁćĆéÉĺĹóÓńŃŕŔśŚúÚýÝźŹíÍ");
+  buildaccent("acute", "aAcCeEgGkKlLmMoOnNpPrRsSuUwWyYzZiI",
+                       "áÁćĆéÉǵǴḱḰĺĹḿḾóÓńŃṕṔŕŔśŚúÚẃẂýÝźŹíÍ");
   buildaccent("dacute|H|h", "oOuU", "őŐűŰ");       // double acute
-  buildaccent("mathring|r", "uU", "ůŮ");
+  buildaccent("mathring|r", "aAuUwy",
+                            "åÅůŮẘẙ"); // ring
   accents["check{\\imath}"] = "ǐ";
   accents["check{\\jmath}"] = "ǰ";
-  buildaccent("check|v", "cCdDaAeEiIoOuUgGkKhHlLnNrRsSTzZ",
-                         "Ä\8dÄ\8cÄ\8fÄ\8eÇ\8eÇ\8dÄ\9bÄ\9aÇ\90Ç\8fÇ\92Ç\91Ç\94Ç\93ǧǦǩǨÈ\9fÈ\9eľĽÅ\88Å\87Å\99Å\98šŠŤžŽ");    // caron
+  buildaccent("check|v", "cCdDaAeEiIoOuUgGkKhHlLnNrRsSTtzZ",
+                         "Ä\8dÄ\8cÄ\8fÄ\8eÇ\8eÇ\8dÄ\9bÄ\9aÇ\90Ç\8fÇ\92Ç\91Ç\94Ç\93ǧǦǩǨÈ\9fÈ\9eľĽÅ\88Å\87Å\99Å\98šŠŤťžŽ");  // caron
   accents["hat{\\imath}"] = "î";
   accents["hat{\\jmath}"] = "ĵ";
-  buildaccent("hat|^", "aAeEiIcCgGhHjJsSwWyYzZoOuU",
-                       "âÂêÊîÎĉĈĝĜĥĤĵĴŝŜŵŴŷŶẑẐôÔûÛ");      // circ
+  buildaccent("hat|^", "aAcCeEgGhHiIjJoOsSuUwWyYzZ",
+                       "âÂĉĈêÊĝĜĥĤîÎĵĴôÔŝŜûÛŵŴŷŶẑẐ");      // circ
   accents["bar{\\imath}"] = "ī";
   buildaccent("bar|=", "aAeEiIoOuUyY",
                        "āĀēĒīĪōŌūŪȳȲ");    // macron
   accents["tilde{\\imath}"] = "ĩ";
-  buildaccent("tilde", "aAnNoOiIuU",
-                       "ãÃñÑõÕĩĨũŨ");        // tilde
+  buildaccent("tilde", "aAeEiInNoOuUvVyY",
+                       "ãÃẽẼĩĨñÑõÕũŨṽṼỹỸ");      // tilde
   accents["breve{\\imath}"] = "ĭ";
   buildaccent("breve|u", "aAeEgGiIoOuU",
-                         "ăĂĕĔğĞĭĬŏŎŭŬ");    // breve
+                         "ăĂĕĔğĞĭĬŏŎŭŬ");  // breve
   accents["grave{\\imath}"] = "ì";
   buildaccent("grave|`", "aAeEiIoOuUnNwWyY",
-                         "àÀèÈìÌòÒùÙǹǸẁẀỳỲ");                // grave
+                         "àÀèÈìÌòÒùÙǹǸẁẀỳỲ");      // grave
+  buildaccent("subdot|d", "BbDdHhKkLlMmNnRrSsTtVvWwZzAaEeIiOoUuYy",
+                          "ḄḅḌḍḤḥḲḳḶḷṂṃṆṇṚṛṢṣṬṭṾṿẈẉẒẓẠạẸẹỊịỌọỤụỴỵ");       // dot below
+  buildaccent("ogonek|k", "AaEeIiUuOo",
+                          "ĄąĘęĮįŲųǪǫ");     // ogonek
+  buildaccent("cedilla|c", "CcGgKkLlNnRrSsTtEeDdHh",
+                           "ÇçĢĢĶķĻļŅņŖŗŞşŢţȨȩḐḑḨḩ");        // cedilla
+  buildaccent("subring|textsubring", "Aa",
+                                     "Ḁḁ");        // subring
+  buildaccent("subhat|textsubcircum", "DdEeLlNnTtUu",
+                                      "ḒḓḘḙḼḽṊṋṰṱṶṷ"); // subcircum
+  buildaccent("subtilde|textsubtilde", "EeIiUu",
+                                       "ḚḛḬḭṴṵ");  // subtilde
+  accents["dgrave{\\imath}"] = "ȉ";
+  accents["textdoublegrave{\\i}"] = "ȉ";
+  buildaccent("dgrave|textdoublegrave", "AaEeIiOoRrUu",
+                                        "ȀȁȄȅȈȉȌȍȐȑȔȕ"); // double grave
+  accents["rcap{\\imath}"] = "ȉ";
+  accents["textroundcap{\\i}"] = "ȉ";
+  buildaccent("rcap|textroundcap", "AaEeIiOoRrUu",
+                                   "ȂȃȆȇȊȋȎȏȒȓȖȗ"); // inverted breve
+  buildaccent("slashed", "oO",
+                         "øØ"); // slashed
 }
 
 /*
@@ -1329,20 +1386,20 @@ void Intervall::removeAccents()
 {
   if (accents.empty())
     buildAccentsMap();
-  static regex const accre("\\\\((.|grave|breve|lyxmathsym|ddot|dot|acute|dacute|mathring|check|hat|bar|tilde)\\{[^\\{\\}]+\\}|(i|imath|jmath)(?![a-zA-Z]))");
+  static regex const accre("\\\\(([\\S]|grave|breve|lyxmathsym|text|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)(?![a-zA-Z]))");
   smatch sub;
   for (sregex_iterator itacc(par.begin(), par.end(), accre), end; itacc != end; ++itacc) {
     sub = *itacc;
     string key = sub.str(1);
     if (accents.find(key) != accents.end()) {
       string val = accents[key];
-      size_t pos = sub.position(0);
+      size_t pos = sub.position(size_t(0));
       for (size_t i = 0; i < val.size(); i++) {
         par[pos+i] = val[i];
       }
       addIntervall(pos+val.size(), pos + sub.str(0).size());
       for (size_t i = pos+val.size(); i < pos + sub.str(0).size(); i++) {
-        // remove any remaining parentheses
+        // remove traces of any remaining chars
         par[i] = ' ';
       }
     }
@@ -1412,9 +1469,9 @@ static KeysMap keys = map<string, KeyInfo>();
 
 class LatexInfo {
  private:
-  int entidx;
-  Entries entries;
-  Intervall interval;
+  int entidx_;
+  Entries entries_;
+  Intervall interval_;
   void buildKeys(bool);
   void buildEntries(bool);
   void makeKey(const string &, KeyInfo, bool isPatternString);
@@ -1422,48 +1479,47 @@ class LatexInfo {
   void removeHead(KeyInfo&, int count=0);
 
  public:
- LatexInfo(string par, bool isPatternString) : entidx(-1), interval(isPatternString) {
-    interval.par = par;
-    interval.hasTitle = false;
-    interval.titleValue = "";
+ LatexInfo(string const & par, bool isPatternString)
+        : entidx_(-1), interval_(isPatternString, par)
+  {
     buildKeys(isPatternString);
-    entries = vector<KeyInfo>();
+    entries_ = vector<KeyInfo>();
     buildEntries(isPatternString);
   };
   int getFirstKey() {
-    entidx = 0;
-    if (entries.empty()) {
-      return (-1);
+    entidx_ = 0;
+    if (entries_.empty()) {
+      return -1;
     }
-    if (entries[0].keytype == KeyInfo::isTitle) {
-      if (! entries[0].disabled) {
-        interval.hasTitle = true;
-        interval.titleValue = entries[0].head;
+    if (entries_[0].keytype == KeyInfo::isTitle) {
+      if (! entries_[0].disabled) {
+        interval_.hasTitle = true;
+        interval_.titleValue = entries_[0].head;
       }
       else {
-        interval.hasTitle = false;
-        interval.titleValue = "";
+        interval_.hasTitle = false;
+        interval_.titleValue = "";
       }
-      removeHead(entries[0]);
-      if (entries.size() > 1)
-        return (1);
+      removeHead(entries_[0]);
+      if (entries_.size() > 1)
+        return 1;
       else
-        return (-1);
+        return -1;
     }
     return 0;
   };
   int getNextKey() {
-    entidx++;
-    if (int(entries.size()) > entidx) {
-      return entidx;
+    entidx_++;
+    if (int(entries_.size()) > entidx_) {
+      return entidx_;
     }
     else {
-      return (-1);
+      return -1;
     }
   };
   bool setNextKey(int idx) {
-    if ((idx == entidx) && (entidx >= 0)) {
-      entidx--;
+    if ((idx == entidx_) && (entidx_ >= 0)) {
+      entidx_--;
       return true;
     }
     else
@@ -1471,28 +1527,28 @@ class LatexInfo {
   };
   int find(int start, KeyInfo::KeyType keytype) {
     if (start < 0)
-      return (-1);
+      return -1;
     int tmpIdx = start;
-    while (tmpIdx < int(entries.size())) {
-      if (entries[tmpIdx].keytype == keytype)
+    while (tmpIdx < int(entries_.size())) {
+      if (entries_[tmpIdx].keytype == keytype)
         return tmpIdx;
       tmpIdx++;
     }
-    return(-1);
+    return -1;
   };
   int process(ostringstream &os, KeyInfo &actual);
   int dispatch(ostringstream &os, int previousStart, KeyInfo &actual);
   // string show(int lastpos) { return interval.show(lastpos);};
-  int nextNotIgnored(int start) { return interval.nextNotIgnored(start);};
+  int nextNotIgnored(int start) { return interval_.nextNotIgnored(start);};
   KeyInfo &getKeyInfo(int keyinfo) {
     static KeyInfo invalidInfo = KeyInfo();
-    if ((keyinfo < 0) || ( keyinfo >= int(entries.size())))
+    if ((keyinfo < 0) || ( keyinfo >= int(entries_.size())))
       return invalidInfo;
     else
-      return entries[keyinfo];
+      return entries_[keyinfo];
   };
-  void setForDefaultLang(KeyInfo &defLang) {interval.setForDefaultLang(defLang);};
-  void addIntervall(int low, int up) { interval.addIntervall(low, up); };
+  void setForDefaultLang(KeyInfo &defLang) {interval_.setForDefaultLang(defLang);};
+  void addIntervall(int low, int up) { interval_.addIntervall(low, up); };
 };
 
 
@@ -1500,7 +1556,6 @@ int Intervall::findclosing(int start, int end, char up = '{', char down = '}', i
 {
   int skip = 0;
   int depth = 0;
-  repeat--;
   for (int i = start; i < end; i += 1 + skip) {
     char c;
     c = par[i];
@@ -1510,6 +1565,7 @@ int Intervall::findclosing(int start, int end, char up = '{', char down = '}', i
       depth++;
     }
     else if (c == down) {
+      repeat--;
       if (depth == 0) {
         if ((repeat <= 0) || (par[i+1] != up))
           return i;
@@ -1528,44 +1584,44 @@ class MathInfo {
     size_t mathStart;
     size_t mathSize;
   };
-  size_t actualIdx;
-  vector<MathEntry> entries;
+  size_t actualIdx_;
+  vector<MathEntry> entries_;
  public:
   MathInfo() {
-    actualIdx = 0;
+    actualIdx_ = 0;
   }
-  void insert(string wait, size_t start, size_t end) {
+  void insert(string const & wait, size_t start, size_t end) {
     MathEntry m = MathEntry();
     m.wait = wait;
     m.mathStart = start;
     m.mathEnd = end;
     m.mathSize = end - start;
-    entries.push_back(m);
+    entries_.push_back(m);
   }
-  bool empty() { return entries.empty(); };
+  bool empty() { return entries_.empty(); };
   size_t getEndPos() {
-    if (entries.empty() || (actualIdx >= entries.size())) {
+    if (entries_.empty() || (actualIdx_ >= entries_.size())) {
       return 0;
     }
-    return entries[actualIdx].mathEnd;
+    return entries_[actualIdx_].mathEnd;
   }
   size_t getStartPos() {
-    if (entries.empty() || (actualIdx >= entries.size())) {
+    if (entries_.empty() || (actualIdx_ >= entries_.size())) {
       return 100000;                    /*  definitely enough? */
     }
-    return entries[actualIdx].mathStart;
+    return entries_[actualIdx_].mathStart;
   }
   size_t getFirstPos() {
-    actualIdx = 0;
+    actualIdx_ = 0;
     return getStartPos();
   }
   size_t getSize() {
-    if (entries.empty() || (actualIdx >= entries.size())) {
+    if (entries_.empty() || (actualIdx_ >= entries_.size())) {
       return size_t(0);
     }
-    return entries[actualIdx].mathSize;
+    return entries_[actualIdx_].mathSize;
   }
-  void incrEntry() { actualIdx++; };
+  void incrEntry() { actualIdx_++; };
 };
 
 void LatexInfo::buildEntries(bool isPatternString)
@@ -1587,15 +1643,15 @@ void LatexInfo::buildEntries(bool isPatternString)
   size_t math_pos = 10000;
   string math_end;
 
-  interval.removeAccents();
+  interval_.removeAccents();
 
-  for (sregex_iterator itmath(interval.par.begin(), interval.par.end(), rmath), end; itmath != end; ++itmath) {
+  for (sregex_iterator itmath(interval_.par.begin(), interval_.par.end(), rmath), end; itmath != end; ++itmath) {
     submath = *itmath;
     if (math_end_waiting) {
       size_t pos = submath.position(size_t(0));
       if ((math_end == "$") &&
           (submath.str(0) == "$") &&
-          (interval.par[pos-1] != '\\')) {
+          (interval_.par[pos-1] != '\\')) {
         mi.insert("$", math_pos, pos + 1);
         math_end_waiting = false;
       }
@@ -1625,7 +1681,7 @@ void LatexInfo::buildEntries(bool isPatternString)
       }
       else if (submath.str(0) == "$") {
         size_t pos = submath.position(size_t(0));
-        if ((pos == 0) || (interval.par[pos-1] != '\\')) {
+        if ((pos == 0) || (interval_.par[pos-1] != '\\')) {
           math_end_waiting = true;
           math_end = "$";
           math_pos = pos;
@@ -1649,7 +1705,7 @@ void LatexInfo::buildEntries(bool isPatternString)
     }
   }
   math_pos = mi.getFirstPos();
-  for (sregex_iterator it(interval.par.begin(), interval.par.end(), rkeys), end; it != end; ++it) {
+  for (sregex_iterator it(interval_.par.begin(), interval_.par.end(), rkeys), end; it != end; ++it) {
     sub = *it;
     string key = sub.str(3);
     if (key == "") {
@@ -1659,7 +1715,7 @@ void LatexInfo::buildEntries(bool isPatternString)
         key = sub.str(0);
         if (key == "$") {
           size_t k_pos = sub.position(size_t(0));
-          if ((k_pos > 0) && (interval.par[k_pos - 1] == '\\')) {
+          if ((k_pos > 0) && (interval_.par[k_pos - 1] == '\\')) {
             // Escaped '$', ignoring
             continue;
           }
@@ -1674,7 +1730,7 @@ void LatexInfo::buildEntries(bool isPatternString)
         found._dataStart = found._dataEnd;
         found._tokensize = found._dataEnd - found._tokenstart;
         found.parenthesiscount = 0;
-        found.head = interval.par.substr(found._tokenstart, found._tokensize);
+        found.head = interval_.par.substr(found._tokenstart, found._tokensize);
       }
       else {
         continue;
@@ -1717,7 +1773,7 @@ void LatexInfo::buildEntries(bool isPatternString)
         found._dataEnd = found._tokenstart + found._tokensize;
         found._dataStart = found._dataEnd;
         found.parenthesiscount = 0;
-        found.head = interval.par.substr(found._tokenstart, found._tokensize);
+        found.head = interval_.par.substr(found._tokenstart, found._tokensize);
         evaluatingMath = true;
       }
       else {
@@ -1744,7 +1800,7 @@ void LatexInfo::buildEntries(bool isPatternString)
         int pos = sub.position(size_t(0));
         int count;
         for (count = 0; pos - count > 0; count++) {
-          char c = interval.par[pos-count-1];
+          char c = interval_.par[pos-count-1];
           if (discardComment) {
             if ((c != ' ') && (c != '%'))
               break;
@@ -1756,25 +1812,25 @@ void LatexInfo::buildEntries(bool isPatternString)
         if (sub.str(1).compare(0, 5, "begin") == 0) {
           size_t pos1 = pos + sub.str(0).length();
           if (sub.str(5).compare("cjk") == 0) {
-            pos1 = interval.findclosing(pos1+1, interval.par.length()) + 1;
-            if ((interval.par[pos1] == '{') && (interval.par[pos1+1] == '}'))
+            pos1 = interval_.findclosing(pos1+1, interval_.par.length()) + 1;
+            if ((interval_.par[pos1] == '{') && (interval_.par[pos1+1] == '}'))
               pos1 += 2;
             found.keytype = KeyInfo::isMain;
             found._dataStart = pos1;
-            found._dataEnd = interval.par.length();
+            found._dataEnd = interval_.par.length();
             found.disabled = keys["foreignlanguage"].disabled;
             found.used = keys["foreignlanguage"].used;
             found._tokensize = pos1 - found._tokenstart;
-            found.head = interval.par.substr(found._tokenstart, found._tokensize);
+            found.head = interval_.par.substr(found._tokenstart, found._tokensize);
           }
           else {
             // Swallow possible optional params
-            while (interval.par[pos1] == '[') {
-              pos1 = interval.findclosing(pos1+1, interval.par.length(), '[', ']')+1;
+            while (interval_.par[pos1] == '[') {
+              pos1 = interval_.findclosing(pos1+1, interval_.par.length(), '[', ']')+1;
             }
             // Swallow also the eventual parameter
-            if (interval.par[pos1] == '{') {
-              found._dataEnd = interval.findclosing(pos1+1, interval.par.length()) + 1;
+            if (interval_.par[pos1] == '{') {
+              found._dataEnd = interval_.findclosing(pos1+1, interval_.par.length()) + 1;
             }
             else {
               found._dataEnd = pos1;
@@ -1782,7 +1838,7 @@ void LatexInfo::buildEntries(bool isPatternString)
             found._dataStart = found._dataEnd;
             found._tokensize = count + found._dataEnd - pos;
             found.parenthesiscount = 0;
-            found.head = interval.par.substr(found._tokenstart, found._tokensize);
+            found.head = interval_.par.substr(found._tokenstart, found._tokensize);
             found.disabled = true;
           }
         }
@@ -1792,7 +1848,7 @@ void LatexInfo::buildEntries(bool isPatternString)
           found._dataEnd = found._dataStart;
           found._tokensize = count + found._dataEnd - pos;
           found.parenthesiscount = 0;
-          found.head = interval.par.substr(found._tokenstart, found._tokensize);
+          found.head = interval_.par.substr(found._tokenstart, found._tokensize);
           found.disabled = true;
         }
       }
@@ -1802,7 +1858,7 @@ void LatexInfo::buildEntries(bool isPatternString)
       if (found.parenthesiscount == 0) {
         // Probably to be discarded
         size_t following_pos = sub.position(size_t(0)) + sub.str(3).length() + 1;
-        char following = interval.par[following_pos];
+        char following = interval_.par[following_pos];
         if (following == ' ')
           found.head = "\\" + sub.str(3) + " ";
         else if (following == '=') {
@@ -1826,12 +1882,12 @@ void LatexInfo::buildEntries(bool isPatternString)
           }
         }
         int optend = params;
-        while (interval.par[optend] == '[') {
+        while (interval_.par[optend] == '[') {
           // discard optional parameters
-          optend = interval.findclosing(optend+1, interval.par.length(), '[', ']') + 1;
+          optend = interval_.findclosing(optend+1, interval_.par.length(), '[', ']') + 1;
         }
         if (optend > params) {
-          key += interval.par.substr(params, optend-params);
+          key += interval_.par.substr(params, optend-params);
           evaluatingOptional = true;
           optionalEnd = optend;
         }
@@ -1851,10 +1907,16 @@ void LatexInfo::buildEntries(bool isPatternString)
         }
         found._tokensize = found.head.length();
         found._dataStart = found._tokenstart + found.head.length();
-        if (interval.par.substr(found._dataStart-1, 15).compare("\\endarguments{}") == 0) {
+        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;
+          closings = 1;
+        }
+        if (interval_.par.substr(found._dataStart-1, 15).compare("\\endarguments{}") == 0) {
           found._dataStart += 15;
         }
-        size_t endpos = interval.findclosing(found._dataStart, interval.par.length(), '{', '}', closings);
+        size_t endpos = interval_.findclosing(found._dataStart, interval_.par.length(), '{', '}', closings);
         if (found.keytype == KeyInfo::isList) {
           // Check if it really is list env
           static regex const listre("^([a-z]+)$");
@@ -1876,18 +1938,18 @@ void LatexInfo::buildEntries(bool isPatternString)
             // Disable this key, treate it as standard
             found.keytype = KeyInfo::isStandard;
             found.disabled = true;
-            if ((codeEnd == interval.par.length()) &&
+            if ((codeEnd == interval_.par.length()) &&
                 (found._tokenstart == codeStart)) {
               // trickery, because the code inset starts
               // with \selectlanguage ...
               codeEnd = endpos;
-              if (entries.size() > 1) {
-                entries[entries.size()-1]._dataEnd = codeEnd;
+              if (entries_.size() > 1) {
+                entries_[entries_.size()-1]._dataEnd = codeEnd;
               }
             }
           }
         }
-        if ((endpos == interval.par.length()) &&
+        if ((endpos == interval_.par.length()) &&
             (found.keytype == KeyInfo::doRemove)) {
           // Missing closing => error in latex-input?
           // therefore do not delete remaining data
@@ -1901,7 +1963,7 @@ void LatexInfo::buildEntries(bool isPatternString)
         keys[key].used = true;
       }
     }
-    entries.push_back(found);
+    entries_.push_back(found);
   }
 }
 
@@ -1978,6 +2040,11 @@ void LatexInfo::buildKeys(bool isPatternString)
   // handle like standard keys with 1 parameter.
   makeKey("url|href|vref|thanks", KeyInfo(KeyInfo::isStandard, 1, false), isPatternString);
 
+  // Ignore deleted text
+  makeKey("lyxdeleted", KeyInfo(KeyInfo::doRemove, 2, false), isPatternString);
+  // but preserve added text
+  makeKey("lyxadded", KeyInfo(KeyInfo::doRemove, 1, false), isPatternString);
+
   // Macros to remove, but let the parameter survive
   // No split
   makeKey("menuitem|textmd|textrm", KeyInfo(KeyInfo::isStandard, 1, true), isPatternString);
@@ -2078,7 +2145,7 @@ string Intervall::show(int lastpos)
   if (lastpos > i) {
     s += par.substr(i, lastpos-i);
   }
-  return (s);
+  return s;
 }
 #endif
 
@@ -2119,12 +2186,17 @@ void Intervall::output(ostringstream &os, int lastpos)
     printed += lastpos-i;
   }
   handleParentheses(lastpos, false);
-  for (int i = actualdeptindex; i > 0; --i) {
+  int startindex;
+  if (keys["foreignlanguage"].disabled)
+    startindex = actualdeptindex-langcount;
+  else
+    startindex = actualdeptindex;
+  for (int i = startindex; i > 0; --i) {
     os << "}";
   }
   if (hasTitle && (printed > 0))
     os << "}";
-  if (! isPatternString)
+  if (! isPatternString_)
     os << "\n";
   handleParentheses(lastpos, true); /* extra closings '}' allowed here */
 }
@@ -2132,16 +2204,16 @@ void Intervall::output(ostringstream &os, int lastpos)
 void LatexInfo::processRegion(int start, int region_end)
 {
   while (start < region_end) {          /* Let {[} and {]} survive */
-    int cnt = interval.isOpeningPar(start);
+    int cnt = interval_.isOpeningPar(start);
     if (cnt == 1) {
       // Closing is allowed past the region
-      int closing = interval.findclosing(start+1, interval.par.length());
-      interval.addIntervall(start, start+1);
-      interval.addIntervall(closing, closing+1);
+      int closing = interval_.findclosing(start+1, interval_.par.length());
+      interval_.addIntervall(start, start+1);
+      interval_.addIntervall(closing, closing+1);
     }
     else if (cnt == 3)
       start += 2;
-    start = interval.nextNotIgnored(start+1);
+    start = interval_.nextNotIgnored(start+1);
   }
 }
 
@@ -2149,12 +2221,12 @@ void LatexInfo::removeHead(KeyInfo &actual, int count)
 {
   if (actual.parenthesiscount == 0) {
     // "{\tiny{} ...}" ==> "{{} ...}"
-    interval.addIntervall(actual._tokenstart-count, actual._tokenstart + actual._tokensize);
+    interval_.addIntervall(actual._tokenstart-count, actual._tokenstart + actual._tokensize);
   }
   else {
     // Remove header hull, that is "\url{abcd}" ==> "abcd"
-    interval.addIntervall(actual._tokenstart - count, actual._dataStart);
-    interval.addIntervall(actual._dataEnd, actual._dataEnd+1);
+    interval_.addIntervall(actual._tokenstart - count, actual._dataStart);
+    interval_.addIntervall(actual._dataEnd, actual._dataEnd+1);
   }
 }
 
@@ -2175,23 +2247,23 @@ int LatexInfo::dispatch(ostringstream &os, int previousStart, KeyInfo &actual)
       int tmpIdx = find(nextKeyIdx, KeyInfo::endArguments);
       if (tmpIdx > 0) {
         for (int i = nextKeyIdx; i <= tmpIdx; i++) {
-          entries[i].disabled = true;
+          entries_[i].disabled = true;
         }
-        actual._dataEnd = entries[tmpIdx]._dataEnd;
+        actual._dataEnd = entries_[tmpIdx]._dataEnd;
       }
-      while (interval.par[actual._dataEnd] == ' ')
+      while (interval_.par[actual._dataEnd] == ' ')
         actual._dataEnd++;
-      interval.addIntervall(0, actual._dataEnd+1);
-      interval.actualdeptindex = 0;
-      interval.depts[0] = actual._dataEnd+1;
-      interval.closes[0] = -1;
+      interval_.addIntervall(0, actual._dataEnd+1);
+      interval_.actualdeptindex = 0;
+      interval_.depts[0] = actual._dataEnd+1;
+      interval_.closes[0] = -1;
       break;
     }
     case KeyInfo::noContent: {          /* char like "\hspace{2cm}" */
       if (actual.disabled)
-        interval.addIntervall(actual._tokenstart, actual._dataEnd);
+        interval_.addIntervall(actual._tokenstart, actual._dataEnd);
       else
-        interval.addIntervall(actual._dataStart, actual._dataEnd);
+        interval_.addIntervall(actual._dataStart, actual._dataEnd);
     }
       // fall through
     case KeyInfo::isChar: {
@@ -2199,29 +2271,29 @@ int LatexInfo::dispatch(ostringstream &os, int previousStart, KeyInfo &actual)
       break;
     }
     case KeyInfo::isSize: {
-      if (actual.disabled || (interval.par[actual._dataStart] != '{') || (interval.par[actual._dataStart-1] == ' ')) {
+      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);
+        interval_.addIntervall(actual._tokenstart, actual._dataEnd+1);
         nextKeyIdx = getNextKey();
       } else {
         // Here _dataStart points to '{', so correct it
         actual._dataStart += 1;
         actual._tokensize += 1;
         actual.parenthesiscount = 1;
-        if (interval.par[actual._dataStart] == '}') {
+        if (interval_.par[actual._dataStart] == '}') {
           // Determine the end if used like '{\tiny{}...}'
-          actual._dataEnd = interval.findclosing(actual._dataStart+1, interval.par.length()) + 1;
-          interval.addIntervall(actual._dataStart, actual._dataStart+1);
+          actual._dataEnd = interval_.findclosing(actual._dataStart+1, interval_.par.length()) + 1;
+          interval_.addIntervall(actual._dataStart, actual._dataStart+1);
         }
         else {
           // Determine the end if used like '\tiny{...}'
-          actual._dataEnd = interval.findclosing(actual._dataStart, interval.par.length()) + 1;
+          actual._dataEnd = interval_.findclosing(actual._dataStart, interval_.par.length()) + 1;
         }
         // Split on this key if not at start
-        int start = interval.nextNotIgnored(previousStart);
+        int start = interval_.nextNotIgnored(previousStart);
         if (start < actual._tokenstart) {
-          interval.output(os, actual._tokenstart);
-          interval.addIntervall(start, actual._tokenstart);
+          interval_.output(os, actual._tokenstart);
+          interval_.addIntervall(start, actual._tokenstart);
         }
         // discard entry if at end of actual
         nextKeyIdx = process(os, actual);
@@ -2232,7 +2304,7 @@ int LatexInfo::dispatch(ostringstream &os, int previousStart, KeyInfo &actual)
       // Remove trailing '{}' too
       actual._dataStart += 1;
       actual._dataEnd += 1;
-      interval.addIntervall(actual._tokenstart, actual._dataEnd+1);
+      interval_.addIntervall(actual._tokenstart, actual._dataEnd+1);
       nextKeyIdx = getNextKey();
       break;
     case KeyInfo::noMain:
@@ -2244,10 +2316,10 @@ int LatexInfo::dispatch(ostringstream &os, int previousStart, KeyInfo &actual)
         nextKeyIdx = getNextKey();
       } else {
         // Split on this key if not at datastart of calling entry
-        int start = interval.nextNotIgnored(previousStart);
+        int start = interval_.nextNotIgnored(previousStart);
         if (start < actual._tokenstart) {
-          interval.output(os, actual._tokenstart);
-          interval.addIntervall(start, actual._tokenstart);
+          interval_.output(os, actual._tokenstart);
+          interval_.addIntervall(start, actual._tokenstart);
         }
         // discard entry if at end of actual
         nextKeyIdx = process(os, actual);
@@ -2260,21 +2332,37 @@ int LatexInfo::dispatch(ostringstream &os, int previousStart, KeyInfo &actual)
       int tmpIdx = find(nextKeyIdx, KeyInfo::endArguments);
       if (tmpIdx > 0) {
         for (int i = nextKeyIdx; i <= tmpIdx; i++) {
-          entries[i].disabled = true;
+          entries_[i].disabled = true;
         }
-        actual._dataEnd = entries[tmpIdx]._dataEnd;
+        actual._dataEnd = entries_[tmpIdx]._dataEnd;
       }
-      interval.addIntervall(actual._tokenstart, actual._dataEnd+1);
+      interval_.addIntervall(actual._tokenstart, actual._dataEnd+1);
       break;
     }
     case KeyInfo::doRemove: {
       // Remove the key with all parameters and following spaces
       size_t pos;
-      for (pos = actual._dataEnd+1; pos < interval.par.length(); pos++) {
-        if ((interval.par[pos] != ' ') && (interval.par[pos] != '%'))
+      for (pos = actual._dataEnd+1; pos < interval_.par.length(); pos++) {
+        if ((interval_.par[pos] != ' ') && (interval_.par[pos] != '%'))
           break;
       }
-      interval.addIntervall(actual._tokenstart, pos);
+      // Remove also enclosing parentheses [] and {}
+      int numpars = 0;
+      int spaces = 0;
+      while (actual._tokenstart > numpars) {
+        if (interval_.par[pos+numpars] == ']' && interval_.par[actual._tokenstart-numpars-1] == '[')
+          numpars++;
+        else if (interval_.par[pos+numpars] == '}' && interval_.par[actual._tokenstart-numpars-1] == '{')
+          numpars++;
+        else
+          break;
+      }
+      if (numpars > 0) {
+        if (interval_.par[pos+numpars] == ' ')
+          spaces++;
+      }
+
+      interval_.addIntervall(actual._tokenstart-numpars, pos+numpars+spaces);
       nextKeyIdx = getNextKey();
       break;
     }
@@ -2282,7 +2370,7 @@ int LatexInfo::dispatch(ostringstream &os, int previousStart, KeyInfo &actual)
       // Discard space before _tokenstart
       int count;
       for (count = 0; count < actual._tokenstart; count++) {
-        if (interval.par[actual._tokenstart-count-1] != ' ')
+        if (interval_.par[actual._tokenstart-count-1] != ' ')
           break;
       }
       nextKeyIdx = getNextKey();
@@ -2292,44 +2380,44 @@ int LatexInfo::dispatch(ostringstream &os, int previousStart, KeyInfo &actual)
         // with arguments
         // How else can we catch this one?
         for (int i = nextKeyIdx; i <= tmpIdx; i++) {
-          entries[i].disabled = true;
+          entries_[i].disabled = true;
         }
-        actual._dataEnd = entries[tmpIdx]._dataEnd;
+        actual._dataEnd = entries_[tmpIdx]._dataEnd;
       }
       else if (nextKeyIdx > 0) {
         // Ignore any lang entries inside data region
-        for (int i = nextKeyIdx; i < int(entries.size()) && entries[i]._tokenstart < actual._dataEnd; i++) {
-          if (entries[i].keytype == KeyInfo::isMain)
-            entries[i].disabled = true;
+        for (int i = nextKeyIdx; i < int(entries_.size()) && entries_[i]._tokenstart < actual._dataEnd; i++) {
+          if (entries_[i].keytype == KeyInfo::isMain)
+            entries_[i].disabled = true;
         }
       }
       if (actual.disabled) {
-        interval.addIntervall(actual._tokenstart-count, actual._dataEnd+1);
+        interval_.addIntervall(actual._tokenstart-count, actual._dataEnd+1);
       }
       else {
-        interval.addIntervall(actual._tokenstart-count, actual._tokenstart);
+        interval_.addIntervall(actual._tokenstart-count, actual._tokenstart);
       }
-      if (interval.par[actual._dataEnd+1] == '[') {
-        int posdown = interval.findclosing(actual._dataEnd+2, interval.par.length(), '[', ']');
-        if ((interval.par[actual._dataEnd+2] == '{') &&
-            (interval.par[posdown-1] == '}')) {
-          interval.addIntervall(actual._dataEnd+1,actual._dataEnd+3);
-          interval.addIntervall(posdown-1, posdown+1);
+      if (interval_.par[actual._dataEnd+1] == '[') {
+        int posdown = interval_.findclosing(actual._dataEnd+2, interval_.par.length(), '[', ']');
+        if ((interval_.par[actual._dataEnd+2] == '{') &&
+            (interval_.par[posdown-1] == '}')) {
+          interval_.addIntervall(actual._dataEnd+1,actual._dataEnd+3);
+          interval_.addIntervall(posdown-1, posdown+1);
         }
         else {
-          interval.addIntervall(actual._dataEnd+1, actual._dataEnd+2);
-          interval.addIntervall(posdown, posdown+1);
+          interval_.addIntervall(actual._dataEnd+1, actual._dataEnd+2);
+          interval_.addIntervall(posdown, posdown+1);
         }
-        int blk = interval.nextNotIgnored(actual._dataEnd+1);
+        int blk = interval_.nextNotIgnored(actual._dataEnd+1);
         if (blk > posdown) {
           // Discard at most 1 space after empty item
           int count;
           for (count = 0; count < 1; count++) {
-            if (interval.par[blk+count] != ' ')
+            if (interval_.par[blk+count] != ' ')
               break;
           }
           if (count > 0)
-            interval.addIntervall(blk, blk+count);
+            interval_.addIntervall(blk, blk+count);
         }
       }
       break;
@@ -2339,8 +2427,8 @@ int LatexInfo::dispatch(ostringstream &os, int previousStart, KeyInfo &actual)
       int count;
       int val = actual._tokenstart;
       for (count = 0; count < actual._tokenstart;) {
-        val = interval.previousNotIgnored(val-1);
-        if (interval.par[val] != ' ')
+        val = interval_.previousNotIgnored(val-1);
+        if (interval_.par[val] != ' ')
           break;
         else {
           count = actual._tokenstart - val;
@@ -2350,7 +2438,7 @@ int LatexInfo::dispatch(ostringstream &os, int previousStart, KeyInfo &actual)
         removeHead(actual, count);
         nextKeyIdx = getNextKey();
       } else {
-        interval.addIntervall(actual._tokenstart-count, actual._tokenstart);
+        interval_.addIntervall(actual._tokenstart-count, actual._tokenstart);
         nextKeyIdx = process(os, actual);
       }
       break;
@@ -2372,19 +2460,20 @@ int LatexInfo::dispatch(ostringstream &os, int previousStart, KeyInfo &actual)
       break;
     }
     case KeyInfo::isMain: {
-      if (interval.par.substr(actual._dataStart, 2) == "% ")
-        interval.addIntervall(actual._dataStart, actual._dataStart+2);
+      if (interval_.par.substr(actual._dataStart, 2) == "% ")
+        interval_.addIntervall(actual._dataStart, actual._dataStart+2);
       if (actual._tokenstart > 0) {
-        int prev = interval.previousNotIgnored(actual._tokenstart - 1);
-        if ((prev >= 0) && interval.par[prev] == '%')
-          interval.addIntervall(prev, prev+1);
+        int prev = interval_.previousNotIgnored(actual._tokenstart - 1);
+        if ((prev >= 0) && interval_.par[prev] == '%')
+          interval_.addIntervall(prev, prev+1);
       }
       if (actual.disabled) {
         removeHead(actual);
-        if ((interval.par.substr(actual._dataStart, 3) == " \\[") ||
-            (interval.par.substr(actual._dataStart, 8) == " \\begin{")) {
+        interval_.langcount++;
+        if ((interval_.par.substr(actual._dataStart, 3) == " \\[") ||
+            (interval_.par.substr(actual._dataStart, 8) == " \\begin{")) {
           // Discard also the space before math-equation
-          interval.addIntervall(actual._dataStart, actual._dataStart+1);
+          interval_.addIntervall(actual._dataStart, actual._dataStart+1);
         }
         nextKeyIdx = getNextKey();
         // interval.resetOpenedP(actual._dataStart-1);
@@ -2392,9 +2481,9 @@ int LatexInfo::dispatch(ostringstream &os, int previousStart, KeyInfo &actual)
       else {
         if (actual._tokenstart < 26) {
           // for the first (and maybe dummy) language
-          interval.setForDefaultLang(actual);
+          interval_.setForDefaultLang(actual);
         }
-        interval.resetOpenedP(actual._dataStart-1);
+        interval_.resetOpenedP(actual._dataStart-1);
       }
       break;
     }
@@ -2412,13 +2501,13 @@ int LatexInfo::dispatch(ostringstream &os, int previousStart, KeyInfo &actual)
 
 int LatexInfo::process(ostringstream &os, KeyInfo &actual )
 {
-  int end = interval.nextNotIgnored(actual._dataEnd);
+  int end = interval_.nextNotIgnored(actual._dataEnd);
   int oldStart = actual._dataStart;
   int nextKeyIdx = getNextKey();
   while (true) {
     if ((nextKeyIdx < 0) ||
-        (entries[nextKeyIdx]._tokenstart >= actual._dataEnd) ||
-        (entries[nextKeyIdx].keytype == KeyInfo::invalid)) {
+        (entries_[nextKeyIdx]._tokenstart >= actual._dataEnd) ||
+        (entries_[nextKeyIdx].keytype == KeyInfo::invalid)) {
       if (oldStart <= end) {
         processRegion(oldStart, end);
         oldStart = end+1;
@@ -2442,7 +2531,7 @@ int LatexInfo::process(ostringstream &os, KeyInfo &actual )
   if (oldStart <= end) {
     processRegion(oldStart, end);
   }
-  if (interval.par[end] == '}') {
+  if (interval_.par[end] == '}') {
     end += 1;
     // This is the normal case.
     // But if using the firstlanguage, the closing may be missing
@@ -2450,23 +2539,23 @@ int LatexInfo::process(ostringstream &os, KeyInfo &actual )
   // get minimum of 'end' and  'actual._dataEnd' in case that the nextKey.keytype was 'KeyInfo::isMain'
   int output_end;
   if (actual._dataEnd < end)
-    output_end = interval.nextNotIgnored(actual._dataEnd);
+    output_end = interval_.nextNotIgnored(actual._dataEnd);
   else
-    output_end = interval.nextNotIgnored(end);
+    output_end = interval_.nextNotIgnored(end);
   if ((actual.keytype == KeyInfo::isMain) && actual.disabled) {
-    interval.addIntervall(actual._tokenstart, actual._tokenstart+actual._tokensize);
+    interval_.addIntervall(actual._tokenstart, actual._tokenstart+actual._tokensize);
   }
   // Remove possible empty data
-  int dstart = interval.nextNotIgnored(actual._dataStart);
-  while (interval.isOpeningPar(dstart) == 1) {
-    interval.addIntervall(dstart, dstart+1);
-    int dend = interval.findclosing(dstart+1, output_end);
-    interval.addIntervall(dend, dend+1);
-    dstart = interval.nextNotIgnored(dstart+1);
+  int dstart = interval_.nextNotIgnored(actual._dataStart);
+  while (interval_.isOpeningPar(dstart) == 1) {
+    interval_.addIntervall(dstart, dstart+1);
+    int dend = interval_.findclosing(dstart+1, output_end);
+    interval_.addIntervall(dend, dend+1);
+    dstart = interval_.nextNotIgnored(dstart+1);
   }
   if (dstart < output_end)
-    interval.output(os, output_end);
-  interval.addIntervall(actual._tokenstart, end);
+    interval_.output(os, output_end);
+  interval_.addIntervall(actual._tokenstart, end);
   return nextKeyIdx;
 }
 
@@ -2597,14 +2686,14 @@ static string correctlanguagesetting(string par, bool isPatternString, bool with
                        if (b && ! info[a]) {
                                missed++;
                                LYXERR(Debug::FIND, "Missed(" << missed << " " << a <<", srclen = " << parlen );
-                               return("");
+                               return "";
                        }
                }
        }
        else {
                // LYXERR0("No regex formats");
        }
-       return(result);
+       return result;
 }
 
 
@@ -2629,6 +2718,8 @@ static int identifyClosing(string & t)
        return open_braces;
 }
 
+static int num_replaced = 0;
+static bool previous_single_replace = true;
 
 MatchStringAdv::MatchStringAdv(lyx::Buffer & buf, FindAndReplaceOptions const & opt)
        : p_buf(&buf), p_first_buf(&buf), opt(opt)
@@ -2636,6 +2727,14 @@ MatchStringAdv::MatchStringAdv(lyx::Buffer & buf, FindAndReplaceOptions const &
        Buffer & find_buf = *theBufferList().getBuffer(FileName(to_utf8(opt.find_buf_name)), true);
        docstring const & ds = stringifySearchBuffer(find_buf, opt);
        use_regexp = lyx::to_utf8(ds).find("\\regexp{") != std::string::npos;
+       if (opt.replace_all && previous_single_replace) {
+               previous_single_replace = false;
+               num_replaced = 0;
+       }
+       else if (!opt.replace_all) {
+               num_replaced = 0;       // count number of replaced strings
+               previous_single_replace = true;
+       }
        // When using regexp, braces are hacked already by escape_for_regex()
        par_as_string = normalize(ds, !use_regexp);
        open_braces = 0;
@@ -2852,7 +2951,7 @@ MatchResult MatchStringAdv::findAux(DocIterator const & cur, int len, bool at_be
 
                // Exclude from the returned match length any length
                // due to close wildcards added at end of regexp
-               // and also the length of the leading (e.g. '\emph{')
+               // and also the length of the leading (e.g. '\emph{}')
                //
                // Whole found string, including the leading: m[0].second - m[0].first
                // Size of the leading string: m[1].second - m[1].first
@@ -2860,9 +2959,9 @@ MatchResult MatchStringAdv::findAux(DocIterator const & cur, int len, bool at_be
                if (m.size() > 1)
                        leadingsize = m[1].second - m[1].first;
                int result;
-                for (size_t i = 0; i < m.size(); i++) {
-                  LYXERR(Debug::FIND, "Match " << i << " is " << m[i].second - m[i].first << " long");
-                }
+               for (size_t i = 0; i < m.size(); i++) {
+                       LYXERR(Debug::FIND, "Match " << i << " is " << m[i].second - m[i].first << " long");
+               }
                if (close_wildcards == 0)
                        result = m[0].second - m[0].first;
 
@@ -2904,7 +3003,8 @@ MatchResult MatchStringAdv::findAux(DocIterator const & cur, int len, bool at_be
                        return mres;
                }
        } else {
-               size_t pos = str.find(par_as_string_nolead);
+               // Start the search _after_ the leading part
+               size_t pos = str.find(par_as_string_nolead, lead_as_string.size());
                if (pos != string::npos) {
                        mres.match_len = par_as_string.size();
                        mres.match2end = str.size() - pos;
@@ -3425,13 +3525,13 @@ docstring stringifyFromForSearch(FindAndReplaceOptions const & opt,
 
 
 FindAndReplaceOptions::FindAndReplaceOptions(
-       docstring const & find_buf_name, bool casesensitive,
-       bool matchword, bool forward, bool expandmacros, bool ignoreformat,
-       docstring const & repl_buf_name, bool keep_case,
-       SearchScope scope, SearchRestriction restr)
-       : find_buf_name(find_buf_name), casesensitive(casesensitive), matchword(matchword),
-         forward(forward), expandmacros(expandmacros), ignoreformat(ignoreformat),
-         repl_buf_name(repl_buf_name), keep_case(keep_case), scope(scope), restr(restr)
+       docstring const & _find_buf_name, bool _casesensitive,
+       bool _matchword, bool _forward, bool _expandmacros, bool _ignoreformat,
+       docstring const & _repl_buf_name, bool _keep_case,
+       SearchScope _scope, SearchRestriction _restr, bool _replace_all)
+       : find_buf_name(_find_buf_name), casesensitive(_casesensitive), matchword(_matchword),
+         forward(_forward), expandmacros(_expandmacros), ignoreformat(_ignoreformat),
+         repl_buf_name(_repl_buf_name), keep_case(_keep_case), scope(_scope), restr(_restr), replace_all(_replace_all)
 {
 }
 
@@ -3493,29 +3593,29 @@ static void changeFirstCase(Buffer & buffer, TextCase first_case, TextCase other
 } // namespace
 
 ///
-static void findAdvReplace(BufferView * bv, FindAndReplaceOptions const & opt, MatchStringAdv & matchAdv)
+static int findAdvReplace(BufferView * bv, FindAndReplaceOptions const & opt, MatchStringAdv & matchAdv)
 {
        Cursor & cur = bv->cursor();
        if (opt.repl_buf_name == docstring()
            || theBufferList().getBuffer(FileName(to_utf8(opt.repl_buf_name)), true) == 0
            || theBufferList().getBuffer(FileName(to_utf8(opt.find_buf_name)), true) == 0)
-               return;
+               return 0;
 
        DocIterator sel_beg = cur.selectionBegin();
        DocIterator sel_end = cur.selectionEnd();
        if (&sel_beg.inset() != &sel_end.inset()
            || sel_beg.pit() != sel_end.pit()
            || sel_beg.idx() != sel_end.idx())
-               return;
+               return 0;
        int sel_len = sel_end.pos() - sel_beg.pos();
        LYXERR(Debug::FIND, "sel_beg: " << sel_beg << ", sel_end: " << sel_end
               << ", sel_len: " << sel_len << endl);
        if (sel_len == 0)
-               return;
-       LASSERT(sel_len > 0, return);
+               return 0;
+       LASSERT(sel_len > 0, return 0);
 
        if (!matchAdv(sel_beg, sel_len).match_len)
-               return;
+               return 0;
 
        // Build a copy of the replace buffer, adapted to the KeepCase option
        Buffer & repl_buffer_orig = *theBufferList().getBuffer(FileName(to_utf8(opt.repl_buf_name)), true);
@@ -3524,7 +3624,7 @@ static void findAdvReplace(BufferView * bv, FindAndReplaceOptions const & opt, M
        string lyx = oss.str();
        Buffer repl_buffer("", false);
        repl_buffer.setUnnamed(true);
-       LASSERT(repl_buffer.readString(lyx), return);
+       LASSERT(repl_buffer.readString(lyx), return 0);
        if (opt.keep_case && sel_len >= 2) {
                LYXERR(Debug::FIND, "keep_case true: cur.pos()=" << cur.pos() << ", sel_len=" << sel_len);
                if (cur.inTexted()) {
@@ -3577,6 +3677,7 @@ static void findAdvReplace(BufferView * bv, FindAndReplaceOptions const & opt, M
        LYXERR(Debug::FIND, "After pos adj cur=" << cur << " with depth: " << cur.depth() << " and len: " << sel_len);
        bv->putSelectionAt(DocIterator(cur), sel_len, !opt.forward);
        bv->processUpdateFlags(Update::Force);
+       return 1;
 }
 
 
@@ -3596,7 +3697,7 @@ bool findAdv(BufferView * bv, FindAndReplaceOptions const & opt)
                int length = bv->cursor().selectionEnd().pos() - bv->cursor().selectionBegin().pos();
                if (length > 0)
                        bv->putSelectionAt(bv->cursor().selectionBegin(), length, !opt.forward);
-               findAdvReplace(bv, opt, matchAdv);
+               num_replaced += findAdvReplace(bv, opt, matchAdv);
                cur = bv->cursor();
                if (opt.forward)
                        match_len = findForwardAdv(cur, matchAdv);
@@ -3609,11 +3710,31 @@ bool findAdv(BufferView * bv, FindAndReplaceOptions const & opt)
        }
 
        if (match_len == 0) {
-               bv->message(_("Match not found!"));
+               if (num_replaced > 0) {
+                       switch (num_replaced)
+                       {
+                               case 1:
+                                       bv->message(_("One match has been replaced."));
+                                       break;
+                               case 2:
+                                       bv->message(_("Two matches have been replaced."));
+                                       break;
+                               default:
+                                       bv->message(bformat(_("%1$d matches have been replaced."), num_replaced));
+                                       break;
+                       }
+                       num_replaced = 0;
+               }
+               else {
+                       bv->message(_("Match not found."));
+               }
                return false;
        }
 
-       bv->message(_("Match found!"));
+       if (num_replaced > 0)
+               bv->message(_("Match has been replaced."));
+       else
+               bv->message(_("Match found."));
 
        LYXERR(Debug::FIND, "Putting selection at cur=" << cur << " with len: " << match_len);
        bv->putSelectionAt(cur, match_len, !opt.forward);
@@ -3630,6 +3751,7 @@ ostringstream & operator<<(ostringstream & os, FindAndReplaceOptions const & opt
           << opt.forward << ' '
           << opt.expandmacros << ' '
           << opt.ignoreformat << ' '
+          << opt.replace_all << ' '
           << to_utf8(opt.repl_buf_name) << "\nEOSS\n"
           << opt.keep_case << ' '
           << int(opt.scope) << ' '
@@ -3657,7 +3779,7 @@ istringstream & operator>>(istringstream & is, FindAndReplaceOptions & opt)
        }
        LYXERR(Debug::FIND, "file_buf_name: '" << s << "'");
        opt.find_buf_name = from_utf8(s);
-       is >> opt.casesensitive >> opt.matchword >> opt.forward >> opt.expandmacros >> opt.ignoreformat;
+       is >> opt.casesensitive >> opt.matchword >> opt.forward >> opt.expandmacros >> opt.ignoreformat >> opt.replace_all;
        is.get();       // Waste space before replace string
        s = "";
        getline(is, line);