}
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(table);
+
+ // now we have to pop the associated frame in the stack
+ frames.pop();
}
else if (parent && parent.isG() && !parent.hasId() && parent.parent())
{
if (parent.isG())
{
frames.push(Frame(entry));
- cout << "do_control: valore di pos del frame inserito " << frames.top().pos << endl;
+
+ if (entry.table)
+ cout << "do_control: we have a table" << endl;
+
if (entry.paramDelimited(0))
{
+ cout << "do_control: it'a MACRO with delimited first argument" << endl;
TNode g = doc.createG();
m.append(g);
g.append(cursor);
prev.append(cursor);
do_gdelete();
}
- else if (prev.isC())
+ else if (prev.isC() && dictionary.find(prev["name"]).cls != TDictionary::UNDEFINED)
{
const TDictionary::Entry& entry = dictionary.find(prev["name"]);
prev.last().append(cursor);
// i have to push a frame with a correct value of pos
Frame frame(entry);
- frame.pos = entry.pattern.size() - 2;
+ assert(entry.previousParam(entry.pattern.size()) != entry.pattern.size());
+ unsigned sequence_length = entry.pattern.size() - entry.previousParam(entry.pattern.size()) - 1;
+ frame.pos = entry.pattern.size() - sequence_length - 1;
frames.push(frame);
+ cout << "gdelete_prev: i have inserted a frame, it's pos is: " << frames.top().pos << endl;
}
else
{
// remove it
cout << "gdelete_prev: i try to remove the last argumet of the MACRO" << endl;
cursor.remove();
- prev.append(cursor); // now prev is the cursor's parent
+ if (entry.table == 1 && prev.last().is("row"))
+ {
+ // in this case should 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);
+ }
+ else prev.append(cursor);
Frame frame(entry);
frame.pos = entry.pattern.size();
frames.push(frame);
- gdelete_prev();
+ if (cursor.prev()) gdelete_prev();
+ else do_gdelete();
}
}
}
+ else if (dictionary.find(prev["name"]).cls == TDictionary::UNDEFINED)
+ {
+ // The user wants to delete an undefined element.
+ // I suppose that he (or she) wants to delete it all
+ cursor.remove();
+ prev.replace(cursor);
+ }
else
{
// not handled
TNode uncle = parent.prev();
if (uncle.isG() && !uncle.hasId())
{
- // the cursor's parent is a phantom group, so it was a
- // delimited argument of the MACRO and the corrisponding
- // delimeter is inserted. So, the action of deleting means
- // removing this delimeter
+ // the cursor's uncle is a phantom group, so it was a
+ // delimited argument of the MACRO and the corrisponding sequence of
+ // delimeters is inserted. So, the action of deleting means
+ // removing this sequence
+ 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.remove();
parent.remove();
uncle.append(cursor);
- frame.pos -= 2;
}
else
{
}
}
+ else if (gfuther.is("cell"))
+ {
+ // being here means that there is a frame in the stack
+ // associated to the "table"
+ cout << "do_gdelete: i have to delete a cell" << endl;
+ assert(!frames.empty());
+ assert(frames.top().pos == 1);
+ assert(frames.top().entry.table == 1);
+ // a cell MUST be child of row element, which in turn MUST be child of an element
+ // havin attribute table.
+ assert(gfuther.parent() && gfuther.parent().is("row") && gfuther.parent().parent());
+ TNode row = gfuther.parent();
+
+ // in this case the cell has no element, so the user wants to delete this cell.
+ TNode prev_cell = gfuther.prev();
+
+ cursor.remove();
+ parent.remove();
+ gfuther.remove();
+ // now the cell no longer exists
+
+ if (!prev_cell)
+ {
+ // i this case, the cell is the only cell in the row.
+ // So, i assume that the user wants to delete the entire row.
+ TNode table = row.parent();
+ TNode prev_row = row.prev();
+ row.remove();
+ if (!prev_row)
+ {
+ // the row was the only child of the table.
+ // I think have to delete the entire table
+ assert(table.parent());
+ TNode parent_table = table.parent();
+ table.remove();
+ frames.pop();
+ parent_table.append(cursor);
+ }
+ else
+ {
+ // there are other rows (one at least)
+ assert(prev_row.is("row"));
+ assert(prev_row.last());
+ TNode last_cell = prev_row.last();
+ assert(last_cell.is("cell"));
+ assert(last_cell.size() == 1);
+ assert(last_cell.first().isG() && !last_cell.first().hasId());
+ last_cell.first().append(cursor);
+ }
+ }
+ else
+ {
+ // being here means that there is a previous cell,
+ // so we append the cursor to group.
+ assert(prev_cell.size() == 1);
+ assert(prev_cell.first().isG() && !prev_cell.first().hasId());
+ prev_cell.first().append(cursor);
+ }
+ }
}
else // the grand futher is math
{
if (prev.isG() && !prev.hasId())
{
// in this case we have to append the cursor
- // to the prev and decrement frame.pos of two units
- // because the prev is a delimited argument and the
- // delimiter is inserted. So we ideally remove this delimiter
+ // to the prev and decrement frame.pos of the length of
+ // delimiters sequence that delimitates the preceding argument.
+ // So we ideally remove this sequence
+ assert(frame.pos > 1);
cursor.remove();
prev.append(cursor);
- frame.pos -=2;
+ assert(frame.entry.previousParam(frame.pos) != frame.entry.pattern.size());
+ unsigned sequence_length = frame.pos - frame.entry.previousParam(frame.pos) - 1;
+ assert(sequence_length);
+ frame.pos = frame.pos - sequence_length - 1;
}
else
{
{
// being here means that a prev MUST exist
// and that there is only an element preceding the cursor.
- // A sp's (or sb's) MUST NOT be a MACRO
+ // The sp's (or sb's) parent MUST NOT be a MACRO
assert(parent.size() == 2);
assert(parent.parent() && !parent.parent().isC());
TNode prev = cursor.prev();
cursor.remove();
- if (prev.isG() && !prev.hasId() && (prev.size() == 0))
+ if (prev.isG() /*&& !prev.hasId()*/ && (prev.size() == 0))
{
prev.remove();
parent.replace(cursor);
}
else
{
- // the cursro has no parent!!!
+ // the cursor has no parent!!!
// do nothing?
// emit an error? and if we want to emit an error, in which way?
}
cout << "push: i have to process a token with category member = GDELETE" << endl;
process(token);
}
- else
+ else if ((doc.root().first() && doc.root().first().is("math")) || token.category == TToken::SHIFT)
{
- TNode parent = cursor.parent();
- // If the cursor has no parent then it is detached from the editing
- // tree, which means this token will be ignored
-
- if (parent)
- // If the parent is a phantom group and the grand-parent is a
- // control sequence, there are two cases:
- // a. we are parsing a delimited argument of a entry
- // b. we are parsing a side of a right- or left-open entry
- if (parent.isG() && !parent.hasId() && parent.parent().isC())
- {
- // There must be an open frame, for the grand-parent is a control sequence
- assert(!frames.empty());
- Frame& frame = frames.top();
- if (!frame.entry.pattern.empty())
- {
- // The entry pattern is not empty. By our conventions this means
- // the entry cannot be open at either end, hence we are parsing
- // a delimited argument
- assert(frame.pos + 1 < frame.entry.pattern.size());
- assert(frame.entry.pattern[frame.pos + 1].category != TToken::PARAMETER);
- if (frame.entry.pattern[frame.pos + 1] == token)
+ TNode parent = cursor.parent();
+ // If the cursor has no parent then it is detached from the editing
+ // tree, which means this token will be ignored
+
+ if (parent)
+ // If the parent is a phantom group and the grand-parent is a
+ // control sequence, there are two cases:
+ // a. we are parsing a delimited argument of a entry
+ // b. we are parsing a side of a right- or left-open entry
+ if (parent.isG() && !parent.hasId() && parent.parent().isC())
+ {
+ // There must be an open frame, for the grand-parent is a control sequence
+ assert(!frames.empty());
+ Frame& frame = frames.top();
+ if (!frame.entry.pattern.empty())
{
- // The token matches with the delimiter of the argument.
- cursor.remove();
-
- // If the phantom group has just one child, it is not necessary
- // and can be removed. However, this would complicate
- // all the code that follows, so given it is a rare case we
- // leave it alone
- // if (parent.size() == 1) parent.replace(parent[0]);
-
- // Eat both the argument and its delimiter
- frame.pos += 2;
- if (frame.pos == frame.entry.pattern.size())
- {
- // This token has completed the entry
- advance(parent.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);
+ // The entry pattern is not empty. By our conventions this means
+ // the entry cannot be open at either end, hence we are parsing
+ // a delimited argument
+ assert(frame.pos + 1 < frame.entry.pattern.size());
+ assert(frame.entry.pattern[frame.pos + 1].category != TToken::PARAMETER);
+ if (frame.entry.pattern[frame.pos + 1] == token)
+ {
+ // The token matches with a delimiter of the argument,
+ // so we increment the frame.pos
+ frame.pos++;
+
+ if (frame.entry.lastDelimiter(frame.pos))
+ {
+ // 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
+ frames.pop();
+ advance(parent.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);
+ }
+ }
+ else
+ {
+ // Delimiter mismatch.
+ if (frame.entry.pattern[frame.pos].category != TToken::PARAMETER)
+ {
+ // in this case, there is a sequence of delimiters that delimitates
+ // the argument, and the user correctly inserted a portion of this
+ // sequence, but has inserted a wrong delimiter.
+ // Here, there are some possibilities:
+ // - ignore the token, and wait for the correct delimiter
+ // - ignore the token, wait for the correct delimiter and emit an error
+ // If we want to emit an error, we shlould implement a class, that handle
+ // the error.
+ // At the moment, the error is printed to screen
+ cout << "push: it's not the correct delimiter...you have to type " << frame.entry.pattern[frame.pos + 1].value << endl;
+ }
+ else
+ {
+ // in this case, the sequence of delimiters is composed of one
+ // delimiter. It means that we have to process the token
+ process(token);
+ }
+ }
}
else
{
- // Delimiter mismatch. Since we are parsing a delimited
- // argument we just process the token
- process(token);
+ // The entry pattern is empty, hence we are parsing a right-open
+ // entry. What happens if we actually are in the left side?
+ // This could happen only when re-editing an entered expression
+ // We'll see...
+ assert(frame.entry.rightOpen);
+ process(token);
}
- }
- else
- {
- // The entry pattern is empty, hence we are parsing a right-open
- // entry. What happens if we actually are in the left side?
- // This could happen only when re-editing an entered expression
- // We'll see...
- assert(frame.entry.rightOpen);
- process(token);
- }
- }
- else if (parent.isC())
- {
- // We are parsing a non-delimited argument entry
- // or a fixed token
- Frame& frame = frames.top();
- assert(frame.pos < frame.entry.pattern.size());
-
- cout << "push: il valore di pos del frame inserito prima e': " << frame.pos << endl;
- if (frame.entry.pattern[frame.pos].category == TToken::PARAMETER)
- {
- // As by the TeX parsing rules of undelimited parameters,
- // empty spaces are ignored
- if (token.category != TToken::SPACE)
+ }
+ else if (parent.isC())
+ {
+ // We are parsing a non-delimited argument entry
+ // or a fixed token
+ Frame& frame = frames.top();
+ assert(frame.pos < frame.entry.pattern.size());
+
+ cout << "push: there is a frame with pos " << frame.pos << endl;
+ if (frame.entry.pattern[frame.pos].category == TToken::PARAMETER)
{
- // 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);
+ // 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);
+ }
}
- }
- else if (frame.entry.pattern[frame.pos] == token)
- {
- // The token has been accepted
- frame.pos++;
- if (frame.pos < frame.entry.pattern.size() &&
- frame.entry.paramDelimited(frame.pos))
+ else if (frame.entry.pattern[frame.pos] == token)
{
- // If the next is a delimited argument we have to place
- // the phantom group with the cursor inside
- TNode g = doc.createG();
- cursor.replace(g);
- g.append(cursor);
+ // The token has been accepted
+ frame.pos++;
+ if (frame.pos < frame.entry.pattern.size() &&
+ frame.entry.paramDelimited(frame.pos))
+ {
+ // If the next is a delimited argument we have to place
+ // the phantom group with the cursor inside
+ TNode g = doc.createG();
+ cursor.replace(g);
+ g.append(cursor);
+ }
+ else
+ advance(parent);
}
else
- advance(parent);
- }
- else
- {
- // There is a mismatch. Emit an error and ignore the token?
- cerr << "ERROR: token ignored: " << token.value << " (cat: " << token.category << ")" << endl;
- }
+ {
+ // There is a mismatch. Emit an error and ignore the token?
+ cerr << "ERROR: token ignored: " << token.value << " (cat: " << token.category << ")" << endl;
+ }
- }
- else
- process(token);
+ }
+ else
+ process(token);
+ else
+ {
+ cout << "ignored token" << endl;
+ }
+
+ if (listener) listener->callback(doc); //it shoul be repristened if you remove the comment in the else above
+
+ } // this end corresponds to the if ((doc.root().first() && doc.root().first().is("math")) || token.category == TToken::SHIFT)
else
{
- cout << "ignored token" << endl;
+ // there is no math element
+ // In this case, i think we have to emit an error
+ cout << "push: ignored token...you have to enter in math mode...insert $" << endl;
}
- } // this end corresponds to the else of the if (token.category == GDELETE)
- if (listener) listener->callback(doc);
+ //if (listener) listener->callback(doc);
if (frames.empty()) cout << "stack vuoto" << endl;
else cout << "stack non vuoto" << endl;