]> git.lyx.org Git - lyx.git/blobdiff - src/lyxfind.cpp
Let tm be a reference here as elsewhere
[lyx.git] / src / lyxfind.cpp
index 4bc5295f251035e2cf1948ad25487276336bec5f..0e996dc1660d9da1875166469181ae60e42aa1f4 100644 (file)
@@ -59,6 +59,111 @@ using namespace lyx::support;
 
 namespace lyx {
 
+
+// Helper class for deciding what should be ignored
+class IgnoreFormats {
+ public:
+       ///
+       IgnoreFormats()
+               : ignoreFamily_(false), ignoreSeries_(false),
+                 ignoreShape_(false), ignoreUnderline_(false),
+                 ignoreMarkUp_(false), ignoreStrikeOut_(false),
+                 ignoreSectioning_(false), ignoreFrontMatter_(true),
+                 ignoreColor_(false), ignoreLanguage_(false) {}
+       ///
+       bool getFamily() { return ignoreFamily_; };
+       ///
+       bool getSeries() { return ignoreSeries_; };
+       ///
+       bool getShape() { return ignoreShape_; };
+       ///
+       bool getUnderline() { return ignoreUnderline_; };
+       ///
+       bool getMarkUp() { return ignoreMarkUp_; };
+       ///
+       bool getStrikeOut() { return ignoreStrikeOut_; };
+       ///
+       bool getSectioning() { return ignoreSectioning_; };
+       ///
+       bool getFrontMatter() { return ignoreFrontMatter_; };
+       ///
+       bool getColor() { return ignoreColor_; };
+       ///
+       bool getLanguage() { return ignoreLanguage_; };
+       ///
+       void setIgnoreFormat(string type, bool value);
+
+private:
+       ///
+       bool ignoreFamily_;
+       ///
+       bool ignoreSeries_;
+       ///
+       bool ignoreShape_;
+       ///
+       bool ignoreUnderline_;
+       ///
+       bool ignoreMarkUp_;
+       ///
+       bool ignoreStrikeOut_;
+       ///
+       bool ignoreSectioning_;
+       ///
+       bool ignoreFrontMatter_;
+       ///
+       bool ignoreColor_;
+       ///
+       bool ignoreLanguage_;
+};
+
+
+void IgnoreFormats::setIgnoreFormat(string type, bool value)
+{
+       if (type == "color") {
+               ignoreColor_ = value;
+       }
+       else if (type == "language") {
+               ignoreLanguage_ = value;
+       }
+       else if (type == "sectioning") {
+               ignoreSectioning_ = value;
+               ignoreFrontMatter_ = value;
+       }
+       else if (type == "font") {
+               ignoreSeries_ = value;
+               ignoreShape_ = value;
+               ignoreFamily_ = value;
+       }
+       else if (type == "series") {
+               ignoreSeries_ = value;
+       }
+       else if (type == "shape") {
+               ignoreShape_ = value;
+       }
+       else if (type == "family") {
+               ignoreFamily_ = value;
+       }
+       else if (type == "markup") {
+               ignoreMarkUp_ = value;
+       }
+       else if (type == "underline") {
+               ignoreUnderline_ = value;
+       }
+       else if (type == "strike") {
+               ignoreStrikeOut_ = value;
+       }
+}
+
+// The global variable that can be changed from outside
+IgnoreFormats ignoreFormats;
+
+
+void setIgnoreFormat(string type, bool value)
+{
+       ignoreFormats.setIgnoreFormat(type, value);
+}
+
+
 namespace {
 
 bool parse_bool(docstring & howto)
@@ -775,7 +880,7 @@ private:
        string par_as_string;
        // regular expression to use for searching
        lyx::regex regexp;
-       // same as regexp, but prefixed with a ".*"
+       // same as regexp, but prefixed with a ".*?"
        lyx::regex regexp2;
        // leading format material as string
        string lead_as_string;
@@ -846,7 +951,7 @@ static size_t identifyLeading(string const & s)
        // @TODO Support \item[text]
        // Kornel: Added textsl, textsf, textit, texttt and noun
        // + allow to search for colored text too
-       while (regex_replace(t, t, REGEX_BOS "\\\\(((emph|noun|minisec|text(bf|sl|sf|it|tt))|((textcolor|foreignlanguage)\\{[a-z]+\\})|(u|uu)line|(s|x)out|uwave)|((sub)?(((sub)?section)|paragraph)|part|chapter)\\*?)\\{", "")
+       while (regex_replace(t, t, REGEX_BOS "\\\\(((footnotesize|tiny|scriptsize|small|large|Large|LARGE|huge|Huge|emph|noun|minisec|text(bf|md|sl|sf|it|tt))|((textcolor|foreignlanguage)\\{[a-z]+\\})|(u|uu)line|(s|x)out|uwave)|((sub)?(((sub)?section)|paragraph)|part|chapter)\\*?)\\{", "")
               || regex_replace(t, t, REGEX_BOS "\\$", "")
               || regex_replace(t, t, REGEX_BOS "\\\\\\[ ", "")
               || regex_replace(t, t, REGEX_BOS " ?\\\\item\\{[a-z]+\\}", "")
@@ -868,7 +973,7 @@ typedef map<string, bool> Features;
 static Features identifyFeatures(string const & s)
 {
        static regex const feature("\\\\(([a-z]+(\\{([a-z]+)\\}|\\*)?))\\{");
-       static regex const valid("^(((emph|noun|text(bf|sl|sf|it|tt)|(textcolor|foreignlanguage|item)\\{[a-z]+\\})|(u|uu)line|(s|x)out|uwave)|((sub)?(((sub)?section)|paragraph)|part|chapter)\\*?)$");
+       static regex const valid("^(((footnotesize|tiny|scriptsize|small|large|Large|LARGE|huge|Huge|emph|noun|text(bf|md|sl|sf|it|tt)|(textcolor|foreignlanguage|item)\\{[a-z]+\\})|(u|uu)line|(s|x)out|uwave)|((sub)?(((sub)?section)|paragraph)|part|chapter)\\*?)$");
        smatch sub;
        bool displ = true;
        Features info;
@@ -905,27 +1010,60 @@ static Features identifyFeatures(string const & s)
 class KeyInfo {
  public:
   enum KeyType {
+    /* Char type with content discarded
+     * like \hspace{1cm} */
+    noContent,
+    /* Char, like \backslash */
     isChar,
+    /* \part, \section*, ... */
     isSectioning,
-    isMain,                             /* for \\foreignlanguage */
+    /* \foreignlanguage{ngerman}, ... */
+    isMain,
+    /* inside \code{} or \footnote{}
+     * to discard language in content */
+    noMain,
     isRegex,
+    /* \begin{eqnarray}...\end{eqnarray}, ... $...$ */
     isMath,
+    /* fonts, colors, markups, ... */
     isStandard,
+    /* footnotesize, ... large, ...
+     * Ignore all of them */
     isSize,
     invalid,
+    /* inputencoding, shortcut, ...
+     * Discard also content, because they do not help in search */
     doRemove,
+    /* twocolumns, ...
+     * like remove, but also all arguments */
+    removeWithArg,
+    /* item, listitem */
     isList,
-    isIgnored                           /* to be ignored by creating infos */
+    /* tex, latex, ... like isChar */
+    isIgnored,
+    /* like \lettrine[lines=5]{}{} */
+    cleanToStart,
+    /* End of arguments marker for lettrine,
+     * so that they can be ignored */
+    endArguments
   };
  KeyInfo()
    : keytype(invalid),
     head(""),
+    _tokensize(-1),
+    _tokenstart(-1),
+    _dataStart(-1),
+    _dataEnd(-1),
     parenthesiscount(1),
     disabled(false),
     used(false)
   {};
  KeyInfo(KeyType type, int parcount, bool disable)
    : keytype(type),
+    _tokensize(-1),
+    _tokenstart(-1),
+    _dataStart(-1),
+    _dataEnd(-1),
     parenthesiscount(parcount),
     disabled(disable),
     used(false) {};
@@ -951,14 +1089,17 @@ class Border {
 class Intervall {
   bool isPatternString;
  public:
- Intervall(bool isPattern) : isPatternString(isPattern), ignoreidx(-1), actualdeptindex(0) {};
+ explicit Intervall(bool isPattern) :
+  isPatternString(isPattern),
+    ignoreidx(-1),
+    actualdeptindex(0) { depts[0] = 0; closes[0] = 0;};
   string par;
   int ignoreidx;
   int depts[MAXOPENED];
   int closes[MAXOPENED];
   int actualdeptindex;
   Border borders[2*MAXOPENED];
-  // int previousNotIgnored(int);
+  int previousNotIgnored(int);
   int nextNotIgnored(int);
   void handleOpenP(int i);
   void handleCloseP(int i, bool closingAllowed);
@@ -966,7 +1107,7 @@ class Intervall {
   void addIntervall(int upper);
   void addIntervall(int low, int upper); /* if explicit */
   void setForDefaultLang(int upTo);
-  int findclosing(int start, int end, char up, char down);
+  int findclosing(int start, int end, char up, char down, int repeat);
   void handleParentheses(int lastpos, bool closingAllowed);
   void output(ostringstream &os, int lastpos);
   // string show(int lastpos);
@@ -1091,26 +1232,24 @@ void Intervall::resetOpenedP(int openPos)
   closes[1] = -1;
 }
 
-#if 0
 int Intervall::previousNotIgnored(int start)
 {
     int idx = 0;                          /* int intervalls */
     for (idx = ignoreidx; idx >= 0; --idx) {
       if (start > borders[idx].upper)
-        return(start);
+        return start;
       if (start >= borders[idx].low)
         start = borders[idx].low-1;
     }
     return start;
 }
-#endif
 
 int Intervall::nextNotIgnored(int start)
 {
     int idx = 0;                          /* int intervalls */
     for (idx = 0; idx <= ignoreidx; idx++) {
       if (start < borders[idx].low)
-        return(start);
+        return start;
       if (start < borders[idx].upper)
         start = borders[idx].upper;
     }
@@ -1121,96 +1260,6 @@ typedef map<string, KeyInfo> KeysMap;
 typedef vector< KeyInfo> Entries;
 static KeysMap keys = map<string, KeyInfo>();
 
-class IgnoreFormats {
-  static bool ignoreFamily;
-  static bool ignoreSeries;
-  static bool ignoreShape;
-  static bool ignoreUnderline;
-  static bool ignoreMarkUp;
-  static bool ignoreStrikeOut;
-  static bool ignoreSectioning;
-  static bool ignoreFrontMatter;
-  static bool ignoreColor;
-  static bool ignoreLanguage;
- public:
-  bool getFamily() { return ignoreFamily; };
-  bool getSeries() { return ignoreSeries; };
-  bool getShape() { return ignoreShape; };
-  bool getUnderline() { return ignoreUnderline; };
-  bool getMarkUp() { return ignoreMarkUp; };
-  bool getStrikeOut() { return ignoreStrikeOut; };
-  bool getSectioning() { return ignoreSectioning; };
-  bool getFrontMatter() { return ignoreFrontMatter; };
-  bool getColor() { return ignoreColor; };
-  bool getLanguage() { return ignoreLanguage; };
-
-  void setIgnoreFormat(string type, bool value);
-};
-
-bool IgnoreFormats::ignoreFamily     = false;
-bool IgnoreFormats::ignoreSeries     = false;
-bool IgnoreFormats::ignoreShape      = false;
-bool IgnoreFormats::ignoreUnderline  = false;
-bool IgnoreFormats::ignoreMarkUp     = false;
-bool IgnoreFormats::ignoreStrikeOut  = false;
-bool IgnoreFormats::ignoreSectioning = false;
-bool IgnoreFormats::ignoreFrontMatter= true;
-bool IgnoreFormats::ignoreColor      = false;
-bool IgnoreFormats::ignoreLanguage   = false;
-
-void IgnoreFormats::setIgnoreFormat(string type, bool value)
-{
-  if (type == "color") {
-    ignoreColor = value;
-  }
-  else if (type == "language") {
-    ignoreLanguage = value;
-  }
-  else if (type == "sectioning") {
-    ignoreSectioning = value;
-    ignoreFrontMatter = value;
-  }
-  else if (type == "font") {
-    ignoreSeries = value;
-    ignoreShape = value;
-    ignoreFamily = value;
-  }
-  else if (type == "series") {
-    ignoreSeries = value;
-  }
-  else if (type == "shape") {
-    ignoreShape = value;
-  }
-  else if (type == "family") {
-    ignoreFamily = value;
-  }
-  else if (type == "markup") {
-    ignoreMarkUp = value;
-  }
-  else if (type == "underline") {
-    ignoreUnderline = value;
-  }
-  else if (type == "strike") {
-    ignoreStrikeOut = value;
-  }
-}
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wpragmas"
-#pragma GCC diagnostic ignored "-Wunused"
-#pragma GCC diagnostic ignored "-Wunused-function"
-
-#ifdef __GNUC__
-#define SUPPRESS_NOT_USED_WARN __attribute__ ((unused))
-#else
-#define SUPPRESS_NOT_USED_WARN
-#endif
-
-void SUPPRESS_NOT_USED_WARN setIgnoreFormat(string type, bool value)
-{
-  IgnoreFormats().setIgnoreFormat(type, value);
-}
-#pragma GCC diagnostic pop
-
 class LatexInfo {
  private:
   int entidx;
@@ -1221,10 +1270,9 @@ class LatexInfo {
   void makeKey(const string &, KeyInfo, bool isPatternString);
   void processRegion(int start, int region_end); /*  remove {} parts */
   void removeHead(KeyInfo&, int count=0);
-  IgnoreFormats f;
 
  public:
- LatexInfo(string par, bool isPatternString) : interval(isPatternString) {
+ LatexInfo(string par, bool isPatternString) : entidx(-1), interval(isPatternString) {
     interval.par = par;
     buildKeys(isPatternString);
     entries = vector<KeyInfo>();
@@ -1252,7 +1300,18 @@ class LatexInfo {
       return true;
     }
     else
-      return(false);
+      return false;
+  };
+  int find(int start, KeyInfo::KeyType keytype) {
+    if (start < 0)
+      return (-1);
+    int tmpIdx = start;
+    while (tmpIdx < int(entries.size())) {
+      if (entries[tmpIdx].keytype == keytype)
+        return tmpIdx;
+      tmpIdx++;
+    }
+    return(-1);
   };
   int process(ostringstream &os, KeyInfo &actual);
   int dispatch(ostringstream &os, int previousStart, KeyInfo &actual);
@@ -1266,14 +1325,15 @@ class LatexInfo {
       return entries[keyinfo];
   };
   void setForDefaultLang(int upTo) {interval.setForDefaultLang(upTo);};
-
+  void addIntervall(int low, int up) { interval.addIntervall(low, up); };
 };
 
 
-int Intervall::findclosing(int start, int end, char up = '{', char down = '}')
+int Intervall::findclosing(int start, int end, char up = '{', char down = '}', int repeat = 1)
 {
   int skip = 0;
   int depth = 0;
+  repeat--;
   for (int i = start; i < end; i += 1 + skip) {
     char c;
     c = par[i];
@@ -1283,11 +1343,14 @@ int Intervall::findclosing(int start, int end, char up = '{', char down = '}')
       depth++;
     }
     else if (c == down) {
-      if (depth == 0) return(i);
+      if (depth == 0) {
+        if ((repeat <= 0) || (par[i+1] != up))
+          return i;
+      }
       --depth;
     }
   }
-  return(end);
+  return end;
 }
 
 class MathInfo {
@@ -1312,17 +1375,7 @@ class MathInfo {
     m.mathSize = end - start;
     entries.push_back(m);
   }
-  bool evaluating(size_t pos) {
-    while (actualIdx < entries.size()) {
-      if (pos < entries[actualIdx].mathStart)
-        return false;
-      if (pos < entries[actualIdx].mathEnd)
-        return true;
-      actualIdx++;
-    }
-    return false;
-  }
-  bool empty() { return(entries.empty()); };
+  bool empty() { return entries.empty(); };
   size_t getEndPos() {
     if (entries.empty() || (actualIdx >= entries.size())) {
       return 0;
@@ -1350,13 +1403,18 @@ class MathInfo {
 
 void LatexInfo::buildEntries(bool isPatternString)
 {
-  static regex const rmath("\\$|\\\\\\[|\\\\\\]|\\\\(begin|end)\\{((eqnarray|equation|flalign|gather|multiline|align)\\*?)\\}");
+  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;
   MathInfo mi;
   bool evaluatingMath = false;
+  bool evaluatingCode = false;
+  size_t codeEnd = 0;
+  bool evaluatingOptional = false;
+  size_t optionalEnd = 0;
+  int codeStart = -1;
   KeyInfo found;
   bool math_end_waiting = false;
   size_t math_pos = 10000;
@@ -1366,23 +1424,24 @@ void LatexInfo::buildEntries(bool isPatternString)
     submath = *itmath;
     if (math_end_waiting) {
       size_t pos = submath.position(size_t(0));
-      if (math_end == "$") {
-        if ((submath.str(0) == "$") && (interval.par[pos-1] != '\\')) {
-          mi.insert("$", math_pos, pos + 1);
-          math_end_waiting = false;
-        }
+      if ((math_end == "$") &&
+          (submath.str(0) == "$") &&
+          (interval.par[pos-1] != '\\')) {
+        mi.insert("$", math_pos, pos + 1);
+        math_end_waiting = false;
       }
-      else if (math_end == "\\]") {
-        if (submath.str(0) == "\\]") {
-          mi.insert("\\]", math_pos, pos + 2);
-          math_end_waiting = false;
-        }
+      else if ((math_end == "\\]") &&
+               (submath.str(0) == "\\]")) {
+        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());
         math_end_waiting = false;
       }
+      else
+        continue;
     }
     else {
       if (submath.str(1).compare("begin") == 0) {
@@ -1427,8 +1486,16 @@ void LatexInfo::buildEntries(bool isPatternString)
     if (key == "") {
       if (sub.str(0)[0] == '\\')
         key = sub.str(0)[1];
-      else
+      else {
         key = sub.str(0);
+        if (key == "$") {
+          size_t k_pos = sub.position(size_t(0));
+          if ((k_pos > 0) && (interval.par[k_pos - 1] == '\\')) {
+            // Escaped '$', ignoring
+            continue;
+          }
+        }
+      }
     };
     if (evaluatingRegexp) {
       if (sub.str(1).compare("endregexp") == 0) {
@@ -1449,10 +1516,16 @@ void LatexInfo::buildEntries(bool isPatternString)
         math_pos = mi.getStartPos();
       }
       if (keys.find(key) == keys.end()) {
-        LYXERR(Debug::FIND, "Found unknown key " << sub.str(0));
-        continue;
+        found = KeyInfo(KeyInfo::isStandard, 0, true);
+        if (isPatternString) {
+          found.keytype = KeyInfo::isChar;
+          found.disabled = false;
+          found.used = true;
+        }
+        keys[key] = found;
       }
-      found = keys[key];
+      else
+        found = keys[key];
       if (key.compare("regexp") == 0) {
         evaluatingRegexp = true;
         found._tokenstart = sub.position(size_t(0));
@@ -1473,14 +1546,85 @@ void LatexInfo::buildEntries(bool isPatternString)
         found.parenthesiscount = 0;
         evaluatingMath = true;
       }
-      else
-        continue;
+      else {
+        // begin|end of unknown env, discard
+        // First handle tables
+        // longtable|tabular
+        bool discardComment;
+        found = keys[key];
+        found.keytype = KeyInfo::doRemove;
+        if ((sub.str(5).compare("longtable") == 0) ||
+            (sub.str(5).compare("tabular") == 0)) {
+          discardComment = true;        /* '%' */
+        }
+        else {
+          discardComment = false;
+          static regex const removeArgs("^(multicols|multipar|sectionbox|subsectionbox|tcolorbox)$");
+          smatch sub2;
+          string token = sub.str(5);
+          if (regex_match(token, sub2, removeArgs)) {
+            found.keytype = KeyInfo::removeWithArg;
+          }
+        }
+        // discard spaces before pos(0)
+        int pos = sub.position(size_t(0));
+        int count;
+        for (count = 0; pos - count > 0; count++) {
+          char c = interval.par[pos-count-1];
+          if (discardComment) {
+            if ((c != ' ') && (c != '%'))
+              break;
+          }
+          else if (c != ' ')
+            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) {
+            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.disabled = keys["foreignlanguage"].disabled;
+            found.used = keys["foreignlanguage"].used;
+            found._tokensize = pos1 - found._tokenstart;
+            found.head = interval.par.substr(found._tokenstart, found._tokensize);
+          }
+          else {
+            while (interval.par[pos1] == '[') {
+              pos1 = 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;
+            }
+            found._dataStart = found._dataEnd;
+            found._tokensize = count + found._dataEnd - pos;
+            found.parenthesiscount = 0;
+            found.disabled = true;
+          }
+        }
+        else {
+          // Handle "\end{...}"
+          found._dataStart = pos + sub.str(0).length();
+          found._dataEnd = found._dataStart;
+          found._tokensize = count + found._dataEnd - pos;
+          found.parenthesiscount = 0;
+          found.disabled = true;
+        }
+      }
     }
     else if (found.keytype != KeyInfo::isRegex) {
       found._tokenstart = sub.position(size_t(0));
       if (found.parenthesiscount == 0) {
         // Probably to be discarded
-        char following = interval.par[sub.position(size_t(0)) + sub.str(3).length() + 1];
+        size_t following_pos = sub.position(size_t(0)) + sub.str(3).length() + 1;
+        char following = interval.par[following_pos];
         if (following == ' ')
           found.head = "\\" + sub.str(3) + " ";
         else if (following == '=') {
@@ -1494,18 +1638,88 @@ void LatexInfo::buildEntries(bool isPatternString)
         found._dataStart = found._dataEnd;
       }
       else {
+        int params = found._tokenstart + key.length() + 1;
+        if (evaluatingOptional) {
+          if (size_t(found._tokenstart) > optionalEnd) {
+            evaluatingOptional = false;
+          }
+          else {
+            found.disabled = true;
+          }
+        }
+        int optend = params;
+        while (interval.par[optend] == '[') {
+          // discard optional parameters
+          optend = interval.findclosing(optend+1, interval.par.length(), '[', ']') + 1;
+        }
+        if (optend > params) {
+          key += interval.par.substr(params, optend-params);
+          evaluatingOptional = true;
+          optionalEnd = optend;
+        }
+        string token = sub.str(5);
+        int closings = found.parenthesiscount;
         if (found.parenthesiscount == 1) {
           found.head = "\\" + key + "{";
         }
-        else if (found.parenthesiscount == 2) {
-          found.head = sub.str(0) + "{";
+        else if (found.parenthesiscount > 1) {
+          if (token != "") {
+            found.head = sub.str(0) + "{";
+            closings = found.parenthesiscount - 1;
+          }
+          else {
+            found.head = "\\" + key + "{";
+          }
         }
-        found._tokensize = found.head.length();
         found._dataStart = found._tokenstart + found.head.length();
-        found._dataEnd = interval.findclosing(found._dataStart, interval.par.length());
-        if (isPatternString) {
-          keys[key].used = true;
+        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);
+        if (found.keytype == KeyInfo::isList) {
+          // Check if it really is list env
+          static regex const listre("^([a-z]+)$");
+          smatch sub2;
+          if (!regex_match(token, sub2, listre)) {
+            // Change the key of this entry. It is not in a list/item environment
+            found.keytype = KeyInfo::endArguments;
+          }
+        }
+        if (found.keytype == KeyInfo::noMain) {
+          evaluatingCode = true;
+          codeEnd = endpos;
+          codeStart = found._dataStart;
         }
+        else if (evaluatingCode) {
+          if (size_t(found._dataStart) > codeEnd)
+            evaluatingCode = false;
+          else if (found.keytype == KeyInfo::isMain) {
+            // Disable this key, treate it as standard
+            found.keytype = KeyInfo::isStandard;
+            found.disabled = true;
+            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 ((endpos == interval.par.length()) &&
+            (found.keytype == KeyInfo::doRemove)) {
+          // Missing closing => error in latex-input?
+          // therefore do not delete remaining data
+          found._dataStart -= 1;
+          found._dataEnd = found._dataStart;
+        }
+        else
+          found._dataEnd = endpos;
+      }
+      if (isPatternString) {
+        keys[key].used = true;
       }
     }
     entries.push_back(found);
@@ -1534,58 +1748,94 @@ void LatexInfo::buildKeys(bool isPatternString)
   static bool keysBuilt = false;
   if (keysBuilt && !isPatternString) return;
 
-  // Know standard keys with 1 parameter.
+  // Known standard keys with 1 parameter.
   // Split is done, if not at start of region
-  makeKey("textsf|textss|texttt", KeyInfo(KeyInfo::isStandard, 1, f.getFamily()), isPatternString);
-  makeKey("textbf",               KeyInfo(KeyInfo::isStandard, 1, f.getSeries()), isPatternString);
-  makeKey("textit|textsc|textsl", KeyInfo(KeyInfo::isStandard, 1, f.getShape()), isPatternString);
-  makeKey("uuline|uline|uwave",   KeyInfo(KeyInfo::isStandard, 1, f.getUnderline()), isPatternString);
-  makeKey("emph|noun",            KeyInfo(KeyInfo::isStandard, 1, f.getMarkUp()), isPatternString);
-  makeKey("sout|xout",            KeyInfo(KeyInfo::isStandard, 1, f.getStrikeOut()), isPatternString);
+  makeKey("textsf|textss|texttt", KeyInfo(KeyInfo::isStandard, 1, ignoreFormats.getFamily()), isPatternString);
+  makeKey("textbf",               KeyInfo(KeyInfo::isStandard, 1, ignoreFormats.getSeries()), isPatternString);
+  makeKey("textit|textsc|textsl", KeyInfo(KeyInfo::isStandard, 1, ignoreFormats.getShape()), isPatternString);
+  makeKey("uuline|uline|uwave",   KeyInfo(KeyInfo::isStandard, 1, ignoreFormats.getUnderline()), isPatternString);
+  makeKey("emph|noun",            KeyInfo(KeyInfo::isStandard, 1, ignoreFormats.getMarkUp()), isPatternString);
+  makeKey("sout|xout",            KeyInfo(KeyInfo::isStandard, 1, ignoreFormats.getStrikeOut()), isPatternString);
 
   makeKey("section|subsection|subsubsection|paragraph|subparagraph|minisec",
-          KeyInfo(KeyInfo::isSectioning, 1, f.getSectioning()), isPatternString);
+          KeyInfo(KeyInfo::isSectioning, 1, ignoreFormats.getSectioning()), isPatternString);
   makeKey("section*|subsection*|subsubsection*|paragraph*",
-          KeyInfo(KeyInfo::isSectioning, 1, f.getSectioning()), isPatternString);
-  makeKey("part|part*|chapter|chapter*", KeyInfo(KeyInfo::isSectioning, 1, f.getSectioning()), isPatternString);
-  makeKey("title|subtitle|author|subject|publishers|dedication|uppertitleback|lowertitleback|extratitle|lyxaddress|lyxrightaddress", KeyInfo(KeyInfo::isSectioning, 1, f.getFrontMatter()), isPatternString);
+          KeyInfo(KeyInfo::isSectioning, 1, ignoreFormats.getSectioning()), isPatternString);
+  makeKey("part|part*|chapter|chapter*", KeyInfo(KeyInfo::isSectioning, 1, ignoreFormats.getSectioning()), isPatternString);
+  makeKey("title|subtitle|author|subject|publishers|dedication|uppertitleback|lowertitleback|extratitle|lyxaddress|lyxrightaddress", KeyInfo(KeyInfo::isSectioning, 1, ignoreFormats.getFrontMatter()), isPatternString);
   // Regex
   makeKey("regexp", KeyInfo(KeyInfo::isRegex, 1, false), isPatternString);
 
   // Split is done, if not at start of region
-  makeKey("textcolor", KeyInfo(KeyInfo::isStandard, 2, f.getColor()), isPatternString);
+  makeKey("textcolor", KeyInfo(KeyInfo::isStandard, 2, ignoreFormats.getColor()), isPatternString);
 
   // Split is done always.
-  makeKey("foreignlanguage", KeyInfo(KeyInfo::isMain, 2, f.getLanguage()), isPatternString);
+  makeKey("foreignlanguage", KeyInfo(KeyInfo::isMain, 2, ignoreFormats.getLanguage()), isPatternString);
 
   // Know charaters
   // No split
-  makeKey("backslash|textbackslash|textasciicircum|textasciitilde", KeyInfo(KeyInfo::isChar, 1, false), isPatternString);
-
+  makeKey("backslash|textbackslash|slash",  KeyInfo(KeyInfo::isChar, 0, false), isPatternString);
+  makeKey("textasciicircum|textasciitilde", KeyInfo(KeyInfo::isChar, 0, false), isPatternString);
+  makeKey("textasciiacute|texemdash",       KeyInfo(KeyInfo::isChar, 0, false), isPatternString);
+  makeKey("dots|ldots",                     KeyInfo(KeyInfo::isChar, 0, false), isPatternString);
+  // Spaces
+  makeKey("quad|qquad|hfill|dotfill",               KeyInfo(KeyInfo::isChar, 0, false), isPatternString);
+  makeKey("textvisiblespace|nobreakspace",          KeyInfo(KeyInfo::isChar, 0, false), isPatternString);
+  makeKey("negthickspace|negmedspace|negthinspace", KeyInfo(KeyInfo::isChar, 0, false), isPatternString);
+  // Skip
+  // makeKey("enskip|smallskip|medskip|bigskip|vfill", KeyInfo(KeyInfo::isChar, 0, false), isPatternString);
+  // Custom space/skip, remove the content (== length value)
+  makeKey("vspace|hspace|mspace", KeyInfo(KeyInfo::noContent, 1, false), isPatternString);
+  // Found in fr/UserGuide.lyx
+  makeKey("og|fg", KeyInfo(KeyInfo::isChar, 0, false), isPatternString);
+  // quotes
+  makeKey("textquotedbl|quotesinglbase|lyxarrow", KeyInfo(KeyInfo::isChar, 0, false), isPatternString);
+  makeKey("textquotedblleft|textquotedblright", KeyInfo(KeyInfo::isChar, 0, false), isPatternString);
   // Known macros to remove (including their parameter)
   // No split
-  makeKey("inputencoding|shortcut|label|ref", KeyInfo(KeyInfo::doRemove, 1, false), isPatternString);
+  makeKey("inputencoding|shortcut|label|ref|index|bibitem", KeyInfo(KeyInfo::doRemove, 1, false), isPatternString);
+  makeKey("addtocounter|setlength",                 KeyInfo(KeyInfo::noContent, 2, true), isPatternString);
+  // handle like standard keys with 1 parameter.
+  makeKey("url|href|vref|thanks", KeyInfo(KeyInfo::isStandard, 1, false), isPatternString);
 
   // Macros to remove, but let the parameter survive
   // No split
-  makeKey("url|href|menuitem|footnote|code", KeyInfo(KeyInfo::isStandard, 1, true), isPatternString);
+  makeKey("menuitem|textmd|textrm", KeyInfo(KeyInfo::isStandard, 1, true), isPatternString);
+
+  // Remove language spec from content of these insets
+  makeKey("code", KeyInfo(KeyInfo::noMain, 1, false), isPatternString);
 
   // Same effect as previous, parameter will survive (because there is no one anyway)
   // No split
-  makeKey("noindent", KeyInfo(KeyInfo::isStandard, 0, true), isPatternString);
-  // like ('tiny{}' or '\tiny ' ... }
-  makeKey("footnotesize|tiny|scriptsize|small|large|Large|LARGE|huge|Huge", KeyInfo(KeyInfo::isSize, 0, true), isPatternString);
+  makeKey("noindent|textcompwordmark", KeyInfo(KeyInfo::isStandard, 0, true), isPatternString);
+  // Remove table decorations
+  makeKey("hline|tabularnewline|toprule|bottomrule|midrule", KeyInfo(KeyInfo::doRemove, 0, true), isPatternString);
+  // Discard shape-header
+  makeKey("circlepar|diamondpar|heartpar|nutpar",  KeyInfo(KeyInfo::isStandard, 1, true), isPatternString);
+  makeKey("trianglerightpar|hexagonpar|starpar",   KeyInfo(KeyInfo::isStandard, 1, true), isPatternString);
+  makeKey("triangleuppar|triangledownpar|droppar", KeyInfo(KeyInfo::isStandard, 1, true), isPatternString);
+  makeKey("triangleleftpar|shapepar|dropuppar",    KeyInfo(KeyInfo::isStandard, 1, true), isPatternString);
+  makeKey("hphantom|footnote|includegraphics",     KeyInfo(KeyInfo::isStandard, 1, true), isPatternString);
+  // like ('tiny{}' or '\tiny ' ... )
+  makeKey("footnotesize|tiny|scriptsize|small|large|Large|LARGE|huge|Huge", KeyInfo(KeyInfo::isSize, 0, false), isPatternString);
 
   // Survives, like known character
-  makeKey("lyx|latex|tex", KeyInfo(KeyInfo::isIgnored, 0, false), isPatternString);
-  makeKey("item", KeyInfo(KeyInfo::isList, 1, false), isPatternString);
+  makeKey("lyx|LyX|latex|LaTeX|latexe|LaTeXe|tex|TeX", KeyInfo(KeyInfo::isChar, 0, false), isPatternString);
+  makeKey("item|listitem", KeyInfo(KeyInfo::isList, 1, false), isPatternString);
 
   makeKey("begin|end", KeyInfo(KeyInfo::isMath, 1, false), isPatternString);
   makeKey("[|]", KeyInfo(KeyInfo::isMath, 1, false), isPatternString);
   makeKey("$", KeyInfo(KeyInfo::isMath, 1, false), isPatternString);
 
-  makeKey("par|uldepth|ULdepth|protect", KeyInfo(KeyInfo::doRemove, 0, true), isPatternString);
-
+  makeKey("par|uldepth|ULdepth|protect|nobreakdash|medskip|relax", KeyInfo(KeyInfo::isStandard, 0, true), isPatternString);
+  // Remove RTL/LTR marker
+  makeKey("l|r|textlr|textfr|textar|beginl|endl", KeyInfo(KeyInfo::isStandard, 0, true), isPatternString);
+  makeKey("lettrine", KeyInfo(KeyInfo::cleanToStart, 0, true), isPatternString);
+  makeKey("lyxslide", KeyInfo(KeyInfo::isSectioning, 1, true), isPatternString);
+  makeKey("endarguments", KeyInfo(KeyInfo::endArguments, 0, true), isPatternString);
+  makeKey("twocolumn", KeyInfo(KeyInfo::removeWithArg, 2, true), isPatternString);
+  makeKey("tnotetext|ead|fntext|cortext|address", KeyInfo(KeyInfo::removeWithArg, 0, true), isPatternString);
+  makeKey("lyxend", KeyInfo(KeyInfo::isStandard, 0, true), isPatternString);
   if (isPatternString) {
     // Allow the first searched string to rebuild the keys too
     keysBuilt = false;
@@ -1621,7 +1871,6 @@ void Intervall::handleParentheses(int lastpos, bool closingAllowed)
 string Intervall::show(int lastpos)
 {
   int idx = 0;                          /* int intervalls */
-  int count = 0;
   string s;
   int i = 0;
   for (idx = 0; idx <= ignoreidx; idx++) {
@@ -1657,8 +1906,8 @@ void Intervall::output(ostringstream &os, int lastpos)
   int i = 0;
   for (idx = 0; idx <= ignoreidx; idx++) {
     if (i < lastpos) {
-      int printsize;
       if (i <= borders[idx].low) {
+        int printsize;
         if (borders[idx].low > lastpos)
           printsize = lastpos - i;
         else
@@ -1711,7 +1960,7 @@ void LatexInfo::removeHead(KeyInfo &actual, int count)
   }
   else {
     // Remove header hull, that is "\url{abcd}" ==> "abcd"
-    interval.addIntervall(actual._tokenstart, actual._dataStart);
+    interval.addIntervall(actual._tokenstart - count, actual._dataStart);
     interval.addIntervall(actual._dataEnd, actual._dataEnd+1);
   }
 }
@@ -1721,17 +1970,55 @@ int LatexInfo::dispatch(ostringstream &os, int previousStart, KeyInfo &actual)
   int nextKeyIdx = 0;
   switch (actual.keytype)
   {
+    case KeyInfo::cleanToStart: {
+      actual._dataEnd = actual._dataStart;
+      nextKeyIdx = getNextKey();
+      // Search for end of arguments
+      int tmpIdx = find(nextKeyIdx, KeyInfo::endArguments);
+      if (tmpIdx > 0) {
+        for (int i = nextKeyIdx; i <= tmpIdx; i++) {
+          entries[i].disabled = true;
+        }
+        actual._dataEnd = entries[tmpIdx]._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;
+      break;
+    }
+    case KeyInfo::noContent: {          /* char like "\hspace{2cm}" */
+      if (actual.disabled)
+        interval.addIntervall(actual._tokenstart, actual._dataEnd);
+      else
+        interval.addIntervall(actual._dataStart, actual._dataEnd);
+    }
+      // fall through
     case KeyInfo::isChar: {
       nextKeyIdx = getNextKey();
       break;
     }
     case KeyInfo::isSize: {
-      if (actual.disabled) {
-        // Allways disabled
+      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);
         nextKeyIdx = getNextKey();
       } else {
+        // Here _dataStart points to '{', so correct it
+        actual._dataStart += 1;
+        actual._tokensize += 1;
+        actual.parenthesiscount = 1;
+        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);
+        }
+        else {
+          // Determine the end if used like '\tiny{...}'
+          actual._dataEnd = interval.findclosing(actual._dataStart, interval.par.length()) + 1;
+        }
         // Split on this key if not at start
         int start = interval.nextNotIgnored(previousStart);
         if (start < actual._tokenstart) {
@@ -1743,13 +2030,22 @@ int LatexInfo::dispatch(ostringstream &os, int previousStart, KeyInfo &actual)
       }
       break;
     }
+    case KeyInfo::endArguments:
+      // Remove trailing '{}' too
+      actual._dataStart += 2;
+      actual._dataEnd += 2;
+      interval.addIntervall(actual._tokenstart, actual._dataEnd);
+      nextKeyIdx = getNextKey();
+      break;
+    case KeyInfo::noMain:
+      // fall through
     case KeyInfo::isStandard: {
       if (actual.disabled) {
         removeHead(actual);
         processRegion(actual._dataStart, actual._dataStart+1);
         nextKeyIdx = getNextKey();
       } else {
-        // Split on this key if not at start
+        // Split on this key if not at datastart of calling entry
         int start = interval.nextNotIgnored(previousStart);
         if (start < actual._tokenstart) {
           interval.output(os, actual._tokenstart);
@@ -1760,9 +2056,27 @@ int LatexInfo::dispatch(ostringstream &os, int previousStart, KeyInfo &actual)
       }
       break;
     }
-    case KeyInfo::doRemove: {
-      // Remove the key with all parameters
+    case KeyInfo::removeWithArg: {
+      nextKeyIdx = getNextKey();
+      // Search for end of arguments
+      int tmpIdx = find(nextKeyIdx, KeyInfo::endArguments);
+      if (tmpIdx > 0) {
+        for (int i = nextKeyIdx; i <= tmpIdx; i++) {
+          entries[i].disabled = true;
+        }
+        actual._dataEnd = entries[tmpIdx]._dataEnd;
+      }
       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] != '%'))
+          break;
+      }
+      interval.addIntervall(actual._tokenstart, pos);
       nextKeyIdx = getNextKey();
       break;
     }
@@ -1773,27 +2087,66 @@ int LatexInfo::dispatch(ostringstream &os, int previousStart, KeyInfo &actual)
         if (interval.par[actual._tokenstart-count-1] != ' ')
           break;
       }
+      nextKeyIdx = getNextKey();
+      int tmpIdx = find(nextKeyIdx, KeyInfo::endArguments);
+      if (tmpIdx > 0) {
+        // Special case: \item is not a list, but a command (like in Style Author_Biography in maa-monthly.layout)
+        // with arguments
+        // How else can we catch this one?
+        for (int i = nextKeyIdx; i <= tmpIdx; i++) {
+          entries[i].disabled = true;
+        }
+        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;
+        }
+      }
       if (actual.disabled) {
         interval.addIntervall(actual._tokenstart-count, actual._dataEnd+1);
       }
       else {
         interval.addIntervall(actual._tokenstart-count, actual._tokenstart);
       }
-      // Discard extra parentheses '[]'
       if (interval.par[actual._dataEnd+1] == '[') {
         int posdown = interval.findclosing(actual._dataEnd+2, interval.par.length(), '[', ']');
-        interval.addIntervall(actual._dataEnd+1, actual._dataEnd+2);
-        interval.addIntervall(posdown, posdown+1);
+        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);
+        }
+        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] != ' ')
+              break;
+          }
+          if (count > 0)
+            interval.addIntervall(blk, blk+count);
+        }
       }
-      nextKeyIdx = getNextKey();
       break;
     }
     case KeyInfo::isSectioning: {
-      // Discard space before _tokenstart
+      // Discard spaces before _tokenstart
       int count;
-      for (count = 0; count < actual._tokenstart; count++) {
-        if (interval.par[actual._tokenstart-count-1] != ' ')
+      int val = actual._tokenstart;
+      for (count = 0; count < actual._tokenstart;) {
+        val = interval.previousNotIgnored(val-1);
+        if (interval.par[val] != ' ')
           break;
+        else {
+          count = actual._tokenstart - val;
+        }
       }
       if (actual.disabled) {
         removeHead(actual, count);
@@ -1821,6 +2174,8 @@ 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 (actual.disabled) {
         removeHead(actual);
         if ((interval.par.substr(actual._dataStart, 3) == " \\[") ||
@@ -1828,7 +2183,8 @@ int LatexInfo::dispatch(ostringstream &os, int previousStart, KeyInfo &actual)
           // Discard also the space before math-equation
           interval.addIntervall(actual._dataStart, actual._dataStart+1);
         }
-        interval.resetOpenedP(actual._dataStart-1);
+        nextKeyIdx = getNextKey();
+        // interval.resetOpenedP(actual._dataStart-1);
       }
       else {
         if (actual._tokenstart == 0) {
@@ -1848,7 +2204,7 @@ int LatexInfo::dispatch(ostringstream &os, int previousStart, KeyInfo &actual)
       break;
     }
   }
-  return(nextKeyIdx);
+  return nextKeyIdx;
 }
 
 int LatexInfo::process(ostringstream &os, KeyInfo &actual )
@@ -1868,7 +2224,7 @@ int LatexInfo::process(ostringstream &os, KeyInfo &actual )
     }
     KeyInfo &nextKey = getKeyInfo(nextKeyIdx);
 
-    if (nextKey.keytype == KeyInfo::isMain) {
+    if ((nextKey.keytype == KeyInfo::isMain) && !nextKey.disabled) {
       (void) dispatch(os, actual._dataStart, nextKey);
       end = nextKey._tokenstart;
       break;
@@ -1894,15 +2250,28 @@ int LatexInfo::process(ostringstream &os, KeyInfo &actual )
     output_end = interval.nextNotIgnored(actual._dataEnd);
   else
     output_end = interval.nextNotIgnored(end);
-  if (interval.nextNotIgnored(actual._dataStart) < output_end)
+  if ((actual.keytype == KeyInfo::isMain) && actual.disabled) {
+    interval.addIntervall(actual._tokenstart, actual._tokenstart+actual._tokensize);
+  }
+  // Remove possible empty data
+  int dstart = interval.nextNotIgnored(actual._dataStart);
+  while ((dstart < output_end) && (interval.par[dstart] == '{')) {
+    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);
   return nextKeyIdx;
 }
 
-string splitOnKnownMacros(string par, bool isPatternString) {
+string splitOnKnownMacros(string par, bool isPatternString)
+{
   ostringstream os;
   LatexInfo li(par, isPatternString);
+  // LYXERR0("Berfore split: " << par);
   KeyInfo DummyKey = KeyInfo(KeyInfo::KeyType::isMain, 2, true);
   DummyKey.head = "";
   DummyKey._tokensize = 0;
@@ -1920,6 +2289,10 @@ string splitOnKnownMacros(string par, bool isPatternString) {
       firstKey = DummyKey;
       (void) li.setNextKey(firstkeyIdx);
     }
+    else {
+      if (par.substr(firstKey._dataStart, 2) == "% ")
+        li.addIntervall(firstKey._dataStart, firstKey._dataStart+2);
+    }
     nextkeyIdx = li.process(os, firstKey);
     while (nextkeyIdx >= 0) {
       // Check for a possible gap between the last
@@ -1954,12 +2327,22 @@ string splitOnKnownMacros(string par, bool isPatternString) {
     // Handle the remaining
     firstKey._dataStart = li.nextNotIgnored(firstKey._dataStart);
     firstKey._dataEnd = par.length();
-    if (firstKey._dataStart < firstKey._dataEnd)
+    // Check if ! empty
+    if ((firstKey._dataStart < firstKey._dataEnd) &&
+        (par[firstKey._dataStart] != '}')) {
+      if (firstKey._tokensize > 0)
+        li.setForDefaultLang(firstKey._tokensize);
       (void) li.process(os, firstKey);
+    }
     s = os.str();
+    if (s.empty()) {
+      // return string definitelly impossible to match
+      s = "\\foreignlanguage{ignore}{ }";
+    }
   }
   else
     s = par;                            /* no known macros found */
+  // LYXERR0("After split: " << s);
   return s;
 }
 
@@ -1979,12 +2362,16 @@ static string correctlanguagesetting(string par, bool isPatternString, bool with
        while ((parlen > 0) && (par[parlen-1] == '\n')) {
                parlen--;
        }
+       if (isPatternString && (parlen > 0) && (par[parlen-1] == '~')) {
+               // Happens to be there in case of description or labeling environment
+               parlen--;
+       }
        string result;
        if (withformat) {
                // Split the latex input into pieces which
                // can be digested by our search engine
                LYXERR(Debug::FIND, "input: \"" << par << "\"");
-               result = splitOnKnownMacros(par, isPatternString);
+               result = splitOnKnownMacros(par.substr(0,parlen), isPatternString);
                LYXERR(Debug::FIND, "After split: \"" << result << "\"");
        }
        else
@@ -2140,7 +2527,7 @@ MatchStringAdv::MatchStringAdv(lyx::Buffer & buf, FindAndReplaceOptions const &
                                while (regex_replace(par_as_string, par_as_string, orig, dest));
                        }
                        regexp_str = "(" + lead_as_regexp + ")" + par_as_string;
-                       regexp2_str = "(" + lead_as_regexp + ").*" + par_as_string;
+                       regexp2_str = "(" + lead_as_regexp + ").*?" + par_as_string;
                }
                LYXERR(Debug::FIND, "Setting regexp to : '" << regexp_str << "'");
                regexp = lyx::regex(regexp_str);
@@ -2151,6 +2538,58 @@ MatchStringAdv::MatchStringAdv(lyx::Buffer & buf, FindAndReplaceOptions const &
 }
 
 
+// Count number of characters in string
+// {]} ==> 1
+// \&  ==> 1
+// --- ==> 1
+// \\[a-zA-Z]+ ==> 1
+static int computeSize(string s, int len)
+{
+       if (len == 0)
+               return 0;
+       int skip = 1;
+       int count = 0;
+       for (int i = 0; i < len; i += skip, count++) {
+               if (s[i] == '\\') {
+                       skip = 2;
+                       if (isalpha(s[i+1])) {
+                               for (int j = 2;  i+j < len; j++) {
+                                       if (! isalpha(s[i+j])) {
+                                               if (s[i+j] == ' ')
+                                                       skip++;
+                                               else if ((s[i+j] == '{') && s[i+j+1] == '}')
+                                                       skip += 2;
+                                               else if ((s[i+j] == '{') && (i + j + 1 >= len))
+                                                       skip++;
+                                               break;
+                                       }
+                                       skip++;
+                               }
+                       }
+               }
+               else if (s[i] == '{') {
+                       if (s[i+1] == '}')
+                               skip = 2;
+                       else
+                               skip = 3;
+               }
+               else if (s[i] == '-') {
+                       if (s[i+1] == '-') {
+                               if (s[i+2] == '-')
+                                       skip = 3;
+                               else
+                                       skip = 2;
+                       }
+                       else
+                               skip = 1;
+               }
+               else {
+                       skip = 1;
+               }
+       }
+       return count;
+}
+
 int MatchStringAdv::findAux(DocIterator const & cur, int len, bool at_begin) const
 {
        if (at_begin &&
@@ -2214,11 +2653,19 @@ int MatchStringAdv::findAux(DocIterator const & cur, int len, bool at_begin) con
                else
                        result =  m[m.size() - close_wildcards].first - m[0].first;
 
+               size_t pos = m.position(size_t(0));
+               // Ignore last closing characters
+               while (result > 0) {
+                       if (str[pos+result-1] == '}')
+                               --result;
+                       else
+                               break;
+               }
                if (result > leadingsize)
                        result -= leadingsize;
                else
                        result = 0;
-               return(result);
+               return computeSize(str.substr(pos+leadingsize,result), result);
        }
 
        // else !use_regexp: but all code paths above return
@@ -2251,19 +2698,28 @@ int MatchStringAdv::operator()(DocIterator const & cur, int len, bool at_begin)
               << ", inTexted=" << cur.inTexted());
        if (res == 0 || !at_begin || !opt.matchword || !cur.inTexted())
                return res;
+        if ((len > 0) && (res < len))
+          return 0;
        Paragraph const & par = cur.paragraph();
        bool ws_left = (cur.pos() > 0)
                ? par.isWordSeparator(cur.pos() - 1)
                : true;
-       bool ws_right = (cur.pos() + res < par.size())
-               ? par.isWordSeparator(cur.pos() + res)
+       bool ws_right = (cur.pos() + len < par.size())
+               ? par.isWordSeparator(cur.pos() + len)
                : true;
        LYXERR(Debug::FIND,
               "cur.pos()=" << cur.pos() << ", res=" << res
               << ", separ: " << ws_left << ", " << ws_right
+               << ", len: " << len
               << endl);
-       if (ws_left && ws_right)
-               return res;
+       if (ws_left && ws_right) {
+          // Check for word separators inside the found 'word'
+          for (int i = 0; i < len; i++) {
+            if (par.isWordSeparator(cur.pos() + i))
+              return 0;
+          }
+          return res;
+        }
        return 0;
 }
 
@@ -2282,9 +2738,26 @@ string MatchStringAdv::normalize(docstring const & s, bool hack_braces) const
        while (!t.empty() && t[t.size() - 1] == '\n')
                t = t.substr(0, t.size() - 1);
        size_t pos;
-       // Replace all other \n with spaces
-       while ((pos = t.find("\n")) != string::npos)
-               t.replace(pos, 1, " ");
+       // Handle all other '\n'
+       while ((pos = t.find("\n")) != string::npos) {
+               if (pos > 1 && t[pos-1] == '\\' && t[pos-2] == '\\' ) {
+                       // Handle '\\\n'
+                       if (std::isalnum(t[pos+1])) {
+                               t.replace(pos-2, 3, " ");
+                       }
+                       else {
+                               t.replace(pos-2, 3, "");
+                       }
+               }
+               else if (!std::isalnum(t[pos+1]) || !std::isalnum(t[pos-1])) {
+                       // '\n' adjacent to non-alpha-numerics, discard
+                       t.replace(pos, 1, "");
+               }
+               else {
+                       // Replace all other \n with spaces
+                       t.replace(pos, 1, " ");
+               }
+       }
        // Remove stale empty \emph{}, \textbf{} and similar blocks from latexify
        // Kornel: Added textsl, textsf, textit, texttt and noun
        // + allow to seach for colored text too
@@ -2441,50 +2914,89 @@ int findAdvFinalize(DocIterator & cur, MatchStringAdv const & match)
                cur.forwardPos();
        } while (cur && cur.depth() > d && match(cur) > 0);
        cur = old_cur;
-       if (match(cur) <= 0) return 0;
+       int max_match = match(cur);     /* match valid only if not searching whole words */
+       if (max_match <= 0) return 0;
        LYXERR(Debug::FIND, "Ok");
 
        // Compute the match length
-       int len = 1;
+        int len = 1;
        if (cur.pos() + len > cur.lastpos())
-               return 0;
-       LYXERR(Debug::FIND, "verifying unmatch with len = " << len);
-       while (cur.pos() + len <= cur.lastpos() && match(cur, len) <= 0) {
-               ++len;
-               LYXERR(Debug::FIND, "verifying unmatch with len = " << len);
-       }
-       // Length of matched text (different from len param)
-       int old_len = match(cur, len);
-       if (old_len < 0) old_len = 0;
-       int new_len;
-       // Greedy behaviour while matching regexps
-       bool examining = true;
-       int lastvalidlen = len;
-       while (examining) {
-               examining = false;
-               // Kornel: The loop is needed, since it looks like
-               // incrementing 'cur.pos()' does not always lead to the following
-               // char which we could then match.
-               for (int count = 1; count < 5; ++count) {
-                       if (cur.pos() + len + count > cur.lastpos()) {
-                               break;
-                       }
-                       new_len = match(cur, len + count);
-                       if (new_len > old_len) {
-                               len += count;
-                               old_len = new_len;
-                               examining = true;
-                               break;
-                       }
-                       else if (new_len == old_len)
-                               lastvalidlen = len+count;
-               }
-       }
-       if (lastvalidlen == len + 1) {
-               // Kornel:  Don't know, why this is important
-               // All I can see, is that sometimes the last char
-               // is outside of a match although it should be inside
-               len++;
+         return 0;
+       if (match.opt.matchword) {
+          LYXERR(Debug::FIND, "verifying unmatch with len = " << len);
+          while (cur.pos() + len <= cur.lastpos() && match(cur, 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);
+          if (old_match < 0)
+            old_match = 0;
+          int new_match;
+          // Greedy behaviour while matching regexps
+          while ((new_match = match(cur, len + 1)) > old_match) {
+            ++len;
+            old_match = new_match;
+            LYXERR(Debug::FIND, "verifying   match with len = " << len);
+          }
+          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);
+           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);
+           }
+         }
+          old_cur = cur;
+          // Search for real start of matched characters
+          while (len > 1) {
+            int actual_match;
+            do {
+              cur.forwardPos();
+            } while (cur.depth() > old_cur.depth()); /* Skip inner insets */
+            if (cur.depth() < old_cur.depth()) {
+              // Outer inset?
+              LYXERR0("cur.depth() < old_cur.depth(), this should never happen");
+              break;
+            }
+            if (cur.pos() != old_cur.pos()) {
+              // OK, forwarded 1 pos in actual inset
+              actual_match = match(cur, len-1);
+              if (actual_match == max_match) {
+                // Ha, got it! The shorter selection has the same match length
+                len--;
+                old_cur = cur;
+              }
+              else {
+                // OK, the shorter selection matches less chars, revert to previous value
+                cur = old_cur;
+                break;
+              }
+            }
+            else {
+              LYXERR0("cur.pos() == old_cur.pos(), this should never happen");
+              actual_match = match(cur, len);
+              if (actual_match == max_match)
+                old_cur = cur;
+            }
+          }
        }
        return len;
 }
@@ -2503,6 +3015,9 @@ int findForwardAdv(DocIterator & cur, MatchStringAdv & match)
                        int match_len_zero_count = 0;
                        for (; !theApp()->longOperationCancelled() && cur; cur.forwardPos()) {
                                LYXERR(Debug::FIND, "Advancing cur: " << cur);
+                               int match_len3 = match(cur, 1);
+                               if (match_len3 < 0)
+                                       continue;
                                int match_len2 = match(cur);
                                LYXERR(Debug::FIND, "match_len2: " << match_len2);
                                if (match_len2 > 0) {