]> git.lyx.org Git - features.git/blobdiff - src/mathed/InsetMathHull.cpp
s/updateLabels/updateBuffer/g, per a suggestion of Abdel's.
[features.git] / src / mathed / InsetMathHull.cpp
index b2245a6c5adfd7029f9115f57fab89dfdeb7a591..62a28ec4c99005711f938a808d22c37a6517018d 100644 (file)
@@ -3,54 +3,48 @@
  * This file is part of LyX, the document processor.
  * Licence details can be found in the file COPYING.
  *
- * \author André Pönitz
+ * \author André Pönitz
  *
  * Full author contact details are available in file CREDITS.
  */
 
 #include <config.h>
 
-#include "InsetMathArray.h"
+#include "InsetMathHull.h"
+
 #include "InsetMathChar.h"
 #include "InsetMathColor.h"
-#include "MathData.h"
-#include "InsetMathDelim.h"
 #include "MathExtern.h"
 #include "MathFactory.h"
-#include "InsetMathHull.h"
-#include "MathStream.h"
-#include "MathParser.h"
-#include "InsetMathSpace.h"
 #include "MathStream.h"
 #include "MathSupport.h"
-#include "InsetMathRef.h"
 
 #include "Buffer.h"
-#include "buffer_funcs.h"
 #include "BufferParams.h"
 #include "BufferView.h"
+#include "ColorSet.h"
 #include "CutAndPaste.h"
+#include "Encoding.h"
+#include "FuncRequest.h"
 #include "FuncStatus.h"
 #include "LaTeXFeatures.h"
-#include "Cursor.h"
-#include "DispatchResult.h"
-#include "FuncRequest.h"
 #include "LyXRC.h"
-#include "OutputParams.h"
-#include "ParIterator.h"
+#include "MacroTable.h"
+#include "output_xhtml.h"
 #include "sgml.h"
-#include "Text.h"
 #include "TextPainter.h"
 #include "TocBackend.h"
 
-#include "insets/RenderPreview.h"
 #include "insets/InsetLabel.h"
+#include "insets/InsetRef.h"
+#include "insets/RenderPreview.h"
 
 #include "graphics/PreviewImage.h"
 #include "graphics/PreviewLoader.h"
 
 #include "frontends/Painter.h"
 
+#include "support/lassert.h"
 #include "support/debug.h"
 #include "support/gettext.h"
 #include "support/lstrings.h"
@@ -116,7 +110,8 @@ HullType hullType(docstring const & s)
        if (s == "multline")  return hullMultline;
        if (s == "gather")    return hullGather;
        if (s == "flalign")   return hullFlAlign;
-       lyxerr << "unknown hull type '" << to_utf8(s) << "'" << endl;
+       if (s == "regexp")    return hullRegexp;
+       lyxerr << "unknown hull type '" << to_utf8(s) << "'" << endl;
        return HullType(-1);
 }
 
@@ -135,7 +130,8 @@ docstring hullName(HullType type)
                case hullMultline:   return from_ascii("multline");
                case hullGather:     return from_ascii("gather");
                case hullFlAlign:    return from_ascii("flalign");
-               default:
+               case hullRegexp:     return from_ascii("regexp");
+               default:
                        lyxerr << "unknown hull type '" << type << "'" << endl;
                        return from_ascii("none");
        }
@@ -143,29 +139,31 @@ docstring hullName(HullType type)
 
 static InsetLabel * dummy_pointer = 0;
 
-InsetMathHull::InsetMathHull()
-       : InsetMathGrid(1, 1), type_(hullNone), nonum_(1, false), label_(1, dummy_pointer),
-         preview_(new RenderPreview(this))
+InsetMathHull::InsetMathHull(Buffer * buf)
+       : InsetMathGrid(buf, 1, 1), type_(hullNone), nonum_(1, false),
+         label_(1, dummy_pointer), preview_(new RenderPreview(this))
 {
        //lyxerr << "sizeof InsetMath: " << sizeof(InsetMath) << endl;
        //lyxerr << "sizeof MetricsInfo: " << sizeof(MetricsInfo) << endl;
        //lyxerr << "sizeof InsetMathChar: " << sizeof(InsetMathChar) << endl;
        //lyxerr << "sizeof FontInfo: " << sizeof(FontInfo) << endl;
+       buffer_ = buf;
        initMath();
        setDefaults();
 }
 
 
-InsetMathHull::InsetMathHull(HullType type)
-       : InsetMathGrid(getCols(type), 1), type_(type), nonum_(1, false), label_(1, dummy_pointer),
-         preview_(new RenderPreview(this))
+InsetMathHull::InsetMathHull(Buffer * buf, HullType type)
+       : InsetMathGrid(buf, getCols(type), 1), type_(type), nonum_(1, false),
+         label_(1, dummy_pointer), preview_(new RenderPreview(this))
 {
+       buffer_ = buf;
        initMath();
        setDefaults();
 }
 
 
-InsetMathHull::InsetMathHull(InsetMathHull const & other)
+InsetMathHull::InsetMathHull(InsetMathHull const & other) : InsetMathGrid(other)
 {
        operator=(other);
 }
@@ -191,6 +189,7 @@ InsetMathHull & InsetMathHull::operator=(InsetMathHull const & other)
        InsetMathGrid::operator=(other);
        type_  = other.type_;
        nonum_ = other.nonum_;
+       buffer_ = other.buffer_;
        for (size_t i = 0; i < label_.size(); ++i)
                delete label_[i];
        label_ = other.label_;
@@ -206,12 +205,7 @@ InsetMathHull & InsetMathHull::operator=(InsetMathHull const & other)
 
 void InsetMathHull::setBuffer(Buffer & buffer)
 {
-       buffer_ = &buffer;
-       for (idx_type i = 0, n = nargs(); i != n; ++i) {
-               MathData & data = cell(i);
-               for (size_t j = 0; j != data.size(); ++j)
-                       data[j].nucleus()->setBuffer(buffer);
-       }
+       InsetMathGrid::setBuffer(buffer);
 
        for (size_t i = 0; i != label_.size(); ++i) {
                if (label_[i])
@@ -220,7 +214,7 @@ void InsetMathHull::setBuffer(Buffer & buffer)
 }
 
 
-void InsetMathHull::updateLabels(ParIterator const & it)
+void InsetMathHull::updateBuffer(ParIterator const & it, UpdateType utype)
 {
        if (!buffer_) {
                //FIXME: buffer_ should be set at creation for this inset! Problem is
@@ -230,12 +224,14 @@ void InsetMathHull::updateLabels(ParIterator const & it)
        }
        for (size_t i = 0; i != label_.size(); ++i) {
                if (label_[i])
-                       label_[i]->updateLabels(it);
+                       label_[i]->updateBuffer(it, utype);
        }
+       // pass down
+       InsetMathGrid::updateBuffer(it, utype);
 }
 
 
-void InsetMathHull::addToToc(ParConstIterator const & pit) const
+void InsetMathHull::addToToc(DocIterator const & pit)
 {
        if (!buffer_) {
                //FIXME: buffer_ should be set at creation for this inset! Problem is
@@ -244,10 +240,6 @@ void InsetMathHull::addToToc(ParConstIterator const & pit) const
                return;
        }
 
-       // FIXME: it would be way better to directly use InsetLabel instead of this
-       // label list. But it should be possible to copy&paste the code in
-       // InsetLabel::addToToc() anyway.
-
        Toc & toc = buffer().tocBackend().toc("equation");
 
        for (row_type row = 0; row != nrows(); ++row) {
@@ -321,7 +313,18 @@ int InsetMathHull::defaultColSpace(col_type col)
 
 docstring InsetMathHull::standardFont() const
 {
-       return from_ascii(type_ == hullNone ? "lyxnochange" : "mathnormal");
+       const char *font_name;
+       switch (type_) {
+       case hullRegexp:
+               font_name = "texttt";
+               break;
+       case hullNone:
+               font_name = "lyxnochange";
+               break;
+       default:
+               font_name = "mathnormal";
+       }
+       return from_ascii(font_name);
 }
 
 
@@ -344,7 +347,7 @@ void InsetMathHull::metrics(MetricsInfo & mi, Dimension & dim) const
                dim.wid += 1;
                if (display())
                        dim.des += displayMargin();
-               // Cache the inset dimension. 
+               // Cache the inset dimension.
                setDimCache(mi, dim);
                return;
        }
@@ -382,17 +385,31 @@ void InsetMathHull::metrics(MetricsInfo & mi, Dimension & dim) const
 }
 
 
-void InsetMathHull::draw(PainterInfo & pi, int x, int y) const
+ColorCode InsetMathHull::backgroundColor(PainterInfo const & pi) const
+{
+       if (previewState(pi.base.bv))
+               return graphics::PreviewLoader::backgroundColor();
+       return Color_mathbg;
+}
+
+
+void InsetMathHull::drawBackground(PainterInfo & pi, int x, int y) const
 {
-       use_preview_ = previewState(pi.base.bv);
        Dimension const dim = dimension(*pi.base.bv);
+       pi.pain.fillRectangle(x + 1, y - dim.asc + 1, dim.wid - 2,
+               dim.asc + dim.des - 1, pi.backgroundColor(this));
+}
 
-       // background of mathed under focus is not painted because
-       // selection at the top level of nested inset is difficult to handle.
-       if (!editing(pi.base.bv))
-               pi.pain.fillRectangle(x + 1, y - dim.asc + 1, dim.wid - 2,
-                               dim.asc + dim.des - 1, Color_mathbg);
 
+void InsetMathHull::draw(PainterInfo & pi, int x, int y) const
+{
+       use_preview_ = previewState(pi.base.bv);
+
+       if (type_ == hullRegexp) {
+               Dimension const dim = dimension(*pi.base.bv);
+               pi.pain.rectangle(x + 1, y - dim.ascent() + 1,
+                       dim.width() - 2, dim.height() - 2, Color_regexpframe);
+       }
        if (use_preview_) {
                // one pixel gap in front
                preview_->draw(pi, x + 1, y);
@@ -423,7 +440,7 @@ void InsetMathHull::metricsT(TextMetricsInfo const & mi, Dimension & dim) const
                InsetMathGrid::metricsT(mi, dim);
        } else {
                odocstringstream os;
-               WriteStream wi(os, false, true);
+               WriteStream wi(os, false, true, WriteStream::wsDefault);
                write(wi);
                dim.wid = os.str().size();
                dim.asc = 1;
@@ -438,7 +455,7 @@ void InsetMathHull::drawT(TextPainter & pain, int x, int y) const
                InsetMathGrid::drawT(pain, x, y);
        } else {
                odocstringstream os;
-               WriteStream wi(os, false, true);
+               WriteStream wi(os, false, true, WriteStream::wsDefault);
                write(wi);
                pain.draw(x, y, os.str().c_str());
        }
@@ -448,28 +465,71 @@ void InsetMathHull::drawT(TextPainter & pain, int x, int y) const
 static docstring latexString(InsetMathHull const & inset)
 {
        odocstringstream ls;
-       WriteStream wi(ls, false, false);
+       // This has to be static, because a preview snippet or a math
+       // macro containing math in text mode (such as $\text{$\phi$}$ or
+       // \newcommand{\xxx}{\text{$\phi$}}) gets processed twice. The
+       // first time as a whole, and the second time only the inner math.
+       // In this last case inset.buffer() would be invalid.
+       static Encoding const * encoding = 0;
+       if (inset.isBufferValid())
+               encoding = &(inset.buffer().params().encoding());
+       WriteStream wi(ls, false, true, WriteStream::wsPreview, encoding);
        inset.write(wi);
        return ls.str();
 }
 
 
-void InsetMathHull::addPreview(graphics::PreviewLoader & ploader) const
+void InsetMathHull::initUnicodeMath() const
+{
+       // Trigger classification of the unicode symbols in this inset
+       docstring const dummy = latexString(*this);
+}
+
+
+void InsetMathHull::addPreview(DocIterator const & inset_pos,
+       graphics::PreviewLoader & /*ploader*/) const
 {
        if (RenderPreview::status() == LyXRC::PREVIEW_ON) {
-               docstring const snippet = latexString(*this);
-               preview_->addPreview(snippet, ploader);
+               preparePreview(inset_pos);
        }
 }
 
 
-bool InsetMathHull::notifyCursorLeaves(Cursor const & /*old*/, Cursor & cur)
+void InsetMathHull::preparePreview(DocIterator const & pos) const  
+{
+       Buffer const * buffer = pos.buffer();  
+
+       // collect macros at this position  
+       MacroNameSet macros;  
+       buffer->listMacroNames(macros);  
+       MacroNameSet::iterator it = macros.begin();  
+       MacroNameSet::iterator end = macros.end();  
+       odocstringstream macro_preamble;  
+       for (; it != end; ++it) {  
+               MacroData const * data = buffer->getMacro(*it, pos, true);  
+               if (data) {  
+                       data->write(macro_preamble, true);  
+                       macro_preamble << endl;  
+               }
+       }  
+
+       docstring const snippet = macro_preamble.str() + latexString(*this);  
+       LYXERR(Debug::MACROS, "Preview snippet: " << snippet);  
+       preview_->addPreview(snippet, *buffer);  
+}
+
+
+void InsetMathHull::reloadPreview(DocIterator const & pos) const
+{
+       preparePreview(pos);
+       preview_->startLoading(*pos.buffer());
+}
+
+
+bool InsetMathHull::notifyCursorLeaves(Cursor const & old, Cursor & cur)
 {
        if (RenderPreview::status() == LyXRC::PREVIEW_ON) {
-               Buffer const & buffer = cur.buffer();
-               docstring const snippet = latexString(*this);
-               preview_->addPreview(snippet, buffer);
-               preview_->startLoading(buffer);
+               reloadPreview(old);
                cur.updateFlags(Update::Force);
        }
        return false;
@@ -478,7 +538,7 @@ bool InsetMathHull::notifyCursorLeaves(Cursor const & /*old*/, Cursor & cur)
 
 docstring InsetMathHull::label(row_type row) const
 {
-       BOOST_ASSERT(row < nrows());
+       LASSERT(row < nrows(), /**/);
        if (InsetLabel * il = label_[row])
                return il->screenLabel();
        return docstring();
@@ -491,15 +551,22 @@ void InsetMathHull::label(row_type row, docstring const & label)
        if (label_[row]) {
                if (label.empty()) {
                        delete label_[row];
-                       nonum_[row] = true;
                        label_[row] = dummy_pointer;
-               } else
-                       label_[row]->updateCommand(label);
+                       // We need an update of the Buffer reference cache.
+                       // This is achieved by updateBuffer().
+                       if (buffer_)
+                               buffer().updateBuffer();
+               } else {
+                       if (buffer_)
+                               label_[row]->updateCommand(label);
+                       else
+                               label_[row]->setParam("name", label);
+               }
                return;
        }
        InsetCommandParams p(LABEL_CODE);
        p["name"] = label;
-       label_[row] = new InsetLabel(p);
+       label_[row] = new InsetLabel(buffer_, p);
        if (buffer_)
                label_[row]->setBuffer(buffer());
 }
@@ -511,6 +578,14 @@ void InsetMathHull::numbered(row_type row, bool num)
        if (nonum_[row] && label_[row]) {
                delete label_[row];
                label_[row] = 0;
+               if (!buffer_) {
+                       // The buffer is set at the end of readInset.
+                       // When parsing the inset, buffer_ is 0.
+                       return;
+               }
+               // We need an update of the Buffer reference cache.
+               // This is achieved by updateBuffer().
+               buffer().updateBuffer();
        }
 }
 
@@ -523,23 +598,23 @@ bool InsetMathHull::numbered(row_type row) const
 
 bool InsetMathHull::ams() const
 {
-       return
-               type_ == hullAlign ||
-               type_ == hullFlAlign ||
-               type_ == hullMultline ||
-               type_ == hullGather ||
-               type_ == hullAlignAt ||
-               type_ == hullXAlignAt ||
-               type_ == hullXXAlignAt;
+       return type_ == hullAlign
+               || type_ == hullFlAlign
+               || type_ == hullMultline
+               || type_ == hullGather
+               || type_ == hullAlignAt
+               || type_ == hullXAlignAt
+               || type_ == hullXXAlignAt;
 }
 
 
 Inset::DisplayType InsetMathHull::display() const
 {
-       return (type_ != hullSimple && type_ != hullNone) ? AlignCenter : Inline;
+       if (type_ == hullSimple || type_ == hullNone || type_ == hullRegexp)
+               return Inline;
+       return AlignCenter;
 }
 
-
 bool InsetMathHull::numberedType() const
 {
        if (type_ == hullNone)
@@ -548,6 +623,8 @@ bool InsetMathHull::numberedType() const
                return false;
        if (type_ == hullXXAlignAt)
                return false;
+       if (type_ == hullRegexp)
+               return false;
        for (row_type row = 0; row < nrows(); ++row)
                if (!nonum_[row])
                        return true;
@@ -560,6 +637,15 @@ void InsetMathHull::validate(LaTeXFeatures & features) const
        if (ams())
                features.require("amsmath");
 
+       if (type_ == hullRegexp) {
+               features.require("color");
+               string frcol = lcolor.getLaTeXName(Color_regexpframe);
+               string bgcol = "white";
+               features.addPreambleSnippet(
+                       string("\\newcommand{\\regexp}[1]{\\fcolorbox{")
+                       + frcol + string("}{")
+                       + bgcol + string("}{\\texttt{#1}}}"));
+       }
 
        // Validation is necessary only if not using AMS math.
        // To be safe, we will always run mathedvalidate.
@@ -612,6 +698,10 @@ void InsetMathHull::header_write(WriteStream & os) const
                  << '{' << static_cast<unsigned int>((ncols() + 1)/2) << "}\n";
                break;
 
+       case hullRegexp:
+               os << "\\regexp{{{";
+               break;
+
        default:
                os << "\\begin{unknown" << star(n) << '}';
                break;
@@ -653,6 +743,10 @@ void InsetMathHull::footer_write(WriteStream & os) const
                os << "\\end{" << hullName(type_) << "}\n";
                break;
 
+       case hullRegexp:
+               os << "}}}";
+               break;
+
        default:
                os << "\\end{unknown" << star(n) << '}';
                break;
@@ -684,15 +778,19 @@ void InsetMathHull::addRow(row_type row)
                return;
 
        bool numbered = numberedType();
+       docstring lab;
        if (type_ == hullMultline) {
-               if (row + 1 == nrows())
+               if (row + 1 == nrows())  {
                        nonum_[row] = true;
-               else
+                       lab = label(row);
+               } else
                        numbered = false;
        }
 
        nonum_.insert(nonum_.begin() + row + 1, !numbered);
        label_.insert(label_.begin() + row + 1, dummy_pointer);
+       if (!lab.empty())
+               label(row + 1, lab);
        InsetMathGrid::addRow(row);
 }
 
@@ -720,6 +818,14 @@ void InsetMathHull::delRow(row_type row)
 {
        if (nrows() <= 1 || !rowChangeOK())
                return;
+       if (row + 1 == nrows() && type_ == hullMultline) {
+               bool const b = nonum_[row - 1];
+               nonum_[row - 1] = nonum_[row];
+               nonum_[row] = b;
+               swap(label_[row - 1], label_[row]);
+               InsetMathGrid::delRow(row);
+               return;
+       }
        InsetMathGrid::delRow(row);
        // The last dummy row has no number info nor a label.
        // Test nrows() + 1 because we have already erased the row.
@@ -753,7 +859,7 @@ docstring InsetMathHull::nicelabel(row_type row) const
                return docstring();
        if (!label_[row])
                return from_ascii("(#)");
-       return '(' + label_[row]->screenLabel() + ')';
+       return '(' + label_[row]->screenLabel() + from_ascii(", #)");
 }
 
 
@@ -762,7 +868,7 @@ void InsetMathHull::glueall()
        MathData ar;
        for (idx_type i = 0; i < nargs(); ++i)
                ar.append(cell(i));
-       *this = InsetMathHull(hullSimple);
+       *this = InsetMathHull(buffer_, hullSimple);
        cell(0) = ar;
        setDefaults();
 }
@@ -770,12 +876,12 @@ void InsetMathHull::glueall()
 
 void InsetMathHull::splitTo2Cols()
 {
-       BOOST_ASSERT(ncols() == 1);
+       LASSERT(ncols() == 1, /**/);
        InsetMathGrid::addCol(1);
        for (row_type row = 0; row < nrows(); ++row) {
                idx_type const i = 2 * row;
                pos_type pos = firstRelOp(cell(i));
-               cell(i + 1) = MathData(cell(i).begin() + pos, cell(i).end());
+               cell(i + 1) = MathData(buffer_, cell(i).begin() + pos, cell(i).end());
                cell(i).erase(pos, cell(i).size());
        }
 }
@@ -783,14 +889,14 @@ void InsetMathHull::splitTo2Cols()
 
 void InsetMathHull::splitTo3Cols()
 {
-       BOOST_ASSERT(ncols() < 3);
+       LASSERT(ncols() < 3, /**/);
        if (ncols() < 2)
                splitTo2Cols();
        InsetMathGrid::addCol(2);
        for (row_type row = 0; row < nrows(); ++row) {
                idx_type const i = 3 * row + 1;
                if (cell(i).size()) {
-                       cell(i + 1) = MathData(cell(i).begin() + 1, cell(i).end());
+                       cell(i + 1) = MathData(buffer_, cell(i).begin() + 1, cell(i).end());
                        cell(i).erase(1, cell(i).size());
                }
        }
@@ -985,21 +1091,23 @@ void InsetMathHull::mutate(HullType newtype)
 }
 
 
-docstring InsetMathHull::eolString(row_type row, bool emptyline, bool fragile) const
+docstring InsetMathHull::eolString(row_type row, bool fragile) const
 {
        docstring res;
        if (numberedType()) {
                if (label_[row] && !nonum_[row])
-                       res += "\\label{" + label_[row]->getParam("name") + '}';
+                       res += "\\label{" +
+                           escape(label_[row]->getParam("name")) + '}';
                if (nonum_[row] && (type_ != hullMultline))
                        res += "\\nonumber ";
        }
-       return res + InsetMathGrid::eolString(row, emptyline, fragile);
+       return res + InsetMathGrid::eolString(row, fragile);
 }
 
 
 void InsetMathHull::write(WriteStream & os) const
 {
+       ModeSpecifier specifier(os, MATH_MODE);
        header_write(os);
        InsetMathGrid::write(os);
        footer_write(os);
@@ -1028,8 +1136,8 @@ void InsetMathHull::infoize(odocstream & os) const
 
 void InsetMathHull::check() const
 {
-       BOOST_ASSERT(nonum_.size() == nrows());
-       BOOST_ASSERT(label_.size() == nrows());
+       LASSERT(nonum_.size() == nrows(), /**/);
+       LASSERT(label_.size() == nrows(), /**/);
 }
 
 
@@ -1068,7 +1176,7 @@ void InsetMathHull::doExtern(Cursor & cur, FuncRequest & func)
                        ar = cur.cell();
                        lyxerr << "use whole cell: " << ar << endl;
                } else {
-                       ar = MathData(cur.cell().begin() + pos + 1, cur.cell().end());
+                       ar = MathData(buffer_, cur.cell().begin() + pos + 1, cur.cell().end());
                        lyxerr << "use partial cell form pos: " << pos << endl;
                }
                cur.cell().append(eq);
@@ -1127,7 +1235,7 @@ void InsetMathHull::doDispatch(Cursor & cur, FuncRequest & cmd)
                // just swallow this
                break;
 
-       case LFUN_NEW_LINE:
+       case LFUN_NEWLINE_INSERT:
                // some magic for the common case
                if (type_ == hullSimple || type_ == hullEquation) {
                        cur.recordUndoInset();
@@ -1149,7 +1257,7 @@ void InsetMathHull::doDispatch(Cursor & cur, FuncRequest & cmd)
                else
                        for (row_type row = 0; row < nrows(); ++row)
                                numbered(row, !old);
-               
+
                cur.message(old ? _("No number") : _("Number"));
                break;
        }
@@ -1174,7 +1282,7 @@ void InsetMathHull::doDispatch(Cursor & cur, FuncRequest & cmd)
 
                InsetCommandParams p(LABEL_CODE);
                p["name"] = cmd.argument().empty() ? old_label : cmd.argument();
-               string const data = InsetCommandMailer::params2string("label", p);
+               string const data = InsetCommand::params2string("label", p);
 
                if (cmd.argument().empty())
                        cur.bv().showDialog("label", data);
@@ -1185,10 +1293,36 @@ void InsetMathHull::doDispatch(Cursor & cur, FuncRequest & cmd)
                break;
        }
 
+       case LFUN_LABEL_COPY_AS_REF: {
+               row_type row;
+               if (cmd.argument().empty() && &cur.inset() == this)
+                       // if there is no argument and we're inside math, we retrieve
+                       // the row number from the cursor position.
+                       row = (type_ == hullMultline) ? nrows() - 1 : cur.row();
+               else {
+                       // if there is an argument, find the corresponding label, else
+                       // check whether there is at least one label.
+                       for (row = 0; row != nrows(); ++row)
+                               if (!nonum_[row] && label_[row]
+                                         && (cmd.argument().empty() || label(row) == cmd.argument()))
+                                       break;
+               }
+
+               if (row == nrows())
+                       break;
+
+               InsetCommandParams p(REF_CODE, "ref");
+               p["reference"] = label(row);
+               cap::clearSelection();
+               cap::copyInset(cur, new InsetRef(buffer_, p), label(row));
+               break;
+       }
+
        case LFUN_WORD_DELETE_FORWARD:
        case LFUN_CHAR_DELETE_FORWARD:
                if (col(cur.idx()) + 1 == ncols()
-                   && cur.pos() == cur.lastpos()) {
+                   && cur.pos() == cur.lastpos()
+                   && !cur.selection()) {
                        if (!label(row(cur.idx())).empty()) {
                                cur.recordUndoInset();
                                label(row(cur.idx()), docstring());
@@ -1211,7 +1345,7 @@ void InsetMathHull::doDispatch(Cursor & cur, FuncRequest & cmd)
                string const name = cmd.getArg(0);
                if (name == "label") {
                        InsetCommandParams p(LABEL_CODE);
-                       InsetCommandMailer::string2params(name, to_utf8(cmd.argument()), p);
+                       InsetCommand::string2params(name, to_utf8(cmd.argument()), p);
                        docstring str = p["name"];
                        cur.recordUndoInset();
                        row_type const r = (type_ == hullMultline) ? nrows() - 1 : cur.row();
@@ -1252,7 +1386,7 @@ void InsetMathHull::doDispatch(Cursor & cur, FuncRequest & cmd)
                }
                if (cur.pos() > cur.lastpos())
                        cur.pos() = cur.lastpos();
-               
+
                // FIXME: find some more clever handling of the selection,
                // i.e. preserve it.
                cur.clearSelection();
@@ -1286,40 +1420,80 @@ bool InsetMathHull::getStatus(Cursor & cur, FuncRequest const & cmd,
        case LFUN_FINISHED_LEFT:
        case LFUN_UP:
        case LFUN_DOWN:
-       case LFUN_NEW_LINE:
+       case LFUN_NEWLINE_INSERT:
        case LFUN_MATH_EXTERN:
-       case LFUN_MATH_MUTATE:
        case LFUN_MATH_DISPLAY:
                // we handle these
-               status.enabled(true);
+               status.setEnabled(true);
                return true;
+
+       case LFUN_MATH_MUTATE: {
+               HullType ht = hullType(cmd.argument());
+               status.setOnOff(type_ == ht);
+               status.setEnabled(true);
+               return true;
+       }
+
        case LFUN_MATH_NUMBER_TOGGLE:
                // FIXME: what is the right test, this or the one of
                // LABEL_INSERT?
-               status.enabled(display());
+               status.setEnabled(display());
                status.setOnOff(numberedType());
                return true;
+
        case LFUN_MATH_NUMBER_LINE_TOGGLE: {
                // FIXME: what is the right test, this or the one of
                // LABEL_INSERT?
-               status.enabled(display());
+               bool const enable = (type_ == hullMultline)
+                       ? (nrows() - 1 == cur.row())
+                       : display() != Inline && nrows() > 1;
                row_type const r = (type_ == hullMultline) ? nrows() - 1 : cur.row();
-               status.setOnOff(numbered(r));
+               status.setEnabled(enable);
+               status.setOnOff(enable && numbered(r));
                return true;
        }
+
        case LFUN_LABEL_INSERT:
-               status.enabled(type_ != hullSimple);
+               status.setEnabled(type_ != hullSimple);
                return true;
+
+       case LFUN_LABEL_COPY_AS_REF: {
+               bool enabled = false;
+               row_type row;
+               if (cmd.argument().empty() && &cur.inset() == this) {
+                       // if there is no argument and we're inside math, we retrieve
+                       // the row number from the cursor position.
+                       row = (type_ == hullMultline) ? nrows() - 1 : cur.row();
+                       enabled = numberedType() && label_[row] && !nonum_[row];
+               } else {
+                       // if there is an argument, find the corresponding label, else
+                       // check whether there is at least one label.
+                       for (row_type row = 0; row != nrows(); ++row) {
+                               if (!nonum_[row] && label_[row] && 
+                                       (cmd.argument().empty() || label(row) == cmd.argument())) {
+                                               enabled = true;
+                                               break;
+                               }
+                       }
+               }
+               status.setEnabled(enabled);
+               return true;
+       }
+
        case LFUN_INSET_INSERT:
                if (cmd.getArg(0) == "label") {
-                       status.enabled(type_ != hullSimple);
+                       status.setEnabled(type_ != hullSimple);
                        return true;
                }
                return InsetMathGrid::getStatus(cur, cmd, status);
-       case LFUN_TABULAR_FEATURE: {
+
+       case LFUN_INSET_MODIFY: {
                istringstream is(to_utf8(cmd.argument()));
                string s;
                is >> s;
+               if (s != "tabular")
+                       return InsetMathGrid::getStatus(cur, cmd, status);
+               is >> s;
                if (!rowChangeOK()
                    && (s == "append-row"
                        || s == "delete-row"
@@ -1327,7 +1501,7 @@ bool InsetMathHull::getStatus(Cursor & cur, FuncRequest const & cmd,
                        status.message(bformat(
                                from_utf8(N_("Can't change number of rows in '%1$s'")),
                                hullName(type_)));
-                       status.enabled(false);
+                       status.setEnabled(false);
                        return true;
                }
                if (!colChangeOK()
@@ -1337,7 +1511,7 @@ bool InsetMathHull::getStatus(Cursor & cur, FuncRequest const & cmd,
                        status.message(bformat(
                                from_utf8(N_("Can't change number of columns in '%1$s'")),
                                hullName(type_)));
-                       status.enabled(false);
+                       status.setEnabled(false);
                        return true;
                }
                if ((type_ == hullSimple
@@ -1347,24 +1521,25 @@ bool InsetMathHull::getStatus(Cursor & cur, FuncRequest const & cmd,
                        status.message(bformat(
                                from_utf8(N_("Can't add horizontal grid lines in '%1$s'")),
                                hullName(type_)));
-                       status.enabled(false);
+                       status.setEnabled(false);
                        return true;
                }
                if (s == "add-vline-left" || s == "add-vline-right") {
                        status.message(bformat(
                                from_utf8(N_("Can't add vertical grid lines in '%1$s'")),
                                hullName(type_)));
-                       status.enabled(false);
+                       status.setEnabled(false);
                        return true;
                }
                if (s == "valign-top" || s == "valign-middle"
                 || s == "valign-bottom" || s == "align-left"
                 || s == "align-center" || s == "align-right") {
-                       status.enabled(false);
+                       status.setEnabled(false);
                        return true;
                }
                return InsetMathGrid::getStatus(cur, cmd, status);
        }
+
        default:
                return InsetMathGrid::getStatus(cur, cmd, status);
        }
@@ -1384,7 +1559,7 @@ void InsetMathHull::mutateToText()
 #if 0
        // translate to latex
        ostringstream os;
-       latex(NULL, os, false, false);
+       latex(os, false, false);
        string str = os.str();
 
        // insert this text
@@ -1409,7 +1584,7 @@ void InsetMathHull::handleFont(Cursor & cur, docstring const & arg,
        if (cur.inset().asInsetMath()->name() == font)
                cur.handleFont(to_utf8(font));
        else {
-               cur.handleNest(createInsetMath(font));
+               cur.handleNest(createInsetMath(font, cur.buffer()));
                cur.insert(arg);
        }
 }
@@ -1422,7 +1597,7 @@ void InsetMathHull::handleFont2(Cursor & cur, docstring const & arg)
        bool b;
        font.fromString(to_utf8(arg), b);
        if (font.fontInfo().color() != Color_inherit) {
-               MathAtom at = MathAtom(new InsetMathColor(true, font.fontInfo().color()));
+               MathAtom at = MathAtom(new InsetMathColor(buffer_, true, font.fontInfo().color()));
                cur.handleNest(at, 0);
        }
 }
@@ -1431,7 +1606,7 @@ void InsetMathHull::handleFont2(Cursor & cur, docstring const & arg)
 void InsetMathHull::edit(Cursor & cur, bool front, EntryDirection entry_from)
 {
        cur.push(*this);
-       bool enter_front = (entry_from == Inset::ENTRY_DIRECTION_LEFT || 
+       bool enter_front = (entry_from == Inset::ENTRY_DIRECTION_LEFT ||
                (entry_from == Inset::ENTRY_DIRECTION_IGNORE && front));
        enter_front ? idxFirst(cur) : idxLast(cur);
        // The inset formula dimension is not necessarily the same as the
@@ -1441,12 +1616,6 @@ void InsetMathHull::edit(Cursor & cur, bool front, EntryDirection entry_from)
 }
 
 
-docstring InsetMathHull::editMessage() const
-{
-       return _("Math editor mode");
-}
-
-
 void InsetMathHull::revealCodes(Cursor & cur) const
 {
        if (!cur.inMathed())
@@ -1459,7 +1628,7 @@ void InsetMathHull::revealCodes(Cursor & cur) const
        // translate to latex
        cur.markInsert(bv);
        ostringstream os;
-       write(NULL, os);
+       write(os);
        string str = os.str();
        cur.markErase(bv);
        string::size_type pos = 0;
@@ -1483,12 +1652,6 @@ void InsetMathHull::revealCodes(Cursor & cur) const
 }
 
 
-InsetCode InsetMathHull::lyxCode() const
-{
-       return MATH_CODE;
-}
-
-
 /////////////////////////////////////////////////////////////////////
 
 
@@ -1508,7 +1671,7 @@ bool InsetMathHull::searchForward(BufferView * bv, string const & str,
                laststr = str;
                current = ibegin(nucleus());
                ar.clear();
-               mathed_parse_cell(ar, str);
+               mathed_parse_cell(ar, str, Parse::NORMAL, &buffer());
        } else {
                increment(current);
        }
@@ -1536,7 +1699,7 @@ bool InsetMathHull::searchForward(BufferView * bv, string const & str,
 void InsetMathHull::write(ostream & os) const
 {
        odocstringstream oss;
-       WriteStream wi(oss, false, false);
+       WriteStream wi(oss, false, false, WriteStream::wsDefault);
        oss << "Formula ";
        write(wi);
        os << to_utf8(oss.str());
@@ -1546,11 +1709,21 @@ void InsetMathHull::write(ostream & os) const
 void InsetMathHull::read(Lexer & lex)
 {
        MathAtom at;
-       mathed_parse_normal(at, lex);
+       mathed_parse_normal(buffer_, at, lex, Parse::TRACKMACRO);
        operator=(*at->asHullInset());
 }
 
 
+bool InsetMathHull::readQuiet(Lexer & lex)
+{
+       MathAtom at;
+       bool success = mathed_parse_normal(buffer_, at, lex, Parse::QUIET);
+       if (success)
+               operator=(*at->asHullInset());
+       return success;
+}
+
+
 int InsetMathHull::plaintext(odocstream & os, OutputParams const &) const
 {
        if (0 && display()) {
@@ -1565,9 +1738,13 @@ int InsetMathHull::plaintext(odocstream & os, OutputParams const &) const
                return tpain.textheight();
        } else {
                odocstringstream oss;
-               WriteStream wi(oss, false, true);
-               wi << cell(0);
-
+               Encoding const * const enc = encodings.fromLyXName("utf8");
+               WriteStream wi(oss, false, true, WriteStream::wsDefault, enc);
+               // Fix Bug #6139
+               if (type_ == hullRegexp)
+                       write(wi);
+               else
+                       wi << cell(0);
                docstring const str = oss.str();
                os << str;
                return str.size();
@@ -1597,7 +1774,7 @@ int InsetMathHull::docbook(odocstream & os, OutputParams const & runparams) cons
                // Workaround for db2latex: db2latex always includes equations with
                // \ensuremath{} or \begin{display}\end{display}
                // so we strip LyX' math environment
-               WriteStream wi(ls, false, false);
+               WriteStream wi(ls, false, false, WriteStream::wsDefault, runparams.encoding);
                InsetMathGrid::write(wi);
                ms << from_utf8(subst(subst(to_utf8(ls.str()), "&", "&amp;"), "<", "&lt;"));
                ms << ETag("alt");
@@ -1630,7 +1807,21 @@ int InsetMathHull::docbook(odocstream & os, OutputParams const & runparams) cons
 }
 
 
-void InsetMathHull::textString(odocstream & os) const
+docstring InsetMathHull::xhtml(XHTMLStream & xs, OutputParams const &) const
+{
+       if (getType() == hullSimple)
+               xs << html::StartTag("math", "xmlns=\"http://www.w3.org/1998/Math/MathML\"", true);
+       else 
+               xs << html::StartTag("math", 
+                       "display=\"block\" xmlns=\"http://www.w3.org/1998/Math/MathML\"", true);
+       MathStream ms(xs.os());
+       InsetMathGrid::mathmlize(ms);
+       xs << html::EndTag("math");
+       return docstring();
+}
+
+
+void InsetMathHull::tocString(odocstream & os) const
 {
        plaintext(os, OutputParams(0));
 }