]> git.lyx.org Git - features.git/commitdiff
* added non-greedy init mode for macros. If you enter a macro with the cursor, you...
authorStefan Schimanski <sts@lyx.org>
Thu, 1 Nov 2007 14:40:15 +0000 (14:40 +0000)
committerStefan Schimanski <sts@lyx.org>
Thu, 1 Nov 2007 14:40:15 +0000 (14:40 +0000)
* split up the MathData::updateMacro method into the optional and normal parameter part

git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@21334 a592a061-630c-0410-9148-cb99ea01b6c8

src/Cursor.cpp
src/mathed/MathData.cpp
src/mathed/MathData.h
src/mathed/MathMacro.cpp
src/mathed/MathMacro.h

index 54a3b8bb7e43974900ba6d97e4534f0ee276de57..3fa8a4af07bf60705db16df32cf607fe25c29271 100644 (file)
 #include "insets/InsetTabular.h"
 #include "insets/InsetText.h"
 
-#include "mathed/MathData.h"
 #include "mathed/InsetMath.h"
 #include "mathed/InsetMathScript.h"
 #include "mathed/MacroTable.h"
+#include "mathed/MathData.h"
+#include "mathed/MathMacro.h"
 
 #include <boost/assert.hpp>
 #include <boost/bind.hpp>
@@ -943,7 +944,13 @@ bool Cursor::macroModeClose()
        InsetMathNest * const in = inset().asInsetMath()->asNestInset();
        if (in && in->interpretString(*this, s))
                return true;
-       plainInsert(createInsetMath(name));
+       MathAtom atom = createInsetMath(name);
+       if (atom.nucleus()->asMacro()) {
+               // make non-greedy, i.e. don't eat parameters from the right
+               MathMacro * macro = atom.nucleus()->asMacro();
+               macro->setDisplayMode(MathMacro::DISPLAY_NONGREEDY_INIT);
+       }
+       plainInsert(atom);
        return true;
 }
 
index f44f28709502f91840905b9f6992139fabf97704..b417e4b30a01b0375dd31df4f275cf8dc8dbe427 100644 (file)
@@ -378,12 +378,18 @@ void MathData::updateMacros(MetricsInfo & mi)
                                                || macroInset->optionals() != macroOptionals)) {
                        // is it a virgin macro which was never attached to parameters?
                        bool fromInitToNormalMode
-                       = oldDisplayMode == MathMacro::DISPLAY_INIT
+                       = (oldDisplayMode == MathMacro::DISPLAY_INIT 
+                                || oldDisplayMode == MathMacro::DISPLAY_NONGREEDY_INIT)
                                && newDisplayMode == MathMacro::DISPLAY_NORMAL;
+                       bool greedy = (oldDisplayMode != MathMacro::DISPLAY_NONGREEDY_INIT);
                        
                        // attach parameters
                        attachMacroParameters(cur, i, macroNumArgs, macroOptionals,
-                               fromInitToNormalMode);
+                               fromInitToNormalMode, greedy);
+                       
+                       // FIXME: proper anchor handling, this removes the selection
+                       cur.updateInsets(&cur.bottom().inset());
+                       cur.clearSelection();   
                }
 
                // give macro the chance to adapt to new situation
@@ -512,15 +518,15 @@ void MathData::detachMacroParameters(Cursor & cur, const size_type macroPos)
 
 void MathData::attachMacroParameters(Cursor & cur, 
        const size_type macroPos, const size_type macroNumArgs,
-       const int macroOptionals, const bool fromInitToNormalMode)
+       const int macroOptionals, const bool fromInitToNormalMode,
+       const bool greedy)
 {
        MathMacro * macroInset = operator[](macroPos).nucleus()->asMacro();
 
        // start at atom behind the macro again, maybe with some new arguments from above
        // to add them back into the macro inset
        size_t p = macroPos + 1;
-       size_t j = 0;
-       std::vector<MathData>detachedArgs;
+       std::vector<MathData> detachedArgs;
        MathAtom scriptToPutAround;
        
        // find cursor slice again
@@ -529,16 +535,61 @@ void MathData::attachMacroParameters(Cursor & cur,
        if (thisSlice != -1)
                thisPos = cur[thisSlice].pos();
        
+       // find arguments behind the macro
+       if (greedy) {
+               collectOptionalParameters(cur, macroOptionals, detachedArgs, p,
+                       macroPos, thisPos, thisSlice);
+               collectParameters(cur, macroNumArgs, detachedArgs, p,
+                       scriptToPutAround, 
+                       macroPos, thisPos, thisSlice);
+       }
+               
+       // attach arguments back to macro inset
+       macroInset->attachArguments(detachedArgs, macroNumArgs, macroOptionals);
+       
+       // found tail script? E.g. \foo{a}b^x
+       if (scriptToPutAround.nucleus()) {
+               // put macro into a script inset
+               scriptToPutAround.nucleus()->asScriptInset()->nuc()[0] 
+               = operator[](macroPos);
+               operator[](macroPos) = scriptToPutAround;
+               
+               if (thisPos == int(macroPos))
+                       cur.append(0, 0);
+       }
+       
+       // remove them from the MathData
+       erase(begin() + macroPos + 1, begin() + p);
+       
+       // fix cursor if right of p
+       if (thisPos >= int(p))
+               cur[thisSlice].pos() -= p - (macroPos + 1);
+       
+       // was the macro inset just inserted and was now folded?
+       if (cur[thisSlice].pos() == int(macroPos + 1)
+                       && fromInitToNormalMode
+                       && macroInset->arity() > 0
+                       && thisSlice + 1 == int(cur.depth())) {
+               // then enter it if the cursor was just behind
+               cur[thisSlice].pos() = macroPos;
+               cur.push_back(CursorSlice(*macroInset));
+               macroInset->idxFirst(cur);
+       }
+}
+
+
+void MathData::collectOptionalParameters(Cursor & cur, 
+       const size_type numOptionalParams, std::vector<MathData> & params, 
+       size_t & pos, const pos_type macroPos, const int thisPos, const int thisSlice)
+{
        // insert optional arguments?
-       for (; j < macroOptionals && p < size(); ++j) {
+       while (params.size() < numOptionalParams && pos < size()) {
                // is a [] block following which could be an optional parameter?
-               if (operator[](p)->getChar() != '[') {
-                       detachedArgs.push_back(MathData());
-                       continue;
-               }
+               if (operator[](pos)->getChar() != '[')
+                       break;
                                
-               // found optional argument, look for "]"
-               size_t right = p + 1;
+               // found possible optional argument, look for "]"
+               size_t right = pos + 1;
                for (; right < size(); ++right) {
                        if (operator[](right)->getChar() == ']')
                                // found right end
@@ -546,130 +597,106 @@ void MathData::attachMacroParameters(Cursor & cur,
                }
                
                // found?
-               if (right < size()) {
-                       // add everything between [ and ] as optional argument
-                       MathData optarg(begin() + p + 1, begin() + right);
-                       // a brace?
-                       bool brace = false;
-                       if (optarg.size() == 1 && optarg[0]->asBraceInset()) {
-                               brace = true;
-                               detachedArgs.push_back(optarg[0]->asBraceInset()->cell(0));
-                       } else
-                               detachedArgs.push_back(optarg);
-                       // place cursor in optional argument of macro
-                       if (thisPos >= int(p) && thisPos <= int(right)) {
-                               int pos = std::max(0, thisPos - int(p) - 1);
-                               std::vector<CursorSlice> x;
-                               cur.cutOff(thisSlice, x);
-                               cur[thisSlice].pos() = macroPos;
-                               if (brace) {
-                                       pos = x[0].pos();
-                                       x.erase(x.begin());
-                               }
-                               cur.append(0, pos);
-                               cur.append(x);
-                       }
-                       p = right + 1;
-               } else {
+               if (right >= size()) {
                        // no ] found, so it's not an optional argument
-                       // Note: This was "macroPos = p" before, which probably
-                       //       does not make sense. We want to stop with optional
-                       //       argument handling instead, so go back to the beginning.
-                       j = 0; 
                        break;
                }
+               
+               // add everything between [ and ] as optional argument
+               MathData optarg(begin() + pos + 1, begin() + right);
+               
+               // a brace?
+               bool brace = false;
+               if (optarg.size() == 1 && optarg[0]->asBraceInset()) {
+                       brace = true;
+                       params.push_back(optarg[0]->asBraceInset()->cell(0));
+               } else
+                       params.push_back(optarg);
+               
+               // place cursor in optional argument of macro
+               if (thisPos >= int(pos) && thisPos <= int(right)) {
+                       int paramPos = std::max(0, thisPos - int(pos) - 1);
+                       std::vector<CursorSlice> x;
+                       cur.cutOff(thisSlice, x);
+                       cur[thisSlice].pos() = macroPos;
+                       if (brace) {
+                               paramPos = x[0].pos();
+                               x.erase(x.begin());
+                       }
+                       cur.append(0, paramPos);
+                       cur.append(x);
+               }
+               pos = right + 1;
        }
-       
-       // insert normal arguments
-       for (; j < macroNumArgs && p < size(); ++j) {
-               MathAtom & cell = operator[](p);
 
+       // fill up empty optional parameters
+       while (params.size() < numOptionalParams) {
+               params.push_back(MathData());
+       }
+}
+
+
+void MathData::collectParameters(Cursor & cur, 
+       const size_type numParams, std::vector<MathData> & params, 
+       size_t & pos, MathAtom & scriptToPutAround,
+       const pos_type macroPos, const int thisPos, const int thisSlice) 
+{
+       // insert normal arguments
+       for (; params.size() < numParams && pos < size();) {
+               MathAtom & cell = operator[](pos);
+               
                // fix cursor
                std::vector<CursorSlice> argSlices;
                int argPos = 0;
-               if (thisPos == int(p)) {
+               if (thisPos == int(pos)) {
                        cur.cutOff(thisSlice, argSlices);
                }
                
+               // which kind of parameter is it? In {}? With index x^n?
                InsetMathBrace const * brace = cell->asBraceInset();
                if (brace) {
                        // found brace, convert into argument
-                       detachedArgs.push_back(brace->cell(0));
+                       params.push_back(brace->cell(0));
                        
                        // cursor inside of the brace or just in front of?
-                       if (thisPos == int(p) && !argSlices.empty()) {
+                       if (thisPos == int(pos) && !argSlices.empty()) {
                                argPos = argSlices[0].pos();
                                argSlices.erase(argSlices.begin());
                        }
-               } else if (cell->asScriptInset() && j + 1 == macroNumArgs) {
+               } else if (cell->asScriptInset() && params.size() + 1 == numParams) {
                        // last inset with scripts without braces
                        // -> they belong to the macro, not the argument
                        InsetMathScript * script = cell.nucleus()->asScriptInset();
                        if (script->nuc().size() == 1 && script->nuc()[0]->asBraceInset())
                                // nucleus in brace? Unpack!
-                               detachedArgs.push_back(script->nuc()[0]->asBraceInset()->cell(0));
+                               params.push_back(script->nuc()[0]->asBraceInset()->cell(0));
                        else
-                               detachedArgs.push_back(script->nuc());
+                               params.push_back(script->nuc());
                        
                        // script will be put around below
                        scriptToPutAround = cell;
                        
                        // this should only happen after loading, so make cursor handling simple
-                       if (thisPos >= int(macroPos) && thisPos <= int(macroPos + macroNumArgs)) {
+                       if (thisPos >= int(macroPos) && thisPos <= int(macroPos + numParams)) {
                                argSlices.clear();
                                cur.append(0, 0);
                        }
                } else {
+                       // the simplest case: plain inset
                        MathData array;
                        array.insert(0, cell);
-                       detachedArgs.push_back(array);
+                       params.push_back(array);
                }
                
                // put cursor in argument again
-               if (thisPos == int(p)) {
-                       cur.append(j, argPos);
+               if (thisPos == int(pos)) {
+                       cur.append(params.size() - 1, argPos);
                        cur.append(argSlices);
                        cur[thisSlice].pos() = macroPos;
                }
                
-               ++p;
-       }
-       
-       // attach arguments back to macro inset
-       macroInset->attachArguments(detachedArgs, macroNumArgs, macroOptionals);
-       
-       // found tail script? E.g. \foo{a}b^x
-       if (scriptToPutAround.nucleus()) {
-               // put macro into a script inset
-               scriptToPutAround.nucleus()->asScriptInset()->nuc()[0] 
-               = operator[](macroPos);
-               operator[](macroPos) = scriptToPutAround;
-               
-               if (thisPos == int(macroPos))
-                       cur.append(0, 0);
-       }
-       
-       // remove them from the MathData
-       erase(begin() + macroPos + 1, begin() + p);
-       
-       // fix cursor if right of p
-       if (thisPos >= int(p))
-               cur[thisSlice].pos() -= p - (macroPos + 1);
-       
-       // was the macro inset just inserted and was now folded?
-       if (cur[thisSlice].pos() == int(macroPos + 1)
-                       && fromInitToNormalMode
-                       && macroInset->arity() > 0
-                       && thisSlice + 1 == int(cur.depth())) {
-               // then enter it if the cursor was just behind
-               cur[thisSlice].pos() = macroPos;
-               cur.push_back(CursorSlice(*macroInset));
-               macroInset->idxFirst(cur);
-       }
-       
-       // FIXME: proper anchor handling, this removes the selection
-       cur.updateInsets(&cur.bottom().inset());
-       cur.clearSelection();   
+               ++pos;
+       }       
 }
 
 
index 0e217a2f31d54c3202f49cb4e4f133307e2525ec..e6c4c378a4238f73065cc87e21b13dfa08854a51 100644 (file)
@@ -173,7 +173,16 @@ private:
        ///
        void attachMacroParameters(Cursor & cur, const size_type macroPos, 
                const size_type macroNumArgs, const int macroOptionals,
-               const bool fromInitToNormalMode);
+               const bool fromInitToNormalMode, const bool greedy);
+       ///
+       void collectOptionalParameters(Cursor & cur, 
+               const size_type numOptionalParams, std::vector<MathData> & params, 
+               size_t & pos, const pos_type macroPos, const int thisPos, const int thisSlice);
+       ///
+       void collectParameters(Cursor & cur, 
+               const size_type numParams, std::vector<MathData> & params, 
+               size_t & pos, MathAtom & scriptToPutAround,
+               const pos_type macroPos, const int thisPos, const int thisSlice);
        ///
        mutable std::vector<Dimension> atom_dims_;
 };
index e664cf0cab2379d4c03f3a5046d3c4707498267d..67a97cbd4dd99e2d6322e90e540d6f51d0a50d28 100644 (file)
@@ -158,7 +158,7 @@ bool MathMacro::editMode(Cursor const & cur) const {
 void MathMacro::metrics(MetricsInfo & mi, Dimension & dim) const
 {
        // calculate new metrics according to display mode
-       if (displayMode_ == DISPLAY_INIT) {
+       if (displayMode_ == DISPLAY_INIT || displayMode_ == DISPLAY_NONGREEDY_INIT) {
                mathed_string_dim(mi.base.font, from_ascii("\\") + name(), dim);
        } else if (displayMode_ == DISPLAY_UNFOLDED) {
                cell(0).metrics(mi, dim);
@@ -273,7 +273,7 @@ void MathMacro::draw(PainterInfo & pi, int x, int y) const
        int expx = x;
        int expy = y;
 
-       if (displayMode_ == DISPLAY_INIT) {             
+       if (displayMode_ == DISPLAY_INIT || displayMode_ == DISPLAY_NONGREEDY_INIT) {           
                PainterInfo pi2(pi.base.bv, pi.pain);
                pi2.base.font.setColor(macro_ ? Color_latex : Color_error);
                //pi2.base.style = LM_ST_TEXT;
index 88abdd0d854ccb7436bd0a53d4971d589912bb1a..45239e83eba630d41cd517af3f9994ef8e928ef1 100644 (file)
@@ -87,6 +87,7 @@ public:
                
        enum DisplayMode {
                DISPLAY_INIT,
+               DISPLAY_NONGREEDY_INIT,
                DISPLAY_UNFOLDED,
                DISPLAY_NORMAL,
        };
@@ -121,6 +122,7 @@ public:
 protected:
        friend class MathData;
        friend class ArgumentProxy;
+       friend class Cursor;
 
        /// update the display mode (should only be called after detaching arguments)
        void setDisplayMode(DisplayMode mode);