else return "?";
}
-void
+bool
TPushParser::do_begin()
{
TNode parent = cursor.parent();
cursor.replace(g);
g.append(cursor);
}
+ return true;
}
bool
return ok;
}
-void
+bool
TPushParser::do_end()
{
TNode parent = cursor.parent();
// normal closing brace for an explicitly open group
cursor.remove();
advance(parent);
+ return true;
}
else if (parent && parent.isG() && parent.parent() && parent.parent().is("cell"))
{
assert(row && row.is("row"));
assert(row.parent());
advance(row);
+ return true;
}
else if (parent && parent.isG() && !parent.hasId() && parent.parent() && !parent.parent().is("math"))
{
{
// the '}' is not correct
logger.warning("nothing to close");
+ return false;
}
else
{
cursor.remove();
advance(parent);
+ return true;
}
-
}
else
{
- logger.error("closing brace ignored");
+ logger.warning("closing brace ignored");
+ return false;
}
}
else
{
- // at the moment, a phantom group with cursor can be a MACRO's child or a cell's child, and these cases
+ // at the moment, a phantom group with the cursor inside can be a MACRO's child or a cell's child, and these cases
// are handled in other blocks of code.
logger.error("do_end: strange TML tree");
+ return false;
}
}
else
// In this case, there is a redundant '}', so we can ignore it and
// emit an error
logger.warning("There is so no corresponding'{'");
+ return false;
//assert(0);
}
}
-
-/*
-void
-TPushParser::do_end()
-{
- TNode parent = cursor.parent();
- if (parent && parent.isG() && parent.hasId())
- {
- // normal closing brace for an explicitly open group
- cursor.remove();
- advance(parent);
- }
- else if (parent && parent.isG() && parent.parent() && parent.parent().is("cell"))
- {
- assert(!frames.empty());
- // closing brace for a structure in which & or \cr have been used
- TNode row = parent.parent().parent();
- assert(row && row.is("row"));
- TNode table = row.parent();
- assert(table);
- advance(row);
- }
- else if (parent && parent.isG() && !parent.hasId() && parent.parent() && !parent.parent().is("math"))
- {
- // closing brace for a right-open macro (like \over)
- // It's not sure that we want to exit from a phantom group with a
- // '}', because, to enter in the phantom group the user didn't insert a
- // '{'.
- cursor.remove();
- advance(parent);
- }
- else
- {
- // In this case, there is a redundant '}', so I think we can ignore it and
- // emit an error
- logger.warning("There is so no corresponding'{'");
- //assert(0);
- }
-}
-*/
-
-void
+bool
TPushParser::do_shift()
{
TNode parent = cursor.parent();
cursor.replace(math);
math.append(g);
g.append(cursor);
+ return true;
}
else if (parent.isG() && !parent.hasId() && parent.parent() && parent.parent().is("math"))
{
{
// one math shift is enough to close it
cursor.remove();
+ return true;
}
else
{
// we need two closing math shifts
//cursor.remove(); ??
parent.parent().append(cursor);
+ return true; // ???
}
}
else if (parent.parent()["display"] != "1")
// there is nothing before the cursor, and the math is not
// in display mode, so this must be a double math shift
parent.parent()["display"] = "1";
+ return true;
}
else
{
parent.parent().append(cursor);
+ return true;
}
}
else if (parent.is("math"))
{
cursor.remove();
+ return true;
}
else
{
- logger.error("parser: math shift");
+ logger.warning("parser: math shift");
+ return false;
}
}
-void
+bool
TPushParser::do_align()
{
TNode parent = cursor.parent();
row.append(cell);
cell.append(g);
g.append(parent.first(), cursor);
+ return true;
}
else if (parent && parent.isG() && parent.parent().is("cell"))
{
TNode g = doc.createG();
cell.append(g);
g.append(cursor);
+ return true;
}
else
{
- logger.error("alignment tab used outside matrix");
+ logger.warning("alignment tab used outside matrix");
+ return false;
}
}
-void
+bool
TPushParser::do_eol()
{
//if (cursor.parent()) cursor.remove();
+ logger.warning("token ignored");
+ return false;
}
-void
+bool
TPushParser::do_parameter(const std::string& p)
{
- // ???
+ logger.warning("token ignored");
+ return false;
}
-void
+bool
TPushParser::do_subscript()
{
TNode parent = cursor.parent();
cursor.replace(elem);
elem.append(g);
elem.append(cursor);
+ return true;
}
else
{
prev.replace(elem);
elem.append(prev);
elem.append(cursor);
+ return true;
}
}
else if (parent.isSb() && cursor == parent[1])
{
- if (parent["under"] == "1") logger.error("already under");
- else parent["under"] = "1";
+ if (parent["under"] == "1")
+ {
+ logger.warning("already under");
+ return false;
+ }
+ else
+ {
+ parent["under"] = "1";
+ return true;
+ }
+ }
+ else
+ {
+ logger.warning("token ignored");
+ return false;
}
}
-void
+bool
TPushParser::do_superscript()
{
TNode parent = cursor.parent();
cursor.replace(elem);
elem.append(g);
elem.append(cursor);
+ return true;
}
else
{
prev.replace(elem);
elem.append(prev);
elem.append(cursor);
+ return true;
}
}
else if (parent.isSp() && cursor == parent[1])
{
- if (parent["over"] == "1") logger.error("already over");
- else parent["over"] = "1";
+ if (parent["over"] == "1")
+ {
+ logger.warning("token ignored: already over");
+ return false;
+ }
+ else
+ {
+ parent["over"] = "1";
+ return true;
+ }
+ }
+ else
+ {
+ logger.warning("token ignored");
+ return false;
}
}
-void
+bool
TPushParser::do_space(const std::string&)
{
- logger.debug("do_space");
+ return false;
}
-void
+bool
TPushParser::do_letter(const std::string& s)
{
//TNode parent = cursor.parent();
TNode elem = doc.createI(s, nextId++);
cursor.replace(elem);
advance(elem);
+ return true;
}
-void
+bool
TPushParser::do_digit(const std::string& s)
{
- TNode parent = cursor.parent();
- TNode prev = cursor.prev();
- if (prev && parent.isG() && prev.is("n"))
- {
- TNode elem = doc.createN(prev.value() + s, nextId++);
- prev.replace(elem);
- }
- else
- {
- TNode elem = doc.createN(s, nextId++);
- cursor.replace(elem);
- advance(elem);
- }
+ TNode elem = doc.createN(s, nextId++);
+ cursor.replace(elem);
+ advance(elem);
+ return true;
}
bool
return node.isG() && node.last() && node.last().is("o") && node.last()["val"] == PRIME();
}
-void
+bool
TPushParser::do_apostrophe()
{
if (cursor.parent() && cursor.parent().isG())
if (TNode prev = cursor.prev())
{
if (prev.isSp() && prev[1] && isPrimes(prev[1]))
- prev[1].append(doc.createO(PRIME(), nextId++));
+ {
+ prev[1].append(doc.createO(PRIME(), nextId++));
+ return true;
+ }
else if (prev.isSb() && prev[0] &&
prev[0].isSp() && prev[0][1] &&
isPrimes(prev[0][1]))
- prev[0][1].append(doc.createO(PRIME(), nextId++));
+ {
+ prev[0][1].append(doc.createO(PRIME(), nextId++));
+ return true;
+ }
else
{
TNode elem = doc.create("sp");
elem.append(prev);
elem.append(g);
g.append(doc.createO(PRIME(), nextId++));
+ return true;
}
}
else
{
// is it an error?
- logger.error("parser: you have to type one identifier before the ''");
+ logger.warning("parser: you have to type an identifier before ''");
+ return false;
}
}
else
{
- // error ??
+ logger.warning("token ignored: you have to be in a group");
+ return false;
}
}
-void
+bool
TPushParser::do_other(const std::string& s)
{
switch (s[0])
{
case '\'':
- do_apostrophe();
+ return do_apostrophe();
break;
default:
/*cout << "TPushParser::do_other " << s << endl;
cout << "DOCUMENT: " << static_cast<GdomeNode*>(cursor.element().get_ownerDocument()) << endl;*/
TNode elem = doc.createT("o", s, nextId++);
cursor.replace(elem);
- advance(elem);
+ advance(elem);
+ return true;
break;
}
}
-void
+bool
TPushParser::do_active(const std::string&)
{
// ??? space?
+ logger.warning("token ignorde");
+ return false;
}
-void
+bool
TPushParser::do_comment()
{
// ???
+ return false;
}
-void
+bool
TPushParser::do_cr()
{
TNode parent = cursor.parent();
row.append(cell);
cell.append(g);
g.append(cursor);
+ return true;
+ }
+ else
+ {
+ // at the moment, \cr can only be used inside a table
+ logger.warning("token ignored: cr used outside a table");
+ return false;
}
}
-void
+bool
TPushParser::do_control(const std::string& name)
{
- if (name == "cr") do_cr();
+ if (name == "cr") return do_cr();
else
{
TNode parent = cursor.parent();
t["name"] = name;
cursor.replace(t);
advance(t);
+ return true;
}
break;
case TDictionary::OPERATOR:
t["name"] = name;
cursor.replace(t);
advance(t);
+ return true;
}
break;
case TDictionary::NUMBER:
t["name"] = name;
cursor.replace(t);
advance(t);
+ return true;
}
break;
case TDictionary::MACRO:
{
- TNode m = doc.createC(name, nextId++);
- cursor.replace(m);
-
- if (entry.leftOpen && entry.rightOpen)
- {
- assert(entry.pattern.empty());
- assert(parent.isG());
- TNode g1 = doc.createG();
- g1["left-open"] = "1";
- g1.append(parent.first(), m);
- m.append(g1);
- TNode g2 = doc.createG();
- g2.append(cursor);
- m.append(g2);
- frames.push(Frame(entry));
- }
- else if (entry.leftOpen)
+ if (parent.isG())
{
- assert(parent.isG());
- TNode g = doc.createG();
- g["left-open"] = "1";
- g.append(parent.first(), m);
- m.append(g);
- advance(m);
- }
- else if (entry.rightOpen)
- {
- assert(entry.pattern.empty());
- assert(parent.isG());
- TNode g = doc.createG();
- g.append(cursor);
- m.append(g);
- frames.push(Frame(entry));
- }
- else if (!entry.pattern.empty())
- {
- if (parent.isG())
- {
+ TNode m = doc.createC(name, nextId++);
+ cursor.replace(m);
+ if (entry.leftOpen && entry.rightOpen)
+ {
+ assert(entry.pattern.empty());
+ assert(parent.isG());
+ TNode g1 = doc.createG();
+ g1["left-open"] = "1";
+ g1.append(parent.first(), m);
+ m.append(g1);
+ TNode g2 = doc.createG();
+ g2.append(cursor);
+ m.append(g2);
+ frames.push(Frame(entry));
+ }
+ else if (entry.leftOpen)
+ {
+ assert(parent.isG());
+ TNode g = doc.createG();
+ g["left-open"] = "1";
+ g.append(parent.first(), m);
+ m.append(g);
+ advance(m);
+ }
+ else if (entry.rightOpen)
+ {
+ assert(entry.pattern.empty());
+ assert(parent.isG());
+ TNode g = doc.createG();
+ g.append(cursor);
+ m.append(g);
+ frames.push(Frame(entry));
+ }
+ else if (!entry.pattern.empty())
+ {
frames.push(Frame(entry));
-
if (entry.paramDelimited(0))
{
TNode g = doc.createG();
}
else
{
- // error, but we could handle this very easily
- logger.error(" parser:but we could handle this easily");
- }
+ // it's an empty macro
+ advance(m);
+ }
+ return true;
+ }
+ else if (!entry.pattern.size() && !entry.rightOpen && !entry.leftOpen)
+ {
+ // a macro with no arguments and no right open and no left open, can be child of anything
+ TNode m = doc.createC(name, nextId++);
+ cursor.replace(m);
+ advance(m);
+ return true;
+ }
+ else
+ {
+ // a macro with arguments or a rightOpen or leftOpen macro must be a group's child
+ logger.warning("token ignored: this macro should be in a group");
+ return false;
}
- else advance(m);
}
break;
case TDictionary::UNDEFINED:
{
- logger.error("parser: using undefined macro " + name);
+ logger.warning("parser: using undefined macro " + name);
TNode m = doc.createC(name, nextId++);
cursor.replace(m);
advance(m);
+ return true;
}
break;
default:
- assert(0);
+ {
+ //assert(0);
+ logger.warning("token ignored");
+ return false;
+ }
}
}
}
-void
-TPushParser::gdelete_prev_token()
+std::string
+TPushParser::drop_prev_token(bool special)
{
assert(cursor.prev());
assert(cursor.parent());
TNode prev = cursor.prev();
assert(prev.is("i") || prev.is("o") || prev.is("n"));
+
+ DOM::UCS4String ucs4val = prev.element().getAttribute("val");
+ bool macro = prev.element().hasAttribute("name");
+ std::string utf8name;
+ if (macro) utf8name = prev.element().getAttribute("name");
+
+ cursor.remove();
+ prev.replace(cursor);
- // the control below is designed to handle the case in which val have more than one unicode character
- DOM::UCS4String ucs4val(prev.element().getAttribute("val"));
- if ((prev.is("i")) || (ucs4val.length() <= 1) || prev.element().hasAttribute("name"))
+ if (cursor.parent().isC())
{
- cursor.remove();
- prev.replace(cursor);
-
- if (cursor.parent().isC())
- {
- // in this case we have removed an element of a MACRO.
- // we can assert that this element was a non delimited argument
- assert(!frames.empty());
- Frame& frame = frames.top();
- assert(frame.pos > 0);
-
- frame.pos--;
- }
+ // in this case we have removed an element of a MACRO.
+ // we can assert that this element was a non delimited argument
+ assert(!frames.empty());
+ Frame& frame = frames.top();
+ assert(frame.pos > 0);
+ frame.pos--;
}
- else
+
+ if ((ucs4val.length() > 1) && !special)
{
- ucs4val.erase(ucs4val.length() - 1, 1);
- prev.element().setAttribute(DOM::GdomeString("val"), DOM::GdomeString(ucs4val));
+ if (!macro)
+ {
+ // in this case we can return the content of ucs4val, but we have
+ // to convert it in a utf8
+ DOM::GdomeString gdsval(ucs4val);
+ std::string utf8val(gdsval);
+ utf8val = utf8val.erase(utf8val.length() - 1, 1);
+ return std::string(utf8val);
+ }
+ else
+ {
+ // in this case, the content of val could be in unicode,
+ // but we have attribute name, which doesn't contain character not representable
+ // with a byte.
+ return "\\" + utf8name.erase(utf8name.length() - 1, 1);
+ }
}
-
+ else if ((ucs4val.length() <= 1) && macro && special) return "\\" + utf8name.erase(utf8name.length() - 1, 1);
+ else return "";
}
-void
-TPushParser::gdelete_prev_script()
+std::string
+TPushParser::drop_prev_script(bool special)
{
// this method deletes an sp or an sb preceding the cursor
assert(cursor.prev());
assert(prev.is("sp") || prev.is("sb"));
cursor.remove();
prev.append(cursor);
- // we can invoke the gdelete_prev, because a sp (sb) MUST have two children
- gdelete_prev();
+ // we can invoke the drop_prev, because a sp (sb) MUST have two children
+ // but we cannot invoke do_drop_script because it assumes when called, the first
+ // child has been removed yet.
+ if (cursor.prev().isG() && !prev.hasId())
+ {
+ // in this case, the user has inserted the a sequence of '.
+ // Hence, we force a normal deleting, because the behaviour must be the same
+ // for the two kind of deleting
+ return drop_prev(false);
+ }
+ else return drop_prev(special);
}
-void
-TPushParser::gdelete_prev_group()
+std::string
+TPushParser::drop_prev_group(bool special)
{
assert(cursor.prev() && cursor.prev().isG());
+ TNode parent = cursor.parent();
TNode prev = cursor.prev();
cursor.remove();
prev.append(cursor);
-
- // a group could have no children, so the gdelete_prev is not appropriate
- // so, this method is not equivalent to the one above
- do_gdelete();
+
+ if (parent.isC() && prev.hasId())
+ {
+ assert(!frames.empty());
+ frames.top().pos--;
+ }
+
+ if (special) return "";
+ else
+ {
+ // a group could have no children, so the drop_prev is not appropriate
+ // so, this method is not equivalent to the one above
+ return do_drop(special);
+ }
}
-void
-TPushParser::gdelete_prev_macro()
+std::string
+TPushParser::drop_prev_macro(bool special)
{
assert(cursor.parent());
assert(cursor.prev());
TNode prev = cursor.prev();
assert(prev.isC());
+
+ std::string macro_name = prev.nameC();
+
+ TNode parent = cursor.parent();
const TDictionary::Entry& entry = dictionary.find(prev["name"]);
if (!entry.defined())
{
- // We can assume that the user want to completely delete the undefined macro
+ // We can assume that the user wants to completely delete the undefined macro,
+ // but we can also handle this case as we handle tokens. At the moment, we delete the
+ // whole macro
cursor.remove();
prev.replace(cursor);
+ if (cursor.parent().isC())
+ {
+ // we have removed a macro's child
+ assert(!frames.empty());
+ frames.top().pos--;
+ }
+ if (special) return "\\" + macro_name.erase(macro_name.length() - 1, 1);
+ return "";
}
else
{
cursor.remove();
prev.last().append(cursor);
-
- // the gdelete_prev is not appropriate, because the last child of the MACRO could have no children
- do_gdelete_phantom_group();
+
+ if (special) return "";
+ else
+ {
+ // the drop_prev is not appropriate, because the last child of the MACRO could have no children
+ return do_drop_phantom_group(special);
+ }
}
else if (entry.leftOpen)
{
// the leftOpen MACRO MUST have one and only one child, which MUST be a phantom group
// In this case, we do not have to push a frame in the stack, because we remove the
// MACRO immediately, substituting it with the content of the phantom group.
- // At the moment, we don't remove the last child of the phantom group, but
+ // We could remove the last child of the phantom group, but
// it's not clear if it's the correct behavior of the graphical deleting.
- // To delete it, just remove the comment of the last instruction of the
- // if (g.size()) block.
+ // At the moment, to give a standard behaviour, we remove the last element.
assert(prev.first());
assert(prev.first().isG());
assert(prev.first() == prev.last());
// TNode::replace.
g.remove();
prev.replace(g.first(), TNode());
- //gdelete_prev();
+ parent.append(cursor);
+ if (special) return "\\" + macro_name.erase(macro_name.length() - 1, 1);
+ else return do_drop(special);
}
else
{
cursor.remove();
g.remove();
prev.replace(cursor);
+ if (special) return "\\" + macro_name.erase(macro_name.length() - 1, 1);
+ else
+ {
+ // Once removed this empty macro, we could try to remove something else.
+ // This would be justified by the fact that, generally, an empty macro gives no visual information
+ // about it.
+ return do_drop(special); // special is false
+ }
}
}
else if (!entry.pattern.empty())
// frome the one in which it's a not delimited argument.
if (prev.last().isG() && !prev.last().hasId())
{
- // the last argument of the MACRO is a delimited argumet. We ideally remove
- // the sequence of delimiters
- cursor.remove();
- prev.last().append(cursor);
- // we have to push a frame with a correct value of pos
- assert(entry.previousParam(entry.pattern.size()) != entry.pattern.size());
-
- unsigned sequence_length = entry.pattern.size() - entry.previousParam(entry.pattern.size()) - 1;
- unsigned p = entry.pattern.size() - sequence_length - 1;
- // now, p is the correct value of pos, and we can push the frame.
- frames.push(Frame(entry, p));
+ if (special)
+ {
+ // in this case, we have to start removing the last delimiter
+ frames.push(Frame(entry, entry.pattern.size() - 2));
+
+ cursor.remove();
+ prev.last().append(cursor);
+
+ std::string last_del = entry.pattern[entry.pattern.size() - 1].value;
+
+ return "\\" + last_del.erase(last_del.length() - 1, 1);
+ }
+ else
+ {
+ // the last argument of the MACRO is a delimited argumet. We ideally remove
+ // the sequence of delimiters
+ cursor.remove();
+ prev.last().append(cursor);
+ // we have to push a frame with a correct value of pos
+ assert(entry.previousParam(entry.pattern.size()) != entry.pattern.size());
+
+ unsigned sequence_length = entry.pattern.size() - entry.previousParam(entry.pattern.size()) - 1;
+ unsigned p = entry.pattern.size() - sequence_length - 1;
+ // now, p is the correct value of pos, and we can push the frame.
+ frames.push(Frame(entry, p));
+
+ // To give a standard behaviour to the graphical deleting, we remove the last
+ // element of the macro. Since we are in a phantom group, we can invoke the
+ // do_drop_phantom_group(special).
+ return do_drop_phantom_group(special);
+ }
}
else
{
cursor.remove();
if (entry.table == 1 && prev.last().is("row"))
{
- // in this case the cursor should be appended to the group associated to
+ // in this case the cursor has to be appended to the group associated to
// the last cell of the last row of the table
assert(prev.last().last().is("cell") && prev.last().last().first().isG());
prev.last().last().first().append(cursor);
+
+ // we have to push a frame in the stack. Since tables has a pattern size = 1, we have to
+ // set pos at 0, because appending the cursor to the last cell means that this argument
+ // is not whole inserted.
+ // We don't call frames.push(Frame(entry)), because it incoditionaly set pos at 0. The
+ // following line is more general
+ frames.push(Frame(entry, entry.pattern.size() - 1));
+ if (special)
+ {
+ // to type a table with rows and cells, the user had typed a
+ // "{", and to exit from it, the user had inserted a "}".
+ // Since we are in a special deleting, we just idealy remove the "}"
+ return "";
+ }
+ else return do_drop_phantom_group(special);
}
else
{
+ // we push a frame in the stack with a correct value of member pos.
+ // This correct value is the size of the pattern - 1, because we have been started to delete
+ // a MACRO. It means that all of the MACRO's arguments have been inserted, but
+ frames.push(Frame(entry, entry.pattern.size()));
prev.append(cursor);
+ return drop_prev(special);
}
- // we push a frame in the stack with a correct value of member pos.
- // This correct value is the size of the pattern, because we have to START to delete
- // a MACRO. It means that all of the MACRO's arguments have been inserted.
- frames.push(Frame(entry, entry.pattern.size()));
-
- if (cursor.prev())
- {
- // in this case we try to remove the last child of the MACRO.
- gdelete_prev();
- }
- else
- {
- // this block of code will never be executed, because the MACRO accepts arguments,
- // so a MACRO's child MUST exist. But, we can handle this case, emitting a warning
- logger.warning("Parser: the TML tree is in a strange state, but a good state will be generated");
- do_gdelete();
- }
} // end of the else of the if (prev.last().isG() && !prev.last().hasId())
} // end of if (!entry.pattern.empty())
assert(prev.size() == 0);
cursor.remove();
prev.replace(cursor);
+ if (cursor.parent().isC())
+ {
+ // we have removed an empty macro, which was a non delimited argument of a macro.
+ // We have to decrement pos
+ assert(!frames.empty());
+ frames.top().pos--;
+ }
+
+ if (special) return "\\" + macro_name.erase(macro_name.length() - 1, 1);
+ else return "";
+
+ // now we could start to remove something else. This behaviour would be justified by the
+ // fact that, generally, an empty MACRO gives no visual information about it.
+ // To adopt this behaviour, just remove the comment to the following instruction
+ // return do_drop(special);
}
} // end of defined MACRO
}
-void
-TPushParser::gdelete_prev()
+std::string
+TPushParser::drop_prev(bool special)
{
// if in this function, the prev of cursor does exist, also the parent and we want a graphical deleting.
if (prev.is("i") || prev.is("o") || prev.is("n"))
{
- gdelete_prev_token();
+ return drop_prev_token(special);
}
else if (prev.isSp() || prev.isSb())
{
- gdelete_prev_script();
+ return drop_prev_script(special);
}
else if (prev.isG())
{
- gdelete_prev_group();
+ return drop_prev_group(special);
}
else if (prev.isC())
{
// here, we also treat the case in which the MACRO is a table
- gdelete_prev_macro();
+ return drop_prev_macro(special);
}
else
{
// not handled. Future cases...
+ return "";
}
} // end of method
void
-TPushParser::rgreplace_father(void)
+TPushParser::rgreplace_father()
{
// this method MUST only be invoked, when the cursor
// is the only child of a group with id. This function
parent.replace(cursor);
parent = cursor.parent();
}
-
- if (parent.isC())
- {
- // in this case we have removed a MACRO's child.
- // So, we have to update the member pos of the frame in the stack
- // We can assert that this MACRO accepts arguments.
- assert(!frames.empty());
- Frame& frame = frames.top();
- assert(frame.pos > 0);
- frame.pos--;
- }
}
-void
-TPushParser::do_gdelete_script()
+std::string
+TPushParser::do_drop_script(bool special)
{
// If we are here, the cursor is child of a script (sp or sb) and
// this means that a prev does exist and that there is one and only one
{
// in this case, the script's base is a group with no elements, so
// we have to remove the entire MACRO, replacing it with the cursor.
- // This situation occurs when the user type something like this
+ // This situation occurs when the user had typed something like this
// $....{}^
// or this
// $^
// or this
// $...{^
- prev.remove();
- parent.replace(cursor);
-
- // if the new parent is a group with Id and the cursor is the only
- // element of this group, we have to remove the group. These controls are made
- // in the method rgreplace_father().
- if (cursor.parent().isG() && cursor.parent().hasId()) rgreplace_father();
+ //
+ if (special && prev.hasId())
+ {
+ // in this case, the user has typed: ...{}^
+ // hence we idealy remove the ^
+ parent.replace(prev);
+ prev.parent().append(cursor);
+ return "";
+ }
+ else if (!prev.hasId())
+ {
+ // we idealy remove the ^, but the phantom group
+ // has to be removed, also
+ prev.remove();
+ parent.replace(cursor);
+ return "";
+ }
+ else
+ {
+ prev.remove();
+ parent.replace(cursor);
+
+ // since the script had no children, we can try to remove something else.
+ // Since we don't know who is cursor's parent, and who is cursor's preceding
+ // element, we invoke the do_drop()
+ return do_drop(special);
+
+ /*
+ * * the following istructions have sense, only if we remove the preceding one.
+ *
+ // if the new parent is a group with Id and the cursor is the only
+ // element of this group, we have to remove the group. These controls are made
+ // in the method rgreplace_father().
+ if (cursor.parent().isG() && cursor.parent().hasId()) rgreplace_father();
+ */
+ }
}
else
{
- // in this case, the prev has to replace the script,
- // and the cursor has to be placed after the prev.
- assert(prev.hasId());
+ // in this case, the prev has to replace the script.
parent.replace(prev);
prev.parent().append(cursor);
// now prev have a preceding element
assert(cursor.parent().size() > 1);
+
+ if (special) return "";
+ else
+ {
+ // to give a standard behaviour, we try to remove the element, which was
+ // the script's base.
+ return do_drop(special);
+ }
}
-} // end of method do_gdelete_script
+} // end of method do_drop_script
-void
-TPushParser::do_gdelete_macro()
+std::string
+TPushParser::do_drop_macro(bool special)
{
// If we are here, the cursor is a child of a MACRO and this means
// that there is an open frame for the control element
// we can assert that frame.entry.pattern.size() >= 1
assert(cursor.parent() && cursor.parent().isC());
TNode parent = cursor.parent();
+
+ // this string is useful iff we have a special deleting
+ std::string macro_name = parent.nameC();
assert(!frames.empty());
Frame& frame = frames.top();
{
// in this case, a prev does not exist, so the actions of deleting means
// that we have to remove the MACRO. So we have to pop the stack.
- // Being here also means that the MACRO is waiting for the first argument
- // (which is not delimited), but we don't mind about it.
assert(frame.pos == 0);
+
parent.replace(cursor);
frames.pop();
- // if the new parent is a group with Id, and has no elements other than the
- // cursor, we can remove it, because it' a graphical deleting
- if (cursor.parent() && cursor.parent().isG() && cursor.parent().hasId())
- rgreplace_father();
- else if (cursor.parent().isC())
+ if (special) return "\\" + macro_name.erase(macro_name.length() - 1, 1);
+ else
{
- // We have assumed that a MACRO cannot be a MACRO's child.
- // At the moment, this assumption is valid, but in a future
- // it might be false.
- assert(!frames.empty());
- Frame& frame = frames.top();
- assert(frame.pos > 0);
- frame.pos--;
+ // Since the macro hadn't no children and this is a graphical deleting, we try
+ // to remove something else
+ return do_drop(special);
+
+ /*
+ * the following block of code has sense only if we remove the preceding instruction
+ *
+ // if the new parent is a group with Id, and has no elements other than the
+ // cursor, we can remove it, because it' a graphical deleting
+ if (cursor.parent() && cursor.parent().isG() && cursor.parent().hasId())
+ rgreplace_father();
+ else if (cursor.parent().isC())
+ {
+ // We have assumed that a MACRO cannot be a MACRO's child.
+ // At the moment, this assumption is valid, but in a future
+ // it might be false.
+ assert(!frames.empty());
+ Frame& frame = frames.top();
+ assert(frame.pos > 0);
+ frame.pos--;
+ }
+ */
}
}
else
cursor.remove();
prev.append(cursor);
assert(frame.entry.previousParam(frame.pos) != frame.entry.pattern.size());
-
- // these 3 lines of code update the member pos.
- unsigned sequence_length = frame.pos - frame.entry.previousParam(frame.pos) - 1;
- assert(sequence_length);
- frame.pos = frame.pos - sequence_length - 1;
+
+ if (special)
+ {
+ // in this case we have to start removing the last delimimeter.
+ // It means that we return in a situation where the user has not entirely
+ // inserted the delimited argument. So, we have to decrement frame.pos of
+ // two units: the delimiter and the actual argument
+ std::string last_del = frame.entry.pattern[frame.pos - 1].value;
+ frame.pos = frame.pos - 2;
+ return "\\" + last_del.erase(last_del.length() - 1, 1);
+ }
+ else
+ {
+ // these 3 lines of code update the member pos.
+ unsigned sequence_length = frame.pos - frame.entry.previousParam(frame.pos) - 1;
+ assert(sequence_length);
+ frame.pos = frame.pos - sequence_length - 1;
+
+ // since it's a graphical deleting, we have to remove the current preceding element.
+ // We don't invoke the drop_prev(), because a do_drop_phantom_group is more general.
+ return do_drop_phantom_group(special);
+ }
}
else
{
// the prev is not a delimited argument, so we have to try to remove it.
- // We "try", because the prev might be a something that
+ // We "try", because the prev might be something that
// a simple delete cannot remove completely
- gdelete_prev();
+ return drop_prev(special);
}
}
}
-void
-TPushParser::do_gdelete_groupId()
+std::string
+TPushParser::do_drop_groupId(bool special)
{
// if we are here, the cursor's parent is a group with Id
assert(cursor.parent() && cursor.parent().isG() && cursor.parent().hasId());
if (prev)
{
// the cursor has a preceding element, so we try to remove it
- gdelete_prev();
-
- // We control if the group has to be removed, because the cursor
- // might be the only element of the group.
- if ((parent.first() == cursor) && parent.isG() && parent.hasId())
- rgreplace_father();
+ if (special) return drop_prev(special);
+ else
+ {
+ std::string str = drop_prev(special);
+
+ // We control if the group has to be removed, because the cursor
+ // might be the only element of the group.
+ // But we have to be careful, because drop_prev could change the TML tree
+ // more than we think...parent could no longer exist!
+ parent = cursor.parent();
+ if ((parent.first() == cursor) && parent.isG() && parent.hasId())
+ rgreplace_father();
+ return str;
+ }
}
else
{
// the cursor has no preceding elements, so we have to remove the
// group.
- rgreplace_father();
-
- // we have to re-start the process, because it' a graphical delete
- do_gdelete();
+ if (special)
+ {
+ parent.replace(cursor);
+ return "";
+ }
+ else
+ {
+ rgreplace_father();
+ // we have to re-start the process, because it' a graphical deleting
+ return do_drop(special);
+ }
}
-} // end of method do_gdelete_groupId()
+} // end of method do_drop_groupId()
-void
-TPushParser::do_gdelete_phantom_group()
+std::string
+TPushParser::do_drop_phantom_group(bool special)
{
// if we are here, the cursor MUST be a child of a
// phantom group.
TNode prev = cursor.prev();
if (prev)
{
+ if (parent.parent() && parent.parent().isC())
+ {
+ // there is a frame in the stack
+ assert(!frames.empty());
+ if (frames.top().entry.pattern.size())
+ {
+ Frame& frame = frames.top();
+ if (special)
+ {
+ // we are in a delimited argument. If the user has inserted a proper subset of the
+ // delimiters'sequence, we start to remove the previous delimiter. Start to remove
+ // a delimiter means that that delimiter must be removed from the count of inserted delimiters.
+ // It means that we have to decrement the member pos.
+ if (frame.entry.pattern[frame.pos].category != TToken::PARAMETER)
+ {
+ std::string del = frame.entry.pattern[frame.pos].value;
+ frame.pos--;
+ return "\\" + del.erase(del.length() - 1, 1);
+ }
+ }
+ else
+ {
+ // we are in a delimited argument. If the user has inserted a proper subset of the delimiters'sequence,
+ // we have to remove the portion the user has inserted.
+ while (frame.entry.pattern[frame.pos].category != TToken::PARAMETER) frame.pos--;
+ }
+ }
+ }
+
// the cursor has a preceding element, so we try to remove it
- gdelete_prev();
+ std::string str = drop_prev(special);
- if (parent.size() == 1 && parent.parent().isSp())
+ if (special) return str;
+ else
{
- // in this case the gdelete_prev has removed the only element preceding the cursor.
- // If the phantom group is an sp's child, it means that the user has removed all \' in the
- // phantom group.
- // We can remove the phamtom group and the sp element. But we also can only remove the
- // phantom group, giving the user the possibility of inserting an exponent.
- // At the moment, we remove the sp element (and the phantom group), because it may be the correct
- // behavior of a graphical deleting.
- cursor.remove();
- parent.replace(cursor);
- // now we have an sp element with two children: the first child (we don't know anything about it)
- // and the cursror.
- assert(cursor.parent().size() == 2);
+ // now we have to control the parent, to handle the case of primes. But we have returned from a drop_prev(), which
+ // could change the TML tree. So not asssuming that cursor's parent is unchanged is convenient.
+ parent = cursor.parent();
+ if (parent.isG() && !parent.hasId() && (parent.size() == 1) && parent.parent().isSp())
+ {
+ // in this case the drop_prev has removed the only element preceding the cursor.
+ // Since the phantom group is an sp's child, the user has removed all \' in the
+ // phantom group.
+ // Now we have some possibilities:
+ // - we can replace the phantom group with the cursor, giving the user the chance to insert a new
+ // exponent
+ // - we can remove the phantom group and the sp element, recreating the state before the user inserted the first
+ // prime.
+ // At the moment we implement the second one.
+ assert(parent.parent().size() == 2);
+ TNode gparent = parent.parent();
+ TNode base = gparent.first();
+ cursor.remove();
+ parent.remove();
+ gparent.replace(base);
+ // now base's parent is no more gparent
+ base.parent().append(cursor);
- // to delete the script we can invoke the do_gdelete_script(), which will do all controls we need.
- // To give the possibility of insetring an exponent, just remove the following istruction.
- do_gdelete_script();
- }
- else if (parent.parent().isSp())
- {
- // in this case we have to place the cursor after the sp element
- cursor.remove();
- assert(parent.parent().parent());
- parent.parent().parent().append(cursor);
+ return str;
+ }
+ else if (parent.isG() && !parent.hasId() && parent.parent().isSp())
+ {
+ // in this case we have to place the cursor after the sp element
+ cursor.remove();
+ assert(parent.parent().parent());
+ parent.parent().parent().append(cursor);
+ return str;
+ }
+ else return str;
}
}
else
if (!gfather)
{
// If here, the TML tree is in an inconsistent state
- logger.error("do_gdelete_phantom: TML tree in a inconsistent state");
+ logger.error("TML tree in a inconsistent state");
+ return "";
}
else if (gfather.isC())
{
// We have to control the nature of this MACRO.
assert(!frames.empty());
Frame& frame = frames.top();
+
+ // this variable is useful in a special deleting
+ std::string macro_name = gfather.nameC();
if (frame.entry.leftOpen && frame.entry.rightOpen)
{
// now we have the situation preceding the insertion of the leftOpen and rightOpen MACRO.
// this MACRO no longer exists.
frames.pop();
+
+ if (special) return "\\" + macro_name.erase(macro_name.length() - 1, 1);
+ else
+ {
+ // to give a standard behaviour to the graphical deleting, we call the do_drop.
+ return do_drop(special);
+ }
}
else if (frame.entry.rightOpen)
{
// now we have the situation preceding the rightOpen MACRO, so we have to pop the frame
frames.pop();
+
+ if (special) return "\\" + macro_name.erase(macro_name.length() - 1, 1);
+ else
+ {
+ // to give a standard behaviour to the graphical deleting, we call the do_drop.
+ return do_drop(special);
+ }
+
}
else if (frame.entry.leftOpen)
{
// this situation will never occur.
logger.error("the parser has generated a wrong TML tree");
+ return "";
}
else if (!frame.entry.pattern.empty())
{
// the MACRO accepts arguments, and the phantom group in which
- // the cursor is, rappresents a delimited argument
+ // the cursor is, rappresents a delimited argument.
// We have to control if the cursor's parent has a preceding element,
// or not.
TNode uncle = parent.prev();
parent.remove();
gfather.replace(cursor);
frames.pop();
+
+ if (special) return "\\" + macro_name.erase(macro_name.length() - 1, 1);
+ else
+ {
+ // once we have replaced the empty macro with the cursor, we can remove
+ // something else
+ return do_drop(special);
+ }
}
else
{
// to control if the uncle is a delimited argument or not.
if (uncle.isG() && !uncle.hasId())
{
- // the uncle is a delimited argument. So we have to ideally
- // remove the sequence of delimiters.
- assert(frame.pos > 1);
- unsigned sequence_length = frame.pos - frame.entry.previousParam(frame.pos) - 1;
- assert(frame.entry.previousParam(frame.pos) != frame.entry.pattern.size());
- assert(sequence_length);
- // sequence_length is the length of the delimiters sequence which separates
- // the current parameter and the previous parameter
- frame.pos = frame.pos - sequence_length - 1;
+ // cursor's uncle is a delimited argument
cursor.remove();
parent.remove();
uncle.append(cursor);
+ if (special)
+ {
+ // we have to start removing the last delimiter of the delimited
+ // argument.
+ std::string last_del = frame.entry.pattern[frame.pos - 1].value;
+ frame.pos = frame.pos - 2;
+ return "\\" + last_del.erase(last_del.length() - 1, 1);
+ }
+ else
+ {
+ // the uncle is a delimited argument. So we have to ideally
+ // remove the sequence of delimiters.
+ assert(frame.pos > 1);
+ unsigned sequence_length = frame.pos - frame.entry.previousParam(frame.pos) - 1;
+ assert(frame.entry.previousParam(frame.pos) != frame.entry.pattern.size());
+ assert(sequence_length);
+ // sequence_length is the length of the delimiters sequence which separates
+ // the current parameter and the previous parameter
+ frame.pos = frame.pos - sequence_length - 1;
+
+ // once removed the sequnce of delimiters, we can start to remove the actual
+ // parameter. We can call the do_drop_phantom_group() because a delimited argument
+ // is always a phantom group's child
+ return do_drop_phantom_group(special);
+ }
}
else
{
// the uncle is a not delimited argument, so we try to remove it.
cursor.remove();
parent.replace(cursor);
- parent = cursor.parent(); // i update the parent (it should be the MACRO)
+ parent = cursor.parent(); // we update the parent (it should be the MACRO)
assert(parent.isC());
// now we try to remove the uncle (now it' the preceding element)
- gdelete_prev();
+ return drop_prev(special);
}
} // this is the else's end, that handles the case in which an uncle exists
} // end of if (!frame.entry.pattern.empty())
else
{
// the entry has no arguments, is not rightOpen and is not leftOpen.
- logger.warning("parser: TML tree in a strange state, but we try to recover from it");
- if (gfather.size() == 1)
- {
- cursor.remove();
- parent.remove();
- gfather.replace(cursor);
- }
- else
- {
- logger.warning("parser: TML tree in a very strange state, but we try to recover from it");
- cursor.remove();
- gfather.replace(cursor);
- }
+ logger.error("TML tree in a strange state");
+ return "";
}
} // end of if (gfather.isC())
else if (gfather.is("cell"))
{
// A table is a control sequence, so there is a frame in the stack
assert(!frames.empty());
- assert(frames.top().pos == 1);
+ assert(frames.top().pos == 0);
assert(frames.top().entry.table == 1);
// a cell MUST be a row's child, which in turn is a table's child
assert(gfather.parent() && gfather.parent().is("row") && gfather.parent().parent());
+
+ // this variable is useful to handle the special deleting
+ std::string table_name = gfather.parent().parent().nameC();
+
TNode row = gfather.parent();
// in this case the cell has no element, so the user wants to delete this cell.
if (!prev_cell)
{
- // in this case, the cell is the only cell in the row.
+ // in this case, the cell was the only cell in the row.
// So, we assume that the user wants to delete the entire row.
TNode table = row.parent();
TNode prev_row = row.prev();
if (!prev_row)
{
- // the row was the only child of the table.
- // so we have to delete the entire table
- assert(table.parent());
- TNode parent_table = table.parent();
- table.remove();
- frames.pop();
- parent_table.append(cursor);
+ if (special)
+ {
+ // Since there was a cell (and a row), the user has typed a "{" to
+ // We ideally remove this character.
+ table.append(cursor);
+ return "";
+ }
+ else
+ {
+ // the row was the only child of the table.
+ // so we have to delete the entire table
+ assert(table.parent());
+ TNode parent_table = table.parent();
+ table.remove();
+ frames.pop();
+ parent_table.append(cursor);
+ return "";
+ }
}
else
{
assert(last_cell.size() == 1);
assert(last_cell.first().isG() && !last_cell.first().hasId());
last_cell.first().append(cursor);
+ // Since cells and rows are separated by spaces and CRs
+ // (and the user can see this spaces and CRs), a special deleting
+ // is equivalent to a normal deleting
+ return "";
}
} // end of if (!prev_cell)
else
assert(prev_cell.size() == 1);
assert(prev_cell.first().isG() && !prev_cell.first().hasId());
prev_cell.first().append(cursor);
+ return "";
}
} // end of if (gfather.is("cell"))
else if (gfather.isSp())
{
- // in this case, the user typed a \'. So this phantom group
- // contained a sequence of \'.
- // Maybe in this part will never be used, because, if we delete last \' in the
- // phantom group, we remove the phantom group also
- //
- // In any case, if we are here we have two possibilities:
- // we can delete the phantom group;
- // we can delete the superscript.
- // At the moment we implement the first solution. To implement the second one, just remove
- // the line code after the logger.warning and remove comments from the remaining lines
- logger.warning("parser: TML tree in a strange state, we try to recover from it");
- parent.replace(cursor);
-
- //cursor.remove();
- //parent.remove();
- //gfather.replace(cursor);
+ // we cannot be here because a phantom group can be a Sp child only
+ // in two cases. If the user has typed somethong like:
+ // $^
+ // the cursor is not phantom group's child.
+ // If the user has typed somethong like
+ // ..''
+ // In this case the sequence of ' is placed in a phantom group,
+ // which becomes the exponent of the script. But, the cursor is
+ // always outside the phantom group
+ logger.error("TML tree in a strange state");
+ return "";
}
else if (gfather.is("math"))
{
// in this case we ignore the user's will of deleting
- // but we can decide to remove the math mode.
- logger.info("Parser: nothing to delete");
+ // but we could also decide to remove the math mode.
+ logger.warning("Parser: nothing to delete");
+ return "";
}
else
{
// cursor's grand father is undefined
logger.error("parser: TML tree is in a unknown state");
+ return "";
}
} // end of the else of the if (prev)
}
-void
-TPushParser::do_gdelete()
+std::string
+TPushParser::do_drop(bool special)
{
// we have to handle the case in wich the cursor has a parent or not
if (!cursor.parent())
{
// it's not a good situation...at the moment we do not take actions
logger.error("TML tree not well structured");
+ return "";
}
else
{
// we ca do two thing...we can remove the math mode (it implies controlling the display attribute), we can do nothing
// At the moment, the user's will of deleting is simply ignored
logger.warning("nothing to delete");
+ return "";
}
else if (parent.isG())
{
// the cursor's parent is a group. We have to control if it's a phantom group or not
if (parent.hasId())
{
- do_gdelete_groupId();
+ return do_drop_groupId(special);
}
else
{
- do_gdelete_phantom_group();
+ return do_drop_phantom_group(special);
}
} // end of parent is group
else if (parent.isC())
{
- do_gdelete_macro();
+ return do_drop_macro(special);
} // end of parent is a MACRO
else if (parent.isSp() || parent.isSb())
{
- do_gdelete_script();
+ return do_drop_script(special);
} // end of parent is sp or sb
} // end of the else which consider the case in which parent exists
-} // end of method do_gdelete
+} // end of method do_drop
-void
+bool
TPushParser::process(const TToken& token)
{
switch (token.category)
{
- case TToken::BEGIN: do_begin(); break;
- case TToken::END: do_end(); break;
- case TToken::SHIFT: do_shift(); break;
- case TToken::ALIGN: do_align(); break;
- case TToken::EOL: do_eol(); break;
- case TToken::PARAMETER: do_parameter(token.value); break;
- case TToken::SUPERSCRIPT: do_superscript(); break;
- case TToken::SUBSCRIPT: do_subscript(); break;
- case TToken::SPACE: do_space(token.value); break;
- case TToken::LETTER: do_letter(token.value); break;
- case TToken::DIGIT: do_digit(token.value); break;
- case TToken::OTHER: do_other(token.value); break;
- case TToken::ACTIVE: do_active(token.value); break;
- case TToken::COMMENT: do_comment(); break;
- case TToken::CONTROL: do_control(token.value); break;
+ case TToken::BEGIN: return do_begin(); break;
+ case TToken::END: return do_end(); break;
+ case TToken::SHIFT: return do_shift(); break;
+ case TToken::ALIGN: return do_align(); break;
+ case TToken::EOL: return do_eol(); break;
+ case TToken::PARAMETER: return do_parameter(token.value); break;
+ case TToken::SUPERSCRIPT: return do_superscript(); break;
+ case TToken::SUBSCRIPT: return do_subscript(); break;
+ case TToken::SPACE: return do_space(token.value); break;
+ case TToken::LETTER: return do_letter(token.value); break;
+ case TToken::DIGIT: return do_digit(token.value); break;
+ case TToken::OTHER: return do_other(token.value); break;
+ case TToken::ACTIVE: return do_active(token.value); break;
+ case TToken::COMMENT: return do_comment(); break;
+ case TToken::CONTROL: return do_control(token.value); break;
}
}
// this delimiter is the last one for the argumet,
// so the argument is completed
cursor.remove();
- frame.pos++;
-
- if (frame.pos == frame.entry.pattern.size())
- {
- // This token has completed the entry
- advance(parent);
- }
- else if (frame.entry.paramDelimited(frame.pos))
- {
- // For the next is a delimited argument we have to place
- // a suitable phantom group with the cursor inside
- TNode g = doc.createG();
- parent.parent().append(g);
- g.append(cursor);
- }
- else
- parent.parent().append(cursor);
+ advance(parent);
}
}
else
// - ignore the token, and wait for the correct delimiter
// - ignore the token, wait for the correct delimiter and emit an error
// At the moment, we implement the second possibily
- logger.error("parser: it's not the correct delimiter...you have to type " + frame.entry.pattern[frame.pos + 1].value);
+ logger.warning("parser: it's not the correct delimiter...you have to type " + frame.entry.pattern[frame.pos + 1].value);
}
else
{
{
// As by the TeX parsing rules of undelimited parameters,
// empty spaces are ignored
- if (token.category != TToken::SPACE)
- {
- // We need to increase the frame position here, becase inside
- // process the function advance will be called. At that point
- // it will be important for the parser to know that the entry
- // has been completed in order to place the cursor correctly
- // in the next position
- frame.pos++;
- process(token);
- }
+ if (token.category != TToken::SPACE) process(token);
}
else if (frame.entry.pattern[frame.pos] == token)
{
g.append(cursor);
}
else
- advance(parent);
+ {
+ cursor.remove();
+ advance(parent);
+ }
}
else
{
// There is a mismatch. Emit an error and ignore the token?
- logger.debug("parser: token ignored: " + token.value);
+ logger.warning("parser: token ignored: " + token.value);
}
-
}
else
process(token);
}
std::string
-TPushParser::drop()
+TPushParser::drop(bool special)
{
- do_gdelete();
+ std::string str = do_drop(special);
if (factory && doc.dirtyNode() && !frozen()) factory->documentModified(doc);
- return "";
+ return str;
}
-
void
TPushParser::advance(const TNode& node)
{
else if (node.parent().isC())
{
assert(!frames.empty());
- if (frames.top().pos == frames.top().entry.pattern.size())
+ if ((frames.top().pos + 1 == frames.top().entry.pattern.size()) || (frames.top().entry.pattern.empty()))
{
+ // we are here when we have a right open macro, or the inserted element is the last one
if (frames.top().entry.rightOpen)
{
// we have to remove the frame from the stack
advance(node.parent());
}
}
- else if (frames.top().entry.paramDelimited(frames.top().pos))
+ else if (frames.top().entry.paramDelimited(frames.top().pos + 1))
{
// the next argument is delimited, so we have to create a phantom group
TNode g = doc.createG();
g.append(cursor);
node.parent().append(g);
+ frames.top().pos++;
}
else
{
// the next argumet is not delimited, so we have to append the cursor
// to the MACRO
node.parent().append(cursor);
+ frames.top().pos++;
}
}
else advance(node.parent());
}
-
-/*
- * This version handles the case in which we have to
- * create a delimited argument
-
-void
-TPushParser::advance(const TNode& node)
-{
- assert(node);
- TNode parent = node.parent();
- if (!parent)
- ; // nothing to do, the cursor is not in the document any more
- else if (parent.isG())
- {
- TNode next = node.next();
- if (next) next.insert(cursor);
- else parent.append(cursor);
- }
- else if (parent.isC())
- {
- if (node.next())
- ; // cursor removed
- else
- {
- Frame& frame = frames.top();
- if (frame.pos == frame.entry.pattern.size())
- {
- frames.pop();
- advance(parent);
- }
- else if (frame.entry.paramDelimited(frame.pos))
- {
- // the next argument is delimited, so we have to create a phantom group
- // with the cursor inside. We have to remember that, since we are here,
- // the cursor has been removed
- TNode g = doc.createG();
- g.append(cursor);
- parent.append(g);
- }
- else
- {
- // otherwise, the next MACRO's argument is not delimited, so we just
- // append the cursor to the MACRO
- parent.append(cursor);
- }
- }
- }
- else if (parent.is("math"))
- ; // we are done
- else
- advance(parent);
-}
-*/
-
-/*
- * original advance
-void
-TPushParser::advance(const TNode& node)
-{
- assert(node);
- TNode parent = node.parent();
- if (!parent)
- ; // nothing to do, the cursor is not in the document any more
- else if (parent.isG())
- {
- TNode next = node.next();
- if (next) next.insert(cursor);
- else parent.append(cursor);
- }
- else if (parent.isC())
- {
- if (node.next())
- ; // cursor removed
- else
- {
- Frame& frame = frames.top();
- if (frame.pos == frame.entry.pattern.size())
- {
- frames.pop();
- advance(parent);
- }
- else
- parent.append(cursor);
- }
- }
- else if (parent.is("math"))
- ; // we are done
- else
- advance(parent);
-}
-*/
-
-
void
TPushParser::setCursorHint(const std::string& c)
{