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;
/* twocolumns, ...
* like remove, but also all arguments */
removeWithArg,
- /* item */
+ /* item, listitem */
isList,
/* tex, latex, ... like isChar */
isIgnored,
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);
};
-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];
depth++;
}
else if (c == down) {
- if (depth == 0) return i;
+ if (depth == 0) {
+ if ((repeat <= 0) || (par[i+1] != up))
+ return i;
+ }
--depth;
}
}
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));
// 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
+ else {
discardComment = false;
- found = keys[key];
+ 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;
else if (c != ' ')
break;
}
- found.keytype = KeyInfo::doRemove;
found._tokenstart = pos - count;
if (sub.str(1).compare(0, 5, "begin") == 0) {
size_t pos1 = pos + sub.str(0).length();
found.head = interval.par.substr(found._tokenstart, found._tokensize);
}
else {
- if (interval.par[pos1] == '[') {
+ while (interval.par[pos1] == '[') {
pos1 = interval.findclosing(pos1+1, interval.par.length(), '[', ']')+1;
}
if (interval.par[pos1] == '{') {
found.disabled = true;
}
}
- if (interval.par[params] == '[') {
+ int optend = params;
+ while (interval.par[optend] == '[') {
// discard optional parameters
- int optend = interval.findclosing(params+1, interval.par.length(), '[', ']') + 1;
+ 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();
- size_t endpos = interval.findclosing(found._dataStart, interval.par.length());
+ 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;
// No split
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("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);
+ // 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("textquotedblleft|textquotedblright", KeyInfo(KeyInfo::isChar, 0, false), isPatternString);
// Known macros to remove (including their parameter)
// No split
- makeKey("inputencoding|shortcut|label|ref|index", 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);
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);
+ makeKey("code", KeyInfo(KeyInfo::noMain, 1, false), isPatternString);
// Same effect as previous, parameter will survive (because there is no one anyway)
// No split
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|latexe|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|nobreakdash", KeyInfo(KeyInfo::isStandard, 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
string Intervall::show(int lastpos)
{
int idx = 0; /* int intervalls */
- int count = 0;
string s;
int i = 0;
for (idx = 0; idx <= ignoreidx; idx++) {
break;
}
case KeyInfo::noContent: { /* char like "\hspace{2cm}" */
- interval.addIntervall(actual._dataStart, actual._dataEnd);
+ if (actual.disabled)
+ interval.addIntervall(actual._tokenstart, actual._dataEnd);
+ else
+ interval.addIntervall(actual._dataStart, actual._dataEnd);
}
// fall through
case KeyInfo::isChar: {
break;
}
case KeyInfo::endArguments:
- removeHead(actual);
- processRegion(actual._dataStart, actual._dataStart+1);
+ // Remove trailing '{}' too
+ actual._dataStart += 2;
+ actual._dataEnd += 2;
+ interval.addIntervall(actual._tokenstart, actual._dataEnd);
nextKeyIdx = getNextKey();
break;
case KeyInfo::noMain:
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);
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(), '[', ']');
if ((interval.par[actual._dataEnd+2] == '{') &&
interval.addIntervall(blk, blk+count);
}
}
- nextKeyIdx = getNextKey();
break;
}
case KeyInfo::isSectioning: {
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;
}
else
s = par; /* no known macros found */
+ // LYXERR0("After split: " << s);
return s;
}
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
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);
while (!t.empty() && t[t.size() - 1] == '\n')
t = t.substr(0, t.size() - 1);
size_t pos;
- // Replace all other \n with spaces
+ // Handle all other '\n'
while ((pos = t.find("\n")) != string::npos) {
- if (!std::isalnum(t[pos+1]) || !std::isalnum(t[pos-1]))
+ 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
+ }
+ 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
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;
}