]> git.lyx.org Git - lyx.git/blobdiff - src/mathed/math_nestinset.C
the DocIterator stuff
[lyx.git] / src / mathed / math_nestinset.C
index 90a3f74b4dfc5fb790b22e8e66de53b9082f9e78..099f31766c0558d2c0a7b62dc6a56d4ca42983ff 100644 (file)
 #include "math_nestinset.h"
 
 #include "math_arrayinset.h"
+#include "math_braceinset.h"
+#include "math_commentinset.h"
 #include "math_data.h"
 #include "math_deliminset.h"
 #include "math_factory.h"
 #include "math_hullinset.h"
 #include "math_mathmlstream.h"
 #include "math_parser.h"
+#include "math_scriptinset.h"
 #include "math_spaceinset.h"
 #include "math_support.h"
 #include "math_mboxinset.h"
+#include "math_unknowninset.h"
 
 #include "BufferView.h"
 #include "bufferview_funcs.h"
@@ -164,26 +168,6 @@ bool MathNestInset::idxLast(LCursor & cur) const
 }
 
 
-bool MathNestInset::idxHome(LCursor & cur) const
-{
-       BOOST_ASSERT(ptr_cmp(cur.inset(), this));
-       if (cur.pos() == 0)
-               return false;
-       cur.pos() = 0;
-       return true;
-}
-
-
-bool MathNestInset::idxEnd(LCursor & cur) const
-{
-       BOOST_ASSERT(ptr_cmp(cur.inset(), this));
-       if (cur.lastpos() == cur.lastpos())
-               return false;
-       cur.pos() = cur.lastpos();
-       return true;
-}
-
-
 void MathNestInset::dump() const
 {
        WriteStream os(lyxerr);
@@ -351,6 +335,7 @@ void MathNestInset::handleFont2(LCursor & cur, string const & arg)
 void MathNestInset::priv_dispatch(LCursor & cur, FuncRequest const & cmd)
 {
        lyxerr << "MathNestInset: request: " << cmd << std::endl;
+       //CursorSlice sl = cur.current();
 
        switch (cmd.action) {
 
@@ -399,40 +384,59 @@ void MathNestInset::priv_dispatch(LCursor & cur, FuncRequest const & cmd)
                break;
 
        case LFUN_FINISHED_LEFT:
-               cur.pop(cur.currentDepth());
                cur.bv().cursor() = cur;
                break;
 
        case LFUN_FINISHED_RIGHT:
-               cur.pop(cur.currentDepth());
                ++cur.pos();
                cur.bv().cursor() = cur;
                break;
 
        case LFUN_FINISHED_UP:
-               cur.pop(cur.currentDepth());
                //idxUpDown(cur, true);
                cur.bv().cursor() = cur;
                break;
 
        case LFUN_FINISHED_DOWN:
-               cur.pop(cur.currentDepth());
                //idxUpDown(cur, false);
                cur.bv().cursor() = cur;
                break;
 
        case LFUN_RIGHTSEL:
        case LFUN_RIGHT:
+               lyxerr << "mathnest RIGHT: from:\n" << cur << endl;
                cur.selHandle(cmd.action == LFUN_RIGHTSEL);
-               if (!cur.right()) 
+               cur.autocorrect() = false;
+               cur.clearTargetX();
+               if (cur.inMacroMode())
+                       cur.macroModeClose();
+               else if (cur.pos() != cur.lastpos() && cur.openable(cur.nextAtom())) {
+                       cur.pushLeft(cur.nextAtom().nucleus());
+                       cur.inset()->idxFirst(cur);
+               } else if (cur.posRight() || idxRight(cur)
+                       || cur.popRight() || cur.selection())
+                       ;
+               else
                        cur.dispatched(FINISHED_RIGHT);
+               lyxerr << "mathnest RIGHT: to:\n" << cur << endl;
                break;
 
        case LFUN_LEFTSEL:
        case LFUN_LEFT:
                cur.selHandle(cmd.action == LFUN_LEFTSEL);
-               if (!cur.left())
-                       cur.dispatched(FINISHED);
+               cur.autocorrect() = false;
+               cur.clearTargetX();
+               if (cur.inMacroMode())
+                       cur.macroModeClose();
+               else if (cur.pos() != 0 && cur.openable(cur.prevAtom())) {
+                       cur.posLeft();
+                       cur.push(cur.nextAtom().nucleus());
+                       cur.inset()->idxLast(cur);
+               } else if (cur.posLeft() || idxLeft(cur)
+                       || cur.popLeft() || cur.selection())
+                       ;
+               else
+                       cur.dispatched(FINISHED_LEFT);
                break;
 
        case LFUN_UPSEL:
@@ -450,10 +454,12 @@ void MathNestInset::priv_dispatch(LCursor & cur, FuncRequest const & cmd)
                break;
 
        case LFUN_WORDSEL:
-               cur.home();
+               cur.pos() = 0;
+               cur.idx() = 0;
                cur.resetAnchor();
                cur.selection() = true;
-               cur.end();
+               cur.pos() = cur.lastpos();
+               cur.idx() = cur.lastidx();
                break;
 
        case LFUN_UP_PARAGRAPHSEL:
@@ -462,39 +468,50 @@ void MathNestInset::priv_dispatch(LCursor & cur, FuncRequest const & cmd)
        case LFUN_DOWN_PARAGRAPH:
                break;
 
+       case LFUN_HOMESEL:
+       case LFUN_HOME:
        case LFUN_WORDLEFTSEL:
        case LFUN_WORDLEFT:
-               cur.selHandle(cmd.action == LFUN_WORDLEFTSEL);
-               if (!cur.home())
-                       cur.dispatched(FINISHED);
+               cur.selHandle(cmd.action == LFUN_WORDLEFTSEL || cmd.action == LFUN_HOMESEL);
+               cur.macroModeClose();
+               if (cur.pos() != 0) {
+                       cur.pos() = 0;
+               } else if (cur.col() != 0) {
+                       cur.idx() -= cur.col();
+                       cur.pos() = 0;
+               } else if (cur.idx() != 0) {
+                       cur.idx() = 0;
+                       cur.pos() = 0;
+               } else {
+                       cur.dispatched(FINISHED_LEFT);
+               }
                break;
 
        case LFUN_WORDRIGHTSEL:
        case LFUN_WORDRIGHT:
-               cur.selHandle(cmd.action == LFUN_WORDRIGHTSEL);
-               if (!cur.end())
-                       cur.dispatched(FINISHED_RIGHT);
-               break;
-
-       case LFUN_HOMESEL:
-       case LFUN_HOME:
-               cur.selHandle(cmd.action == LFUN_HOMESEL);
-               if (!cur.home())
-                       cur.dispatched(FINISHED_RIGHT);
-               break;
-
        case LFUN_ENDSEL:
        case LFUN_END:
-               cur.selHandle(cmd.action == LFUN_ENDSEL);
-               if (!cur.end())
+               cur.selHandle(cmd.action == LFUN_WORDRIGHTSEL || cmd.action == LFUN_ENDSEL);
+               cur.macroModeClose();
+               cur.clearTargetX();
+               if (cur.pos() != cur.lastpos()) {
+                       cur.pos() = cur.lastpos();
+               } else if (cur.col() != cur.lastcol()) {
+                       cur.idx() = cur.idx() - cur.col() + cur.lastcol();
+                       cur.pos() = cur.lastpos();
+               } else if (cur.idx() != cur.lastidx()) {
+                       cur.idx() = cur.lastidx();
+                       cur.pos() = cur.lastpos();
+               } else {
                        cur.dispatched(FINISHED_RIGHT);
+               }
                break;
 
        case LFUN_PRIORSEL:
        case LFUN_PRIOR:
        case LFUN_BEGINNINGBUFSEL:
        case LFUN_BEGINNINGBUF:
-               cur.dispatched(FINISHED);
+               cur.dispatched(FINISHED_LEFT);
                break;
 
        case LFUN_NEXTSEL:
@@ -522,18 +539,26 @@ void MathNestInset::priv_dispatch(LCursor & cur, FuncRequest const & cmd)
        case LFUN_DELETE:
                //recordUndo(cur, Undo::ATOMIC);
                cur.erase();
-               cur.dispatched(FINISHED);
+               cur.dispatched(FINISHED_LEFT);
                break;
 
        case LFUN_ESCAPE:
                if (cur.selection()) 
                        cur.selClear();
                else 
-                       cur.dispatched(FINISHED);
+                       cur.dispatched(FINISHED_LEFT);
                break;
 
        case LFUN_INSET_TOGGLE:
-               cur.lockToggle();
+               //lockToggle();
+               if (cur.pos() != cur.lastpos()) {
+                       // toggle previous inset ...
+                       cur.nextAtom().nucleus()->lock(!cur.nextAtom()->lock());
+               } else if (cur.popLeft() && cur.pos() != cur.lastpos()) {
+                       // ... or enclosing inset if we are in the last inset position
+                       cur.nextAtom().nucleus()->lock(!cur.nextAtom()->lock());
+                       ++cur.pos();
+               }
                break;
 
        case LFUN_SELFINSERT:
@@ -546,7 +571,7 @@ void MathNestInset::priv_dispatch(LCursor & cur, FuncRequest const & cmd)
                        cur.insert(cmd.argument);
                        break;
                }
-               if (!cur.interpret(cmd.argument[0]))
+               if (!interpret(cur, cmd.argument[0]))
                        cur.dispatched(FINISHED_RIGHT);
                break;
 
@@ -594,7 +619,7 @@ void MathNestInset::priv_dispatch(LCursor & cur, FuncRequest const & cmd)
                        // do superscript if LyX handles
                        // deadkeys
                        //recordUndo(cur, Undo::ATOMIC);
-                       cur.script(true);
+                       script(cur, true);
                }
                break;
 
@@ -659,7 +684,7 @@ void MathNestInset::priv_dispatch(LCursor & cur, FuncRequest const & cmd)
                cur.posLeft();
                cur.pushLeft(cur.nextInset());
 #else
-               if (cur.currentMode() == InsetBase::TEXT_MODE)
+               if (currentMode() == InsetBase::TEXT_MODE)
                        cur.niceInsert(MathAtom(new MathHullInset("simple")));
                else
                        handleFont(cur, cmd.argument, "textrm");
@@ -722,7 +747,7 @@ void MathNestInset::priv_dispatch(LCursor & cur, FuncRequest const & cmd)
        case LFUN_INSET_ERT:
                // interpret this as if a backslash was typed
                //recordUndo(cur, Undo::ATOMIC);
-               cur.interpret('\\');
+               interpret(cur, '\\');
                break;
 
 // FIXME: We probably should swap parts of "math-insert" and "self-insert"
@@ -759,7 +784,7 @@ void MathNestInset::priv_dispatch(LCursor & cur, FuncRequest const & cmd)
                        cur.insert(ar);
                        break;
                }
-               cur.notdispatched();
+               cur.undispatched();
                break;
        }
 
@@ -769,7 +794,7 @@ void MathNestInset::priv_dispatch(LCursor & cur, FuncRequest const & cmd)
        case LFUN_WORD_REPLACE:
        case LFUN_WORD_FIND:
                if (!searchForward(&cur.bv(), cmd.getArg(0), false, false))
-                       cur.notdispatched();
+                       cur.undispatched();
                break;
 
        cur.normalize();
@@ -855,7 +880,7 @@ void MathNestInset::lfunMouseRelease(LCursor & cur, FuncRequest const & cmd)
                return;
        }
 
-       cur.notdispatched();
+       cur.undispatched();
 }
 
 
@@ -893,7 +918,188 @@ void MathNestInset::lfunMouseMotion(LCursor & cur, FuncRequest const & cmd)
                cur.selBegin();
 
        //cur.setScreenPos(cmd.x + xo_, cmd.y + yo_);
-       cur.bv().cursor().cursor_ = cur.cursor_;
-       cur.bv().cursor().selection() = true;
-       return;
+       cur.bv().cursor().setCursor(cur, true);
+}
+
+
+bool MathNestInset::interpret(LCursor & cur, char c)
+{
+       //lyxerr << "interpret 2: '" << c << "'" << endl;
+       cur.clearTargetX();
+       if (cur.inMacroArgMode()) {
+               cur.posLeft();
+               cur.plainErase();
+#warning FIXME
+#if 0
+               int n = c - '0';
+               MathMacroTemplate const * p = formula()->asMacroTemplate();
+               if (p && 1 <= n && n <= p->numargs())
+                       cur.insert(MathAtom(new MathMacroArgument(c - '0')));
+               else {
+                       cur.insert(createMathInset("#"));
+                       interpret(cur, c); // try again
+               }
+#endif
+               return true;
+       }
+
+       // handle macroMode
+       if (cur.inMacroMode()) {
+               string name = cur.macroName();
+               //lyxerr << "interpret name: '" << name << "'" << endl;
+
+               if (isalpha(c)) {
+                       cur.activeMacro()->setName(cur.activeMacro()->name() + c);
+                       return true;
+               }
+
+               // handle 'special char' macros
+               if (name == "\\") {
+                       // remove the '\\'
+                       cur.backspace();
+                       if (c == '\\') {
+                               if (currentMode() == MathInset::TEXT_MODE)
+                                       cur.niceInsert(createMathInset("textbackslash"));
+                               else
+                                       cur.niceInsert(createMathInset("backslash"));
+                       } else if (c == '{') {
+                               cur.niceInsert(MathAtom(new MathBraceInset));
+                       } else {
+                               cur.niceInsert(createMathInset(string(1, c)));
+                       }
+                       return true;
+               }
+
+               // leave macro mode and try again if necessary
+               cur.macroModeClose();
+               if (c == '{')
+                       cur.niceInsert(MathAtom(new MathBraceInset));
+               else if (c != ' ')
+                       interpret(cur, c);
+               return true;
+       }
+
+       // This is annoying as one has to press <space> far too often.
+       // Disable it.
+
+#if 0
+               // leave autocorrect mode if necessary
+               if (autocorrect() && c == ' ') {
+                       autocorrect() = false;
+                       return true;
+               }
+#endif
+
+       // just clear selection on pressing the space bar
+       if (cur.selection() && c == ' ') {
+               cur.selection() = false;
+               return true;
+       }
+
+       cur.selClearOrDel();
+
+       if (c == '\\') {
+               //lyxerr << "starting with macro" << endl;
+               cur.insert(MathAtom(new MathUnknownInset("\\", false)));
+               return true;
+       }
+
+       if (c == '\n') {
+               if (currentMode() == MathInset::TEXT_MODE)
+                       cur.insert(c);
+               return true;
+       }
+
+       if (c == ' ') {
+               if (currentMode() == MathInset::TEXT_MODE) {
+                       // insert spaces in text 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...
+                       if (!cur.pos() != 0 || cur.prevAtom()->getChar() != ' ')
+                               cur.insert(c);
+                       return true;
+               }
+               if (cur.pos() != 0 && cur.prevAtom()->asSpaceInset()) {
+                       cur.prevAtom().nucleus()->asSpaceInset()->incSpace();
+                       return true;
+               }
+               if (cur.popRight())
+                       return true;
+               // if are at the very end, leave the formula
+               return cur.pos() != cur.lastpos();
+       }
+
+       if (c == '_') {
+               script(cur, false);
+               return true;
+       }
+
+       if (c == '^') {
+               script(cur, true);
+               return true;
+       }
+
+       if (c == '{' || c == '}' || c == '#' || c == '&' || c == '$') {
+               cur.niceInsert(createMathInset(string(1, c)));
+               return true;
+       }
+
+       if (c == '%') {
+               cur.niceInsert(MathAtom(new MathCommentInset));
+               return true;
+       }
+
+       // try auto-correction
+       //if (autocorrect() && hasPrevAtom() && math_autocorrect(prevAtom(), c))
+       //      return true;
+
+       // no special circumstances, so insert the character without any fuss
+       cur.insert(c);
+       cur.autocorrect() = true;
+       return true;
+}
+
+
+bool MathNestInset::script(LCursor & cur, bool up)
+{
+       // Hack to get \\^ and \\_ working
+       lyxerr << "handling script: up: " << up << endl;
+       if (cur.inMacroMode() && cur.macroName() == "\\") {
+               if (up)
+                       cur.niceInsert(createMathInset("mathcircumflex"));
+               else
+                       interpret(cur, '_');
+               return true;
+       }
+
+       cur.macroModeClose();
+       string safe = cur.grabAndEraseSelection();
+       if (asScriptInset() && cur.idx() == 2) {
+               // we are in a nucleus of a script inset, move to _our_ script
+               asScriptInset()->ensure(up);
+               cur.idx() = up;
+               cur.pos() = 0;
+       } else if (cur.pos() != 0 && cur.prevAtom()->asScriptInset()) {
+               --cur.pos();
+               cur.nextAtom().nucleus()->asScriptInset()->ensure(up);
+               cur.push(cur.nextInset());
+               cur.idx() = up;
+               cur.pos() = cur.lastpos();
+       } else if (cur.pos() != 0) {
+               --cur.pos();
+               cur.cell()[cur.pos()] = MathAtom(new MathScriptInset(cur.nextAtom(), up));
+               cur.push(cur.nextInset());
+               cur.idx() = up;
+               cur.pos() = 0;
+       } else {
+               cur.plainInsert(MathAtom(new MathScriptInset(up)));
+               --cur.pos();
+               cur.nextAtom().nucleus()->asScriptInset()->ensure(up);
+               cur.push(cur.nextInset());
+               cur.idx() = up;
+               cur.pos() = 0;
+       }
+       cur.paste(safe);
+       return true;
 }