]> git.lyx.org Git - lyx.git/blobdiff - src/lyxfind.cpp
Beamer: autonest column in columns
[lyx.git] / src / lyxfind.cpp
index f7df243408ea903556087b97be5e68ca9295dc9b..6d5abe78814df15e9586c5c1c24dc96c504e8b52 100644 (file)
@@ -951,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|md|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]+\\}", "")
@@ -973,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|md|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;
@@ -1010,27 +1010,52 @@ 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,
+    /* item */
     isList,
-    isIgnored                           /* to be ignored by creating infos */
+    /* tex, latex, ... like isChar */
+    isIgnored
   };
  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) {};
@@ -1056,7 +1081,10 @@ class Border {
 class Intervall {
   bool isPatternString;
  public:
- Intervall(bool isPattern) : isPatternString(isPattern), ignoreidx(-1), actualdeptindex(0) { depts[0] = 0;};
+ explicit Intervall(bool isPattern) :
+  isPatternString(isPattern),
+    ignoreidx(-1),
+    actualdeptindex(0) { depts[0] = 0; closes[0] = 0;};
   string par;
   int ignoreidx;
   int depts[MAXOPENED];
@@ -1238,7 +1266,7 @@ class LatexInfo {
   void removeHead(KeyInfo&, int count=0);
 
  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>();
@@ -1326,16 +1354,6 @@ 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(); };
   size_t getEndPos() {
     if (entries.empty() || (actualIdx >= entries.size())) {
@@ -1371,6 +1389,9 @@ void LatexInfo::buildEntries(bool isPatternString)
   bool evaluatingRegexp = false;
   MathInfo mi;
   bool evaluatingMath = false;
+  bool evaluatingCode = false;
+  size_t codeEnd = 0;
+  int codeStart = -1;
   KeyInfo found;
   bool math_end_waiting = false;
   size_t math_pos = 10000;
@@ -1442,8 +1463,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) {
@@ -1558,7 +1587,8 @@ void LatexInfo::buildEntries(bool isPatternString)
       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 == '=') {
@@ -1581,6 +1611,29 @@ void LatexInfo::buildEntries(bool isPatternString)
         found._tokensize = found.head.length();
         found._dataStart = found._tokenstart + found.head.length();
         size_t endpos = interval.findclosing(found._dataStart, interval.par.length());
+        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?
@@ -1590,9 +1643,9 @@ void LatexInfo::buildEntries(bool isPatternString)
         }
         else
           found._dataEnd = endpos;
-        if (isPatternString) {
-          keys[key].used = true;
-        }
+      }
+      if (isPatternString) {
+        keys[key].used = true;
       }
     }
     entries.push_back(found);
@@ -1621,7 +1674,7 @@ 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, ignoreFormats.getFamily()), isPatternString);
   makeKey("textbf",               KeyInfo(KeyInfo::isStandard, 1, ignoreFormats.getSeries()), isPatternString);
@@ -1647,22 +1700,40 @@ void LatexInfo::buildKeys(bool isPatternString)
 
   // Know charaters
   // No split
-  makeKey("backslash|textbackslash|textasciicircum|textasciitilde|ldots", 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",                 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|textvisiblespace|lyx", KeyInfo(KeyInfo::isChar, 0, false), isPatternString);
-  makeKey("textquotedbl|lyxarrow", KeyInfo(KeyInfo::isChar, 0, false), isPatternString);
-
+  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", KeyInfo(KeyInfo::doRemove, 1, false), 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|index|textmd|textrm", 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|footnote", 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);
+  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
@@ -1671,19 +1742,19 @@ void LatexInfo::buildKeys(bool isPatternString)
   makeKey("triangleuppar|triangledownpar|droppar", KeyInfo(KeyInfo::isStandard, 1, true), isPatternString);
   makeKey("triangleleftpar|shapepar|dropuppar",    KeyInfo(KeyInfo::isStandard, 1, true), isPatternString);
   // like ('tiny{}' or '\tiny ' ... )
-  makeKey("footnotesize|tiny|scriptsize|small|large|Large|LARGE|huge|Huge", KeyInfo(KeyInfo::isSize, 0, true), isPatternString);
+  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("lyx|latex|latexe|tex", KeyInfo(KeyInfo::isIgnored, 0, false), isPatternString);
   makeKey("item", 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", KeyInfo(KeyInfo::isStandard, 0, true), isPatternString);
   // Remove RTL/LTR marker
-  makeKey("l|r|textlr|textfr|textar|beginl|endl", KeyInfo(KeyInfo::doRemove, 0, true), isPatternString);
+  makeKey("l|r|textlr|textfr|textar|beginl|endl", KeyInfo(KeyInfo::isStandard, 0, true), isPatternString);
 
   if (isPatternString) {
     // Allow the first searched string to rebuild the keys too
@@ -1756,8 +1827,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
@@ -1820,17 +1891,33 @@ int LatexInfo::dispatch(ostringstream &os, int previousStart, KeyInfo &actual)
   int nextKeyIdx = 0;
   switch (actual.keytype)
   {
+    case KeyInfo::noContent: {          /* char like "\hspace{2cm}" */
+      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) {
@@ -1842,6 +1929,8 @@ int LatexInfo::dispatch(ostringstream &os, int previousStart, KeyInfo &actual)
       }
       break;
     }
+    case KeyInfo::noMain:
+      // fall through
     case KeyInfo::isStandard: {
       if (actual.disabled) {
         removeHead(actual);
@@ -2021,7 +2110,15 @@ int LatexInfo::process(ostringstream &os, KeyInfo &actual )
   if ((actual.keytype == KeyInfo::isMain) && actual.disabled) {
     interval.addIntervall(actual._tokenstart, actual._tokenstart+actual._tokensize);
   }
-  if (interval.nextNotIgnored(actual._dataStart) < output_end)
+  // 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;
@@ -2406,7 +2503,7 @@ 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(0);
+               size_t pos = m.position(size_t(0));
                // Ignore last closing characters
                while (result > 0) {
                        if (str[pos+result-1] == '}')
@@ -2656,9 +2753,9 @@ int findAdvFinalize(DocIterator & cur, MatchStringAdv const & match)
 
        // Compute the match length
         int len = 1;
+       if (cur.pos() + len > cur.lastpos())
+         return 0;
        if (match.opt.matchword) {
-          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;
@@ -2679,26 +2776,28 @@ int findAdvFinalize(DocIterator & cur, MatchStringAdv const & match)
             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) {
-              maxl = len;
-              len = (int)((maxl + minl)/2);
-            }
-            else if (actual_match < max_match) {
-              minl = len + 1;
-              len = (int)((maxl + minl)/2);
-            }
-            else {
-              // cannot happen, but in case of
-              LYXERR0("????");
-              max_match = actual_match;
-            }
-          }
-        }
+         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);
+           }
+         }
+       }
        return len;
 }