]> git.lyx.org Git - lyx.git/blobdiff - src/mathed/InsetMathNest.cpp
listerrors.lyx : Update a link.
[lyx.git] / src / mathed / InsetMathNest.cpp
index 2aad5c93edfcfbd7ce9ef2820a758bac8dfd322e..78097f555445236a72d5b1958714b00bf9f9a174 100644 (file)
 #include "InsetMathNest.h"
 
 #include "InsetMathArray.h"
+#include "InsetMathAMSArray.h"
 #include "InsetMathBig.h"
 #include "InsetMathBox.h"
 #include "InsetMathBrace.h"
+#include "InsetMathChar.h"
 #include "InsetMathColor.h"
 #include "InsetMathComment.h"
 #include "InsetMathDelim.h"
+#include "InsetMathEnsureMath.h"
 #include "InsetMathHull.h"
 #include "InsetMathRef.h"
 #include "InsetMathScript.h"
 #include "Cursor.h"
 #include "CutAndPaste.h"
 #include "DispatchResult.h"
+#include "Encoding.h"
 #include "FuncRequest.h"
 #include "FuncStatus.h"
-#include "LyXFunc.h"
+#include "LyX.h"
 #include "LyXRC.h"
 #include "OutputParams.h"
 #include "Text.h"
@@ -75,27 +79,49 @@ using cap::replaceSelection;
 using cap::selClearOrDel;
 
 
-InsetMathNest::InsetMathNest(idx_type nargs)
-       : cells_(nargs), lock_(false), mouse_hover_(false)
-{}
+InsetMathNest::InsetMathNest(Buffer * buf, idx_type nargs)
+       : InsetMath(buf), cells_(nargs), lock_(false)
+{
+       setBuffer(*buf);
+}
 
 
 InsetMathNest::InsetMathNest(InsetMathNest const & inset)
-       : InsetMath(inset), cells_(inset.cells_), lock_(inset.lock_),
-         mouse_hover_(false)
+       : InsetMath(inset), cells_(inset.cells_), lock_(inset.lock_)
 {}
 
 
+InsetMathNest::~InsetMathNest()
+{
+       map<BufferView const *, bool>::iterator it = mouse_hover_.begin();
+       map<BufferView const *, bool>::iterator end = mouse_hover_.end();
+       for (; it != end; ++it)
+               if (it->second)
+                       it->first->clearLastInset(this);
+}
+
+
 InsetMathNest & InsetMathNest::operator=(InsetMathNest const & inset)
 {
        cells_ = inset.cells_;
        lock_ = inset.lock_;
-       mouse_hover_ = false;
+       mouse_hover_.clear();
        InsetMath::operator=(inset);
        return *this;
 }
 
 
+void InsetMathNest::setBuffer(Buffer & buffer)
+{
+       InsetMath::setBuffer(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);
+       }
+}
+
+
 InsetMath::idx_type InsetMathNest::nargs() const
 {
        return cells_.size();
@@ -156,6 +182,14 @@ void InsetMathNest::metrics(MetricsInfo const & mi) const
 }
 
 
+void InsetMathNest::updateBuffer(ParIterator const & it, UpdateType utype)
+{
+       for (idx_type i = 0, n = nargs(); i != n; ++i)
+               cell(i).updateBuffer(it, utype);
+}
+
+
+
 bool InsetMathNest::idxNext(Cursor & cur) const
 {
        LASSERT(&cur.inset() == this, /**/);
@@ -337,7 +371,8 @@ MathData InsetMathNest::glue() const
 
 void InsetMathNest::write(WriteStream & os) const
 {
-       ModeSpecifier specifier(os, currentMode());
+       MathEnsurer ensurer(os, currentMode() == MATH_MODE);
+       ModeSpecifier specifier(os, currentMode(), lockedMode());
        docstring const latex_name = name();
        os << '\\' << latex_name;
        for (size_t i = 0; i < nargs(); ++i)
@@ -360,18 +395,29 @@ void InsetMathNest::normalize(NormalStream & os) const
 }
 
 
-int InsetMathNest::latex(odocstream & os, OutputParams const & runparams) const
+void InsetMathNest::latex(otexstream & os, OutputParams const & runparams) const
 {
-       WriteStream wi(os, runparams.moving_arg, true, runparams.dryrun,
-                       runparams.encoding);
+       WriteStream wi(os.os(), runparams.moving_arg, true,
+                      runparams.dryrun ? WriteStream::wsDryrun : WriteStream::wsDefault,
+                      runparams.encoding);
+       wi.canBreakLine(os.canBreakLine());
        write(wi);
-       return wi.line();
+       os.canBreakLine(wi.canBreakLine());
+
+       int lf = wi.line();
+       if (lf > 0 && runparams.lastid != -1) {
+               --lf;
+               os.texrow().newline();
+               os.texrow().start(runparams.lastid, runparams.lastpos);
+       }
+       os.texrow().newlines(lf);
 }
 
 
-bool InsetMathNest::setMouseHover(bool mouse_hover)
+bool InsetMathNest::setMouseHover(BufferView const * bv, bool mouse_hover)
+       const
 {
-       mouse_hover_ = mouse_hover;
+       mouse_hover_[bv] = mouse_hover;
        return true;
 }
 
@@ -424,7 +470,7 @@ void InsetMathNest::handleFont(Cursor & cur, docstring const & arg,
        if (cur.inset().asInsetMath()->name() == font)
                cur.handleFont(to_utf8(font));
        else
-               handleNest(cur, createInsetMath(font), arg);
+               handleNest(cur, createInsetMath(font, cur.buffer()), arg);
 }
 
 
@@ -504,7 +550,7 @@ void InsetMathNest::handleFont2(Cursor & cur, docstring const & arg)
        font.fromString(to_utf8(arg), b);
        if (font.fontInfo().color() != Color_inherit &&
            font.fontInfo().color() != Color_ignore)
-               handleNest(cur, MathAtom(new InsetMathColor(true, font.fontInfo().color())));
+               handleNest(cur, MathAtom(new InsetMathColor(buffer_, true, font.fontInfo().color())));
 
        // FIXME: support other font changes here as well?
 }
@@ -512,17 +558,18 @@ void InsetMathNest::handleFont2(Cursor & cur, docstring const & arg)
 
 void InsetMathNest::doDispatch(Cursor & cur, FuncRequest & cmd)
 {
-       //lyxerr << "InsetMathNest: request: " << cmd << endl;
+       //LYXERR0("InsetMathNest: request: " << cmd);
 
-       Parse::flags parseflg = Parse::QUIET;
+       Parse::flags parseflg = Parse::QUIET | Parse::USETEXT;
 
-       switch (cmd.action) {
+       FuncCode const act = cmd.action();
+       switch (act) {
 
        case LFUN_CLIPBOARD_PASTE:
                parseflg |= Parse::VERBATIM;
                // fall through
        case LFUN_PASTE: {
-               if (cur.currentMode() == TEXT_MODE)
+               if (cur.currentMode() <= TEXT_MODE)
                        parseflg |= Parse::TEXTMODE;
                cur.recordUndoSelection();
                cur.message(_("Paste"));
@@ -536,8 +583,9 @@ void InsetMathNest::doDispatch(Cursor & cur, FuncRequest & cmd)
                        is >> n;
                        topaste = cap::selection(n);
                }
-               cur.niceInsert(topaste, parseflg);
+               cur.niceInsert(topaste, parseflg, false);
                cur.clearSelection(); // bug 393
+               cur.forceBufferUpdate();
                cur.finishUndo();
                break;
        }
@@ -549,6 +597,7 @@ void InsetMathNest::doDispatch(Cursor & cur, FuncRequest & cmd)
                // Prevent stale position >= size crash
                // Probably not necessary anymore, see eraseSelection (gb 2005-10-09)
                cur.normalize();
+               cur.forceBufferUpdate();
                break;
 
        case LFUN_COPY:
@@ -583,16 +632,16 @@ void InsetMathNest::doDispatch(Cursor & cur, FuncRequest & cmd)
        case LFUN_CHAR_LEFT:
        case LFUN_CHAR_BACKWARD:
        case LFUN_CHAR_FORWARD:
-               cur.updateFlags(Update::Decoration | Update::FitCursor);
+               cur.screenUpdateFlags(Update::Decoration | Update::FitCursor);
        case LFUN_CHAR_RIGHT_SELECT:
        case LFUN_CHAR_LEFT_SELECT:
        case LFUN_CHAR_BACKWARD_SELECT:
        case LFUN_CHAR_FORWARD_SELECT: {
                // are we in a selection?
-               bool select = (cmd.action == LFUN_CHAR_RIGHT_SELECT
-                                          || cmd.action == LFUN_CHAR_LEFT_SELECT
-                                          || cmd.action == LFUN_CHAR_BACKWARD_SELECT
-                                          || cmd.action == LFUN_CHAR_FORWARD_SELECT);
+               bool select = (act == LFUN_CHAR_RIGHT_SELECT
+                                          || act == LFUN_CHAR_LEFT_SELECT
+                                          || act == LFUN_CHAR_BACKWARD_SELECT
+                                          || act == LFUN_CHAR_FORWARD_SELECT);
                // are we moving forward or backwards?
                // If the command was RIGHT or LEFT, then whether we're moving forward
                // or backwards depends on the cursor movement mode (logical or visual):
@@ -604,19 +653,19 @@ void InsetMathNest::doDispatch(Cursor & cur, FuncRequest & cmd)
                bool forward;
                FuncCode finish_lfun;
 
-               if (cmd.action == LFUN_CHAR_FORWARD
-                               || cmd.action == LFUN_CHAR_FORWARD_SELECT) {
+               if (act == LFUN_CHAR_FORWARD
+                               || act == LFUN_CHAR_FORWARD_SELECT) {
                        forward = true;
                        finish_lfun = LFUN_FINISHED_FORWARD;
                }
-               else if (cmd.action == LFUN_CHAR_BACKWARD
-                               || cmd.action == LFUN_CHAR_BACKWARD_SELECT) {
+               else if (act == LFUN_CHAR_BACKWARD
+                               || act == LFUN_CHAR_BACKWARD_SELECT) {
                        forward = false;
                        finish_lfun = LFUN_FINISHED_BACKWARD;
                }
                else {
-                       bool right = (cmd.action == LFUN_CHAR_RIGHT_SELECT
-                                                 || cmd.action == LFUN_CHAR_RIGHT);
+                       bool right = (act == LFUN_CHAR_RIGHT_SELECT
+                                                 || act == LFUN_CHAR_RIGHT);
                        if (lyxrc.visual_cursor || !reverseDirectionNeeded(cur))
                                forward = right;
                        else
@@ -643,7 +692,7 @@ void InsetMathNest::doDispatch(Cursor & cur, FuncRequest & cmd)
 
        case LFUN_DOWN:
        case LFUN_UP:
-               cur.updateFlags(Update::Decoration | Update::FitCursor);
+               cur.screenUpdateFlags(Update::Decoration | Update::FitCursor);
        case LFUN_DOWN_SELECT:
        case LFUN_UP_SELECT: {
                // close active macro
@@ -653,12 +702,12 @@ void InsetMathNest::doDispatch(Cursor & cur, FuncRequest & cmd)
                }
 
                // stop/start the selection
-               bool select = cmd.action == LFUN_DOWN_SELECT ||
-                       cmd.action == LFUN_UP_SELECT;
+               bool select = act == LFUN_DOWN_SELECT ||
+                       act == LFUN_UP_SELECT;
                cur.selHandle(select);
 
                // go up/down
-               bool up = cmd.action == LFUN_UP || cmd.action == LFUN_UP_SELECT;
+               bool up = act == LFUN_UP || act == LFUN_UP_SELECT;
                bool successful = cur.upDownInMath(up);
                if (successful)
                        break;
@@ -686,7 +735,7 @@ void InsetMathNest::doDispatch(Cursor & cur, FuncRequest & cmd)
 
        case LFUN_PARAGRAPH_UP:
        case LFUN_PARAGRAPH_DOWN:
-               cur.updateFlags(Update::Decoration | Update::FitCursor);
+               cur.screenUpdateFlags(Update::Decoration | Update::FitCursor);
        case LFUN_PARAGRAPH_UP_SELECT:
        case LFUN_PARAGRAPH_DOWN_SELECT:
                break;
@@ -694,13 +743,13 @@ void InsetMathNest::doDispatch(Cursor & cur, FuncRequest & cmd)
        case LFUN_LINE_BEGIN:
        case LFUN_WORD_BACKWARD:
        case LFUN_WORD_LEFT:
-               cur.updateFlags(Update::Decoration | Update::FitCursor);
+               cur.screenUpdateFlags(Update::Decoration | Update::FitCursor);
        case LFUN_LINE_BEGIN_SELECT:
        case LFUN_WORD_BACKWARD_SELECT:
        case LFUN_WORD_LEFT_SELECT:
-               cur.selHandle(cmd.action == LFUN_WORD_BACKWARD_SELECT ||
-                               cmd.action == LFUN_WORD_LEFT_SELECT ||
-                               cmd.action == LFUN_LINE_BEGIN_SELECT);
+               cur.selHandle(act == LFUN_WORD_BACKWARD_SELECT ||
+                               act == LFUN_WORD_LEFT_SELECT ||
+                               act == LFUN_LINE_BEGIN_SELECT);
                cur.macroModeClose();
                if (cur.pos() != 0) {
                        cur.pos() = 0;
@@ -719,13 +768,13 @@ void InsetMathNest::doDispatch(Cursor & cur, FuncRequest & cmd)
        case LFUN_WORD_FORWARD:
        case LFUN_WORD_RIGHT:
        case LFUN_LINE_END:
-               cur.updateFlags(Update::Decoration | Update::FitCursor);
+               cur.screenUpdateFlags(Update::Decoration | Update::FitCursor);
        case LFUN_WORD_FORWARD_SELECT:
        case LFUN_WORD_RIGHT_SELECT:
        case LFUN_LINE_END_SELECT:
-               cur.selHandle(cmd.action == LFUN_WORD_FORWARD_SELECT ||
-                               cmd.action == LFUN_WORD_RIGHT_SELECT ||
-                               cmd.action == LFUN_LINE_END_SELECT);
+               cur.selHandle(act == LFUN_WORD_FORWARD_SELECT ||
+                               act == LFUN_WORD_RIGHT_SELECT ||
+                               act == LFUN_LINE_END_SELECT);
                cur.macroModeClose();
                cur.clearTargetX();
                if (cur.pos() != cur.lastpos()) {
@@ -743,12 +792,12 @@ void InsetMathNest::doDispatch(Cursor & cur, FuncRequest & cmd)
                break;
 
        case LFUN_CELL_FORWARD:
-               cur.updateFlags(Update::Decoration | Update::FitCursor);
+               cur.screenUpdateFlags(Update::Decoration | Update::FitCursor);
                cur.inset().idxNext(cur);
                break;
 
        case LFUN_CELL_BACKWARD:
-               cur.updateFlags(Update::Decoration | Update::FitCursor);
+               cur.screenUpdateFlags(Update::Decoration | Update::FitCursor);
                cur.inset().idxPrev(cur);
                break;
 
@@ -805,7 +854,7 @@ void InsetMathNest::doDispatch(Cursor & cur, FuncRequest & cmd)
                                cur.insert(arg);
                        break;
                }
-               // Don't record undo steps if we are in macro mode and
+               // Don't record undo steps if we are in macro mode and thus
                // cmd.argument is the next character of the macro name.
                // Otherwise we'll get an invalid cursor if we undo after
                // the macro was finished and the macro is a known command,
@@ -814,6 +863,7 @@ void InsetMathNest::doDispatch(Cursor & cur, FuncRequest & cmd)
                // InsetMathFrac -> a pos value > 0 is invalid.
                // A side effect is that an undo before the macro is finished
                // undoes the complete macro, not only the last character.
+               // At the time we hit '\' we are not in macro mode, still.
                if (!cur.inMacroMode())
                        cur.recordUndoSelection();
 
@@ -881,37 +931,37 @@ void InsetMathNest::doDispatch(Cursor & cur, FuncRequest & cmd)
                break;
 
        case LFUN_FONT_BOLD:
-               if (currentMode() == TEXT_MODE)
+               if (currentMode() <= TEXT_MODE)
                        handleFont(cur, cmd.argument(), "textbf");
                else
                        handleFont(cur, cmd.argument(), "mathbf");
                break;
        case LFUN_FONT_BOLDSYMBOL:
-               if (currentMode() == TEXT_MODE)
+               if (currentMode() <= TEXT_MODE)
                        handleFont(cur, cmd.argument(), "textbf");
                else
                        handleFont(cur, cmd.argument(), "boldsymbol");
                break;
        case LFUN_FONT_SANS:
-               if (currentMode() == TEXT_MODE)
+               if (currentMode() <= TEXT_MODE)
                        handleFont(cur, cmd.argument(), "textsf");
                else
                        handleFont(cur, cmd.argument(), "mathsf");
                break;
        case LFUN_FONT_EMPH:
-               if (currentMode() == TEXT_MODE)
+               if (currentMode() <= TEXT_MODE)
                        handleFont(cur, cmd.argument(), "emph");
                else
                        handleFont(cur, cmd.argument(), "mathcal");
                break;
        case LFUN_FONT_ROMAN:
-               if (currentMode() == TEXT_MODE)
+               if (currentMode() <= TEXT_MODE)
                        handleFont(cur, cmd.argument(), "textrm");
                else
                        handleFont(cur, cmd.argument(), "mathrm");
                break;
        case LFUN_FONT_TYPEWRITER:
-               if (currentMode() == TEXT_MODE)
+               if (currentMode() <= TEXT_MODE)
                        handleFont(cur, cmd.argument(), "texttt");
                else
                        handleFont(cur, cmd.argument(), "mathtt");
@@ -920,13 +970,13 @@ void InsetMathNest::doDispatch(Cursor & cur, FuncRequest & cmd)
                handleFont(cur, cmd.argument(), "mathfrak");
                break;
        case LFUN_FONT_ITAL:
-               if (currentMode() == TEXT_MODE)
+               if (currentMode() <= TEXT_MODE)
                        handleFont(cur, cmd.argument(), "textit");
                else
                        handleFont(cur, cmd.argument(), "mathit");
                break;
        case LFUN_FONT_NOUN:
-               if (currentMode() == TEXT_MODE)
+               if (currentMode() <= TEXT_MODE)
                        // FIXME: should be "noun"
                        handleFont(cur, cmd.argument(), "textsc");
                else
@@ -936,6 +986,10 @@ void InsetMathNest::doDispatch(Cursor & cur, FuncRequest & cmd)
                handleFont(cur, cmd.argument(), "textnormal");
                break;
 
+       case LFUN_FONT_UNDERLINE:
+               cur.recordUndo();
+               cur.handleNest(createInsetMath("underline", cur.buffer()));
+               break;
        case LFUN_MATH_MODE: {
 #if 1
                // ignore math-mode on when already in math mode
@@ -946,14 +1000,18 @@ void InsetMathNest::doDispatch(Cursor & cur, FuncRequest & cmd)
                docstring const save_selection = grabAndEraseSelection(cur);
                selClearOrDel(cur);
                //cur.plainInsert(MathAtom(new InsetMathMBox(cur.bv())));
-               cur.plainInsert(MathAtom(new InsetMathBox(from_ascii("mbox"))));
+               if (currentMode() <= Inset::TEXT_MODE)
+                       cur.plainInsert(MathAtom(new InsetMathEnsureMath(buffer_)));
+               else
+                       cur.plainInsert(MathAtom(new InsetMathBox(buffer_, from_ascii("mbox"))));
                cur.posBackward();
                cur.pushBackward(*cur.nextInset());
                cur.niceInsert(save_selection);
+               cur.forceBufferUpdate();
 #else
                if (currentMode() == Inset::TEXT_MODE) {
                        cur.recordUndoSelection();
-                       cur.niceInsert(MathAtom(new InsetMathHull("simple")));
+                       cur.niceInsert(MathAtom(new InsetMathHull("simple", cur.buffer())));
                        cur.message(_("create new math text environment ($...$)"));
                } else {
                        handleFont(cur, cmd.argument(), "textrm");
@@ -964,19 +1022,28 @@ void InsetMathNest::doDispatch(Cursor & cur, FuncRequest & cmd)
        }
 
        case LFUN_REGEXP_MODE: {
-               InsetMathHull * i = dynamic_cast<InsetMathHull *>(cur.inset().asInsetMath());
-               if (i && i->getType() == hullRegexp) {
-                       cur.message(_("Already in regexp mode"));
-                       break;
+               InsetMath * im = cur.inset().asInsetMath();
+               if (im) {
+                       InsetMathHull * i = im->asHullInset();          
+                       if (i && i->getType() == hullRegexp) {
+                               cur.message(_("Already in regular expression mode"));
+                               break;
+                       }
                }
                cur.macroModeClose();
                docstring const save_selection = grabAndEraseSelection(cur);
                selClearOrDel(cur);
-               cur.plainInsert(MathAtom(new InsetMathHull(hullRegexp)));
+               cur.plainInsert(MathAtom(new InsetMathHull(buffer_, hullRegexp)));
                cur.posBackward();
                cur.pushBackward(*cur.nextInset());
                cur.niceInsert(save_selection);
-               cur.message(_("Regexp editor mode"));
+               cur.message(_("Regular expression editor mode"));
+               break;
+       }
+
+       case LFUN_MATH_FONT_STYLE: {
+               FuncRequest fr = FuncRequest(LFUN_MATH_INSERT, '\\' + cmd.argument());
+               doDispatch(cur, fr);
                break;
        }
 
@@ -999,8 +1066,24 @@ void InsetMathNest::doDispatch(Cursor & cur, FuncRequest & cmd)
                if (n < 1)
                        n = 1;
                v_align += 'c';
+               cur.niceInsert(MathAtom(new InsetMathArray(buffer_,
+                       from_ascii("array"), m, n, (char)v_align[0], h_align)));
+               break;
+       }
+
+       case LFUN_MATH_AMS_MATRIX: {
+               cur.recordUndo();
+               unsigned int m = 1;
+               unsigned int n = 1;
+               docstring name;
+               idocstringstream is(cmd.argument());
+               is >> m >> n >> name;
+               if (m < 1)
+                       m = 1;
+               if (n < 1)
+                       n = 1;
                cur.niceInsert(
-                       MathAtom(new InsetMathArray(from_ascii("array"), m, n, (char)v_align[0], h_align)));
+                       MathAtom(new InsetMathAMSArray(buffer_, name, m, n)));
                break;
        }
 
@@ -1013,7 +1096,7 @@ void InsetMathNest::doDispatch(Cursor & cur, FuncRequest & cmd)
                if (rs.empty())
                        rs = ')';
                cur.recordUndo();
-               cur.handleNest(MathAtom(new InsetMathDelim(ls, rs)));
+               cur.handleNest(MathAtom(new InsetMathDelim(buffer_, ls, rs)));
                break;
        }
 
@@ -1037,20 +1120,48 @@ void InsetMathNest::doDispatch(Cursor & cur, FuncRequest & cmd)
                        if (have_l)
                                cur.insert(MathAtom(new InsetMathBig(lname,
                                                                ldelim)));
-                       cur.niceInsert(selection);
-                       if (have_r)
+                       // first insert the right delimiter and then go back
+                       // and re-insert the selection (bug 7088)
+                       if (have_r) {
                                cur.insert(MathAtom(new InsetMathBig(rname,
                                                                rdelim)));
+                               cur.posBackward();
+                       }
+                       cur.niceInsert(selection);
                }
                // Don't call cur.undispatched() if we did nothing, this would
                // lead to infinite recursion via Text::dispatch().
                break;
        }
 
-       case LFUN_SPACE_INSERT:
+       case LFUN_SPACE_INSERT: {
                cur.recordUndoSelection();
-               cur.insert(MathAtom(new InsetMathSpace));
+               string const name = cmd.getArg(0);
+               if (name == "normal")
+                       cur.insert(MathAtom(new InsetMathSpace(" ", "")));
+               else if (name == "protected")
+                       cur.insert(MathAtom(new InsetMathSpace("~", "")));
+               else if (name == "thin" || name == "med" || name == "thick")
+                       cur.insert(MathAtom(new InsetMathSpace(name + "space", "")));
+               else if (name == "hfill*")
+                       cur.insert(MathAtom(new InsetMathSpace("hspace*{\\fill}", "")));
+               else if (name == "quad" || name == "qquad" ||
+                        name == "enspace" || name == "enskip" ||
+                        name == "negthinspace" || name == "negmedspace" ||
+                        name == "negthickspace" || name == "hfill")
+                       cur.insert(MathAtom(new InsetMathSpace(name, "")));
+               else if (name == "hspace" || name == "hspace*") {
+                       string const len = cmd.getArg(1);
+                       if (len.empty() || !isValidLength(len)) {
+                               lyxerr << "LyX function 'space-insert " << name << "' "
+                                         "needs a valid length argument." << endl;
+                               break;
+                       }
+                       cur.insert(MathAtom(new InsetMathSpace(name, len)));
+               } else
+                       cur.insert(MathAtom(new InsetMathSpace));
                break;
+       }
 
        case LFUN_MATH_SPACE:
                cur.recordUndoSelection();
@@ -1084,7 +1195,7 @@ void InsetMathNest::doDispatch(Cursor & cur, FuncRequest & cmd)
        case LFUN_MATH_MACRO_FOLD:
        case LFUN_MATH_MACRO_UNFOLD: {
                Cursor it = cur;
-               bool fold = cmd.action == LFUN_MATH_MACRO_FOLD;
+               bool fold = act == LFUN_MATH_MACRO_FOLD;
                bool found = findMacroToFoldUnfold(it, fold);
                if (found) {
                        MathMacro * macro = it.nextInset()->asInsetMath()->asMacro();
@@ -1113,26 +1224,42 @@ void InsetMathNest::doDispatch(Cursor & cur, FuncRequest & cmd)
                else {
                        MathData ar;
                        asArray(cmd.argument(), ar);
-                       if (ar.size() == 1 && ar[0]->asNestInset()
-                                       && ar[0]->asNestInset()->nargs() > 1)
+                       if (cur.selection() && ar.size() == 1
+                           && ar[0]->asNestInset()
+                           && ar[0]->asNestInset()->nargs() > 1)
                                handleNest(cur, ar[0]);
                        else
                                cur.niceInsert(cmd.argument());
                }
                break;
+       }
+
+       case LFUN_UNICODE_INSERT: {
+               if (cmd.argument().empty())
+                       break;
+               docstring hexstring = cmd.argument();
+               if (isHex(hexstring)) {
+                       char_type c = hexToInt(hexstring);
+                       if (c >= 32 && c < 0x10ffff) {
+                               docstring s = docstring(1, c);
+                               FuncCode code = currentMode() == MATH_MODE ?
+                                       LFUN_MATH_INSERT : LFUN_SELF_INSERT;
+                               lyx::dispatch(FuncRequest(code, s));
+                       }
                }
+               break;
+       }
 
        case LFUN_DIALOG_SHOW_NEW_INSET: {
                docstring const & name = cmd.argument();
                string data;
                if (name == "ref") {
-                       InsetMathRef tmp(name);
-                       data = tmp.createDialogStr(to_utf8(name));
-               } else if (name == "mathspace") {
-                       InsetMathSpace tmp;
+                       InsetMathRef tmp(buffer_, name);
                        data = tmp.createDialogStr();
+                       cur.bv().showDialog(to_utf8(name), data);
+               } else if (name == "mathspace") {
+                       cur.bv().showDialog(to_utf8(name));
                }
-               cur.bv().showDialog(to_utf8(name), data);
                break;
        }
 
@@ -1141,6 +1268,7 @@ void InsetMathNest::doDispatch(Cursor & cur, FuncRequest & cmd)
                if (createInsetMath_fromDialogStr(cmd.argument(), ar)) {
                        cur.recordUndoSelection();
                        cur.insert(ar);
+                       cur.forceBufferUpdate();                        
                } else
                        cur.undispatched();
                break;
@@ -1200,12 +1328,12 @@ bool InsetMathNest::getStatus(Cursor & cur, FuncRequest const & cmd,
        //string tc = "mathnormal";
        bool ret = true;
        string const arg = to_utf8(cmd.argument());
-       switch (cmd.action) {
-       case LFUN_TABULAR_FEATURE:
+       switch (cmd.action()) {
+       case LFUN_INSET_MODIFY:
                flag.setEnabled(false);
                break;
 #if 0
-       case LFUN_TABULAR_FEATURE:
+       case LFUN_INSET_MODIFY:
                // FIXME: check temporarily disabled
                // valign code
                char align = mathcursor::valign();
@@ -1236,10 +1364,6 @@ bool InsetMathNest::getStatus(Cursor & cur, FuncRequest const & cmd,
        case LFUN_FONT_DEFAULT:
                flag.setEnabled(true);
                break;
-       case LFUN_MATH_MUTATE:
-               //flag.setOnOff(mathcursor::formula()->hullType() == to_utf8(cmd.argument()));
-               flag.setOnOff(false);
-               break;
 
        // we just need to be in math mode to enable that
        case LFUN_MATH_SIZE:
@@ -1249,22 +1373,34 @@ bool InsetMathNest::getStatus(Cursor & cur, FuncRequest const & cmd,
                flag.setEnabled(true);
                break;
 
+       case LFUN_FONT_UNDERLINE:
        case LFUN_FONT_FRAK:
                flag.setEnabled(currentMode() != TEXT_MODE);
                break;
 
-       case LFUN_MATH_INSERT: {
+       case LFUN_MATH_FONT_STYLE: {
                bool const textarg =
-                       arg == "\\textbf"   || arg == "\\textsf" ||
-                       arg == "\\textrm"   || arg == "\\textmd" ||
-                       arg == "\\textit"   || arg == "\\textsc" ||
-                       arg == "\\textsl"   || arg == "\\textup" ||
-                       arg == "\\texttt"   || arg == "\\textbb" ||
-                       arg == "\\textnormal";
+                       arg == "textbf"   || arg == "textsf" ||
+                       arg == "textrm"   || arg == "textmd" ||
+                       arg == "textit"   || arg == "textsc" ||
+                       arg == "textsl"   || arg == "textup" ||
+                       arg == "texttt"   || arg == "textbb" ||
+                       arg == "textnormal";
                flag.setEnabled(currentMode() != TEXT_MODE || textarg);
                break;
        }
 
+       case LFUN_MATH_MODE:
+               // forbid "math-mode on" in math mode to prevent irritating
+               // behaviour of menu entries (bug 6709)
+               flag.setEnabled(currentMode() == TEXT_MODE || arg != "on");
+               break;
+
+       case LFUN_MATH_INSERT:
+               flag.setEnabled(currentMode() != TEXT_MODE);
+               break;
+
+       case LFUN_MATH_AMS_MATRIX:
        case LFUN_MATH_MATRIX:
                flag.setEnabled(currentMode() == MATH_MODE);
                break;
@@ -1278,6 +1414,14 @@ bool InsetMathNest::getStatus(Cursor & cur, FuncRequest const & cmd,
                break;
        }
 
+       case LFUN_DIALOG_SHOW_NEW_INSET: {
+               docstring const & name = cmd.argument();
+               if (name == "space")
+                       flag.setEnabled(false);
+               break;
+       }
+
+
        case LFUN_MATH_DELIM:
        case LFUN_MATH_BIGDELIM:
                // Don't do this with multi-cell selections
@@ -1287,16 +1431,24 @@ bool InsetMathNest::getStatus(Cursor & cur, FuncRequest const & cmd,
        case LFUN_MATH_MACRO_FOLD:
        case LFUN_MATH_MACRO_UNFOLD: {
                Cursor it = cur;
-               bool found = findMacroToFoldUnfold(it, cmd.action == LFUN_MATH_MACRO_FOLD);
+               bool found = findMacroToFoldUnfold(it, cmd.action() == LFUN_MATH_MACRO_FOLD);
                flag.setEnabled(found);
                break;
        }
 
        case LFUN_SPECIALCHAR_INSERT:
+       case LFUN_SCRIPT_INSERT:
                // FIXME: These would probably make sense in math-text mode
                flag.setEnabled(false);
                break;
 
+       case LFUN_SPACE_INSERT: {
+               docstring const & name = cmd.argument();
+               if (name == "visible")
+                       flag.setEnabled(false);
+               break;
+       }
+
        case LFUN_INSET_DISSOLVE:
                flag.setEnabled(!asHullInset());
                break;
@@ -1352,6 +1504,15 @@ void InsetMathNest::lfunMousePress(Cursor & cur, FuncRequest & cmd)
 {
        //lyxerr << "## lfunMousePress: buttons: " << cmd.button() << endl;
        BufferView & bv = cur.bv();
+       if (cmd.button() == mouse_button::button3) {
+               // Don't do anything if we right-click a
+               // selection, a context menu will popup.
+               if (bv.cursor().selection() && cur >= bv.cursor().selectionBegin()
+                     && cur < bv.cursor().selectionEnd()) {
+                       cur.noScreenUpdate();
+                       return;
+               }
+       }
        bool do_selection = cmd.button() == mouse_button::button1
                && cmd.argument() == "region-select";
        bv.mouseSetCursor(cur, do_selection);
@@ -1365,8 +1526,8 @@ void InsetMathNest::lfunMousePress(Cursor & cur, FuncRequest & cmd)
                // Update::FitCursor: adjust the screen to the cursor
                //                    position if needed
                // cur.result().update(): don't overwrite previously set flags.
-               cur.updateFlags(Update::Decoration | Update::FitCursor
-                               | cur.result().update());
+               cur.screenUpdateFlags(Update::Decoration | Update::FitCursor
+                               | cur.result().screenUpdate());
        } else if (cmd.button() == mouse_button::button2) {
                if (cap::selection()) {
                        // See comment in Text::dispatch why we do this
@@ -1387,7 +1548,7 @@ void InsetMathNest::lfunMouseMotion(Cursor & cur, FuncRequest & cmd)
        // only select with button 1
        if (cmd.button() == mouse_button::button1) {
                Cursor & bvcur = cur.bv().cursor();
-               if (bvcur.anchor_.hasPart(cur)) {
+               if (bvcur.realAnchor().hasPart(cur)) {
                        //lyxerr << "## lfunMouseMotion: cursor: " << cur << endl;
                        bvcur.setCursor(cur);
                        bvcur.setSelection(true);
@@ -1404,7 +1565,7 @@ void InsetMathNest::lfunMouseRelease(Cursor & cur, FuncRequest & cmd)
 
        if (cmd.button() == mouse_button::button1) {
                if (!cur.selection())
-                       cur.noUpdate();
+                       cur.noScreenUpdate();
                else {
                        Cursor & bvcur = cur.bv().cursor();
                        bvcur.setSelection(true);
@@ -1424,6 +1585,7 @@ bool InsetMathNest::interpretChar(Cursor & cur, char_type const c)
                save_selection = grabAndEraseSelection(cur);
 
        cur.clearTargetX();
+       Buffer * buf = cur.buffer();
 
        // handle macroMode
        if (cur.inMacroMode()) {
@@ -1453,25 +1615,25 @@ bool InsetMathNest::interpretChar(Cursor & cur, char_type const c)
                        // remove the '\\'
                        if (c == '\\') {
                                cur.backspace();
-                               if (currentMode() == InsetMath::TEXT_MODE)
-                                       cur.niceInsert(createInsetMath("textbackslash"));
+                               if (currentMode() <= InsetMath::TEXT_MODE)
+                                       cur.niceInsert(createInsetMath("textbackslash", buf));
                                else
-                                       cur.niceInsert(createInsetMath("backslash"));
+                                       cur.niceInsert(createInsetMath("backslash", buf));
                        } else if (c == '^' && currentMode() == InsetMath::MATH_MODE) {
                                cur.backspace();
-                               cur.niceInsert(createInsetMath("mathcircumflex"));
+                               cur.niceInsert(createInsetMath("mathcircumflex", buf));
                        } else if (c == '{') {
                                cur.backspace();
-                               cur.niceInsert(MathAtom(new InsetMathBrace));
+                               cur.niceInsert(MathAtom(new InsetMathBrace(buf)));
                        } else if (c == '%') {
                                cur.backspace();
-                               cur.niceInsert(MathAtom(new InsetMathComment));
+                               cur.niceInsert(MathAtom(new InsetMathComment(buf)));
                        } else if (c == '#') {
                                LASSERT(cur.activeMacro(), /**/);
                                cur.activeMacro()->setName(name + docstring(1, c));
                        } else {
                                cur.backspace();
-                               cur.niceInsert(createInsetMath(docstring(1, c)));
+                               cur.niceInsert(createInsetMath(docstring(1, c), buf));
                        }
                        return true;
                }
@@ -1507,9 +1669,15 @@ bool InsetMathNest::interpretChar(Cursor & cur, char_type const c)
                }
 
                // leave macro mode and try again if necessary
-               cur.macroModeClose();
+               if (cur.macroModeClose()) {
+                       MathAtom const atom = cur.prevAtom();
+                       if (atom->asNestInset() && atom->isActive()) {
+                               cur.posBackward();
+                               cur.pushBackward(*cur.nextInset());
+                       }
+               }
                if (c == '{')
-                       cur.niceInsert(MathAtom(new InsetMathBrace));
+                       cur.niceInsert(MathAtom(new InsetMathBrace(buf)));
                else if (c != ' ')
                        interpretChar(cur, c);
                return true;
@@ -1539,7 +1707,10 @@ bool InsetMathNest::interpretChar(Cursor & cur, char_type const c)
                bool reduced = cap::reduceSelectionToOneCell(cur);
                if (reduced || !cur.selection()) {
                        docstring const safe = cap::grabAndEraseSelection(cur);
-                       cur.insert(MathAtom(new InsetMathUnknown(from_ascii("\\"), safe, false)));
+                       if (!cur.inRegexped())
+                               cur.insert(MathAtom(new InsetMathUnknown(from_ascii("\\"), safe, false)));
+                       else
+                               cur.niceInsert(createInsetMath("backslash", buf));
                }
                return true;
        }
@@ -1547,14 +1718,14 @@ bool InsetMathNest::interpretChar(Cursor & cur, char_type const c)
        selClearOrDel(cur);
 
        if (c == '\n') {
-               if (currentMode() == InsetMath::TEXT_MODE)
+               if (currentMode() <= InsetMath::TEXT_MODE)
                        cur.insert(c);
                return true;
        }
 
        if (c == ' ') {
-               if (currentMode() == InsetMath::TEXT_MODE) {
-                       // insert spaces in text mode,
+               if (currentMode() <= InsetMath::TEXT_MODE) {
+                       // insert spaces in text or undecided mode,
                        // but suppress direct insertion of two spaces in a row
                        // the still allows typing  '<space>a<space>' and deleting the 'a', but
                        // it is better than nothing...
@@ -1564,7 +1735,7 @@ bool InsetMathNest::interpretChar(Cursor & cur, char_type const c)
                                // visual box corners that define the inset. If we know for
                                // sure that we stay within the same cell we can optimize for
                                // that using:
-                               //cur.updateFlags(Update::SinglePar | Update::FitCursor);
+                               //cur.screenUpdateFlags(Update::SinglePar | Update::FitCursor);
                        }
                        return true;
                }
@@ -1574,7 +1745,7 @@ bool InsetMathNest::interpretChar(Cursor & cur, char_type const c)
                        // visual box corners that define the inset. If we know for
                        // sure that we stay within the same cell we can optimize for
                        // that using:
-                       //cur.updateFlags(Update::SinglePar | Update::FitCursor);
+                       //cur.screenUpdateFlags(Update::SinglePar | Update::FitCursor);
                        return true;
                }
 
@@ -1583,7 +1754,7 @@ bool InsetMathNest::interpretChar(Cursor & cur, char_type const c)
                        // visual box corners that define the inset. If we know for
                        // sure that we stay within the same cell we can optimize for
                        // that using:
-                       //cur.updateFlags(Update::FitCursor);
+                       //cur.screenUpdateFlags(Update::FitCursor);
                        return true;
                }
 
@@ -1592,7 +1763,29 @@ bool InsetMathNest::interpretChar(Cursor & cur, char_type const c)
        }
 
        // These should be treated differently when not in text mode:
-       if (currentMode() != InsetMath::TEXT_MODE) {
+       if (cur.inRegexped()) {
+               switch (c) {
+               case '\\':
+                       cur.niceInsert(createInsetMath("backslash", buf));
+                       break;
+               case '^':
+                       cur.niceInsert(createInsetMath("mathcircumflex", buf));
+                       break;
+               case '{':
+               case '}':
+               case '#':
+               case '%':
+               case '_':
+                       cur.niceInsert(createInsetMath(docstring(1, c), buf));
+                       break;
+               case '~':
+                       cur.niceInsert(createInsetMath("sim", buf));
+                       break;
+               default:
+                       cur.insert(c);
+               }
+               return true;
+       } else if (currentMode() != InsetMath::TEXT_MODE) {
                if (c == '_') {
                        script(cur, false, save_selection);
                        return true;
@@ -1602,29 +1795,37 @@ bool InsetMathNest::interpretChar(Cursor & cur, char_type const c)
                        return true;
                }
                if (c == '~') {
-                       cur.niceInsert(createInsetMath("sim"));
+                       cur.niceInsert(createInsetMath("sim", buf));
+                       return true;
+               }
+               if (currentMode() == InsetMath::MATH_MODE && !isAsciiOrMathAlpha(c)) {
+                       MathAtom at = createInsetMath("text", buf);
+                       at.nucleus()->cell(0).push_back(MathAtom(new InsetMathChar(c)));
+                       cur.niceInsert(at);
+                       cur.posForward();
                        return true;
                }
        } else {
                if (c == '^') {
-                       cur.niceInsert(createInsetMath("textasciicircum"));
+                       cur.niceInsert(createInsetMath("textasciicircum", buf));
                        return true;
                }
                if (c == '~') {
-                       cur.niceInsert(createInsetMath("textasciitilde"));
+                       cur.niceInsert(createInsetMath("textasciitilde", buf));
                        return true;
                }
        }
 
        if (c == '{' || c == '}' || c == '&' || c == '$' || c == '#' ||
            c == '%' || c == '_') {
-               cur.niceInsert(createInsetMath(docstring(1, c)));
+               cur.niceInsert(createInsetMath(docstring(1, c), buf));
                return true;
        }
 
 
        // try auto-correction
-       if (lyxrc.autocorrection_math && cur.autocorrect() && cur.pos() != 0 && math_autocorrect(cur.prevAtom(), c))
+       if (lyxrc.autocorrection_math && cur.autocorrect() && cur.pos() != 0
+                 && math_autocorrect(cur.prevAtom(), c))
                return true;
 
        // no special circumstances, so insert the character without any fuss
@@ -1675,7 +1876,7 @@ bool InsetMathNest::script(Cursor & cur, bool up,
        //lyxerr << "handling script: up: " << up << endl;
        if (cur.inMacroMode() && cur.macroName() == "\\") {
                if (up)
-                       cur.niceInsert(createInsetMath("mathcircumflex"));
+                       cur.niceInsert(createInsetMath("mathcircumflex", cur.buffer()));
                else
                        interpretChar(cur, '_');
                return true;
@@ -1701,10 +1902,10 @@ bool InsetMathNest::script(Cursor & cur, bool up,
                // one if in the very first position of the array
                if (cur.pos() == 0) {
                        //lyxerr << "new scriptinset" << endl;
-                       cur.insert(new InsetMathScript(up));
+                       cur.insert(new InsetMathScript(buffer_, up));
                } else {
                        //lyxerr << "converting prev atom " << endl;
-                       cur.prevAtom() = MathAtom(new InsetMathScript(cur.prevAtom(), up));
+                       cur.prevAtom() = MathAtom(new InsetMathScript(buffer_, cur.prevAtom(), up));
                }
                --cur.pos();
                InsetMathScript * inset = cur.nextAtom().nucleus()->asScriptInset();
@@ -1806,8 +2007,7 @@ void InsetMathNest::completionPosAndDim(Cursor const & cur, int & x, int & y,
        dim.asc += 3;
 
        // and position
-       Point xy
-       = cur.bv().coordCache().insets().xy(inset);
+       Point xy = cur.bv().coordCache().insets().xy(inset);
        x = xy.x_;
        y = xy.y_;
 }
@@ -1892,6 +2092,7 @@ MathCompletionList::MathCompletionList(Cursor const & cur)
        globals.push_back(from_ascii("\\cases"));
        globals.push_back(from_ascii("\\substack"));
        globals.push_back(from_ascii("\\xymatrix"));
+       globals.push_back(from_ascii("\\Diagram"));
        globals.push_back(from_ascii("\\subarray"));
        globals.push_back(from_ascii("\\array"));
        globals.push_back(from_ascii("\\sqrt"));
@@ -1917,6 +2118,9 @@ MathCompletionList::MathCompletionList(Cursor const & cur)
        globals.push_back(from_ascii("\\color"));
        globals.push_back(from_ascii("\\normalcolor"));
        globals.push_back(from_ascii("\\textcolor"));
+       globals.push_back(from_ascii("\\cfrac"));
+       globals.push_back(from_ascii("\\cfracleft"));
+       globals.push_back(from_ascii("\\cfracright"));
        globals.push_back(from_ascii("\\dfrac"));
        globals.push_back(from_ascii("\\tfrac"));
        globals.push_back(from_ascii("\\dbinom"));