]> git.lyx.org Git - lyx.git/blobdiff - src/Text.cpp
Amend 6c3447c8: FindAdv: sometimes a space is added on some math symbols
[lyx.git] / src / Text.cpp
index d8cd365093e53313f700b65370b94123f4b5ad7e..c6e2e054fb615d09a49fddc1370c0d1f6a8369de 100644 (file)
@@ -45,7 +45,6 @@
 #include "Intl.h"
 #include "Language.h"
 #include "Layout.h"
-#include "Lexer.h"
 #include "LyX.h"
 #include "LyXAction.h"
 #include "lyxfind.h"
@@ -95,6 +94,7 @@
 #include "support/filetools.h"
 #include "support/gettext.h"
 #include "support/lassert.h"
+#include "support/Lexer.h"
 #include "support/limited_stack.h"
 #include "support/lstrings.h"
 #include "support/lyxtime.h"
@@ -716,9 +716,8 @@ double Text::spacing(Paragraph const & par) const
 /**
  * This breaks a paragraph at the specified position.
  * The new paragraph will:
- * - Decrease depth by one (or change layout to default layout) when
- *    keep_layout == false
- * - keep current depth and layout when keep_layout == true
+ * - change layout to default layout when keep_layout == false
+ * - keep layout when keep_layout == true
  */
 static void breakParagraph(Text & text, pit_type par_offset, pos_type pos,
                    bool keep_layout)
@@ -733,21 +732,13 @@ static void breakParagraph(Text & text, pit_type par_offset, pos_type pos,
 
        // remember to set the inset_owner
        tmp->setInsetOwner(&par.inInset());
-       // without doing that we get a crash when typing <Return> at the
-       // end of a paragraph
-       tmp->setPlainOrDefaultLayout(bparams.documentClass());
+       tmp->params().depth(par.params().depth());
 
        if (keep_layout) {
                tmp->setLayout(par.layout());
                tmp->setLabelWidthString(par.params().labelWidthString());
-               tmp->params().depth(par.params().depth());
-       } else if (par.params().depth() > 0) {
-               Paragraph const & hook = pars[text.outerHook(par_offset)];
-               tmp->setLayout(hook.layout());
-               // not sure the line below is useful
-               tmp->setLabelWidthString(par.params().labelWidthString());
-               tmp->params().depth(hook.params().depth());
-       }
+       } else
+               tmp->setPlainOrDefaultLayout(bparams.documentClass());
 
        bool const isempty = (par.allowEmpty() && par.empty());
 
@@ -1136,12 +1127,15 @@ void Text::insertChar(Cursor & cur, char_type c)
        if (!cur.paragraph().isPassThru() && owner_->lyxCode() != IPA_CODE &&
            cur.real_current_font.fontInfo().family() != TYPEWRITER_FAMILY &&
            c == '-' && pos > 0) {
-               if (par.getChar(pos - 1) == '-') {
+               pos_type prev_pos = pos - 1;
+               while (prev_pos > 0 && par.isDeleted(prev_pos))
+                       --prev_pos;
+               if (!par.isDeleted(prev_pos) && par.getChar(prev_pos) == '-') {
                        // convert "--" to endash
-                       par.eraseChar(pos - 1, cur.buffer()->params().track_changes);
+                       par.eraseChar(prev_pos, cur.buffer()->params().track_changes);
                        c = 0x2013;
                        pos--;
-               } else if (par.getChar(pos - 1) == 0x2013) {
+               } else if (!par.isDeleted(prev_pos) && par.getChar(prev_pos) == 0x2013) {
                        // convert "---" to emdash
                        par.eraseChar(pos - 1, cur.buffer()->params().track_changes);
                        c = 0x2014;
@@ -1419,11 +1413,22 @@ void Text::expandWordSel(Cursor & cur)
        Cursor c = cur;
        c.selection(false);
        c.text()->selectWord(c, WHOLE_WORD);
+       // get selection around anchor too.
+       // FIXME: this cursor is not a proper one. normalAnchor() should
+       // return a DocIterator.
+       Cursor a(cur.bv());
+       a.push_back(cur.normalAnchor());
+       a.text()->selectWord(a, WHOLE_WORD);
        // use the correct word boundary, depending on selection direction
-       if (cur.top() > cur.normalAnchor())
-               cur.pos() = c.selEnd().pos();
-       else
-               cur.pos() = c.selBegin().pos();
+       if (cur.top() > cur.normalAnchor()) {
+               cur.top() = a.selBegin();
+               cur.resetAnchor();
+               cur.top() = c.selEnd();
+       } else {
+               cur.top() = a.selEnd();
+               cur.resetAnchor();
+               cur.top() = c.selBegin();
+       }
 }
 
 
@@ -2657,7 +2662,7 @@ bool Text::changeDepthAllowed(Cursor const & cur, DEPTH_CHANGE type) const
 }
 
 
-void Text::changeDepth(Cursor const & cur, DEPTH_CHANGE type)
+void Text::changeDepth(Cursor & cur, DEPTH_CHANGE type)
 {
        LBUFERR(this == cur.text());
        pit_type const beg = cur.selBegin().pit();
@@ -2676,6 +2681,7 @@ void Text::changeDepth(Cursor const & cur, DEPTH_CHANGE type)
                }
                max_depth = par.getMaxDepthAfter();
        }
+       cur.setCurrentFont();
        // this handles the counter labels, and also fixes up
        // depth values for follow-on (child) paragraphs
        cur.forceBufferUpdate();
@@ -2917,7 +2923,8 @@ void Text::setParagraphs(Cursor const & cur, docstring const & arg, bool merge)
        Layout priorlayout;
        Cursor c(cur.bv());
        c.setCursor(cur.selectionBegin());
-       for ( ; c <= cur.selectionEnd() ; ++c.pit()) {
+       pit_type const last_pit = cur.selectionEnd().pit();
+       for ( ; c.pit() <= last_pit ; ++c.pit()) {
                Paragraph & par = c.paragraph();
                ParagraphParameters params = par.params();
                params.read(argument, merge);
@@ -2943,7 +2950,8 @@ void Text::setParagraphs(Cursor const & cur, ParagraphParameters const & p)
        Layout priorlayout;
        Cursor c(cur.bv());
        c.setCursor(cur.selectionBegin());
-       for ( ; c < cur.selectionEnd() ; ++c.pit()) {
+       pit_type const last_pit = cur.selectionEnd().pit();
+       for ( ; c.pit() <= last_pit ; ++c.pit()) {
                Paragraph & par = c.paragraph();
                // Changes to label width string apply to all paragraphs
                // with same layout in a sequence.
@@ -2960,12 +2968,12 @@ void Text::setParagraphs(Cursor const & cur, ParagraphParameters const & p)
 }
 
 
-// this really should just insert the inset and not move the cursor.
-void Text::insertInset(Cursor & cur, Inset * inset)
+// just insert the inset and not move the cursor.
+bool Text::insertInset(Cursor & cur, Inset * inset)
 {
        LBUFERR(this == cur.text());
        LBUFERR(inset);
-       cur.paragraph().insertInset(cur.pos(), inset, cur.current_font,
+       return cur.paragraph().insertInset(cur.pos(), inset, cur.current_font,
                Change(cur.buffer()->params().track_changes
                ? Change::INSERTED : Change::UNCHANGED));
 }
@@ -3221,7 +3229,7 @@ int deleteSpaces(Paragraph & par, pos_type const from, pos_type to,
        int pos = from;
        while (pos < to && num_spaces > 0) {
                Change const & change = par.lookupChange(pos);
-               if (change.inserted() && change.currentAuthor()) {
+               if (change.inserted() && !change.currentAuthor()) {
                        par.eraseChar(pos, trackChanges);
                        --num_spaces;
                        --to;
@@ -3640,12 +3648,11 @@ bool doInsertInset(Cursor & cur, Text * text,
                        cutSelectionToTemp(cur, pastesel);
                        /* Move layout information inside the inset if the whole
                         * paragraph and the inset allows setting layout
-                        * FIXME: this does not work as expected when change tracking is on
-                        *   However, we do not really know what to do in this case.
                         * FIXME: figure out a good test in the environment case (see #12251).
                         */
                        if (cur.paragraph().layout().isCommand()
-                            && cur.paragraph().empty()
+                            && (cur.paragraph().empty()
+                                || cur.paragraph().isDeleted(0, cur.paragraph().size()))
                             && !inset->forcePlainLayout()) {
                                cur.paragraph().setPlainOrDefaultLayout(bparams.documentClass());
                                move_layout = true;
@@ -3746,11 +3753,12 @@ void insertSeparator(Cursor const & cur, depth_type const depth)
 }
 
 
-void outline(OutlineOp mode, Cursor & cur, Text * text)
+void outline(OutlineOp mode, Cursor & cur, bool local)
 {
        Buffer & buf = *cur.buffer();
+       Text & text = *cur.text();
        pit_type & pit = cur.pit();
-       ParagraphList & pars = buf.text().paragraphs();
+       ParagraphList & pars = text.paragraphs();
        ParagraphList::iterator const bgn = pars.begin();
        // The first paragraph of the area to be copied:
        ParagraphList::iterator start = pars.iterator_at(pit);
@@ -3759,18 +3767,20 @@ void outline(OutlineOp mode, Cursor & cur, Text * text)
        ParagraphList::iterator const end = pars.end();
        depth_type const current_depth = cur.paragraph().params().depth();
 
-       int const thistoclevel = buf.text().getTocLevel(distance(bgn, start));
+       int const thistoclevel = text.getTocLevel(distance(bgn, start));
        int toclevel;
 
        // Move out (down) from this section header
        if (finish != end)
                ++finish;
 
-       // Seek the one (on same level) below
-       for (; finish != end; ++finish) {
-               toclevel = buf.text().getTocLevel(distance(bgn, finish));
-               if (toclevel != Layout::NOT_IN_TOC && toclevel <= thistoclevel)
-                       break;
+       if (!local || (mode != OutlineIn && mode != OutlineOut)) {
+               // Seek the one (on same level) below
+               for (; finish != end; ++finish) {
+                       toclevel = text.getTocLevel(distance(bgn, finish));
+                       if (toclevel != Layout::NOT_IN_TOC && toclevel <= thistoclevel)
+                               break;
+               }
        }
 
        switch (mode) {
@@ -3785,7 +3795,7 @@ void outline(OutlineOp mode, Cursor & cur, Text * text)
                        // Search previous same-level header above
                        do {
                                --dest;
-                               toclevel = buf.text().getTocLevel(distance(bgn, dest));
+                               toclevel = text.getTocLevel(distance(bgn, dest));
                        } while(dest != bgn
                                && (toclevel == Layout::NOT_IN_TOC
                                    || toclevel > thistoclevel));
@@ -3819,7 +3829,7 @@ void outline(OutlineOp mode, Cursor & cur, Text * text)
                                // Get the parent paragraph (outer in nested context)
                                pit_type const parent =
                                        before->params().depth() > current_depth
-                                               ? text->depthHook(distance(bgn, before), current_depth)
+                                               ? text.depthHook(distance(bgn, before), current_depth)
                                                : distance(bgn, before);
                                // If a environment with same layout preceeds the moved one in the new
                                // position, and there is no separator yet, insert one.
@@ -3845,7 +3855,7 @@ void outline(OutlineOp mode, Cursor & cur, Text * text)
                        ParagraphList::iterator dest = next(finish, 1);
                        // Go further down to find header to insert in front of:
                        for (; dest != end; ++dest) {
-                               toclevel = buf.text().getTocLevel(distance(bgn, dest));
+                               toclevel = text.getTocLevel(distance(bgn, dest));
                                if (toclevel != Layout::NOT_IN_TOC
                                      && toclevel <= thistoclevel)
                                        break;
@@ -3861,7 +3871,7 @@ void outline(OutlineOp mode, Cursor & cur, Text * text)
                        // Get the parent paragraph (outer in nested context)
                        pit_type const parent =
                                before->params().depth() > current_depth
-                                       ? text->depthHook(distance(bgn, before), current_depth)
+                                       ? text.depthHook(distance(bgn, before), current_depth)
                                        : distance(bgn, before);
                        // If a environment with same layout preceeds the moved one in the new
                        // position, and there is no separator yet, insert one.
@@ -3902,13 +3912,25 @@ void outline(OutlineOp mode, Cursor & cur, Text * text)
                        ParagraphList::iterator cstart = start;
                        bool strucchange = false;
                        for (; cstart != finish; ++cstart) {
-                               toclevel = buf.text().getTocLevel(distance(bgn, cstart));
+                               toclevel = text.getTocLevel(distance(bgn, cstart));
                                if (toclevel == Layout::NOT_IN_TOC)
                                        continue;
 
                                DocumentClass const & tc = buf.params().documentClass();
-                               int const newtoclevel =
-                                       (mode == OutlineIn ? toclevel + 1 : toclevel - 1);
+                               int newtoclevel = -1;
+                               if (mode == OutlineIn) {
+                                       if (toclevel == -1 && tc.getTOCLayout().toclevel > 0)
+                                               // we are at part but don't have a chapter
+                                               newtoclevel = tc.getTOCLayout().toclevel;
+                                       else
+                                               newtoclevel = toclevel + 1;
+                               } else {
+                                       if (tc.getTOCLayout().toclevel == toclevel && tc.min_toclevel() < toclevel)
+                                               // we are at highest level, but there is still part
+                                               newtoclevel = tc.min_toclevel();
+                                       else
+                                               newtoclevel = toclevel - 1;
+                               }
 
                                bool found = false;
                                for (auto const & lay : tc) {
@@ -3938,13 +3960,25 @@ void outline(OutlineOp mode, Cursor & cur, Text * text)
                        pit_type const len = distance(start, finish);
                        buf.undo().recordUndo(cur, pit, pit + len - 1);
                        for (; start != finish; ++start) {
-                               toclevel = buf.text().getTocLevel(distance(bgn, start));
+                               toclevel = text.getTocLevel(distance(bgn, start));
                                if (toclevel == Layout::NOT_IN_TOC)
                                        continue;
 
                                DocumentClass const & tc = buf.params().documentClass();
-                               int const newtoclevel =
-                                       (mode == OutlineIn ? toclevel + 1 : toclevel - 1);
+                               int newtoclevel = -1;
+                               if (mode == OutlineIn) {
+                                       if (toclevel == -1 && tc.getTOCLayout().toclevel > 0)
+                                               // we are at part but don't have a chapter
+                                               newtoclevel = tc.getTOCLayout().toclevel;
+                                       else
+                                               newtoclevel = toclevel + 1;
+                               } else {
+                                       if (tc.getTOCLayout().toclevel == toclevel && tc.min_toclevel() < toclevel)
+                                               // we are at highest level, but there is still part
+                                               newtoclevel = tc.min_toclevel();
+                                       else
+                                               newtoclevel = toclevel - 1;
+                               }
 
                                for (auto const & lay : tc) {
                                        if (lay.toclevel == newtoclevel
@@ -4302,7 +4336,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
 
                if (!atFirstOrLastRow) {
                        needsUpdate |= cur.selHandle(select);
-                       cur.upDownInText(up, needsUpdate);
+                       needsUpdate |= cur.upDownInText(up);
                        needsUpdate |= cur.beforeDispatchCursor().inMathed();
                } else {
                        pos_type newpos = up ? 0 : cur.lastpos();
@@ -4310,10 +4344,11 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                                needsUpdate |= cur.selHandle(select);
                                // we do not reset the targetx of the cursor
                                cur.pos() = newpos;
-                               needsUpdate |= bv->checkDepm(cur, bv->cursor());
-                               cur.updateTextTargetOffset();
-                               if (needsUpdate)
+                               if (bv->checkDepm(cur, bv->cursor())) {
+                                       needsUpdate = true;
                                        cur.forceBufferUpdate();
+                               }
+                               cur.updateTextTargetOffset();
                                break;
                        }
 
@@ -4321,7 +4356,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                        // the selection right now, but wait for the next dispatch.
                        if (select)
                                needsUpdate |= cur.selHandle(select);
-                       cur.upDownInText(up, needsUpdate);
+                       needsUpdate |= cur.upDownInText(up);
                        cur.undispatched();
                }
 
@@ -4895,8 +4930,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                        if (theClipboard().isInternal())
                                pasteFromStack(cur, bv->buffer().errorList("Paste"), 0);
                        else if (theClipboard().hasTextContents()) {
-                               if (pasteClipboardText(cur, bv->buffer().errorList("Paste"),
-                                                      !cur.paragraph().parbreakIsNewline(),
+                               if (pasteClipboardText(cur, bv->buffer().errorList("Paste"), 0,
                                                           Clipboard::AnyTextType))
                                        tryGraphics = false;
                        }
@@ -5228,6 +5262,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                bvcur.setMark(false);
                switch (cmd.button()) {
                case mouse_button::button1:
+                       bvcur.setClickPos(cmd.x(), cmd.y());
                        if (!bvcur.selection())
                                // Set the cursor
                                bvcur.resetAnchor();
@@ -5319,6 +5354,8 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
        case LFUN_MOUSE_RELEASE:
                switch (cmd.button()) {
                case mouse_button::button1:
+                       // unregister last mouse press position
+                       cur.bv().cursor().setClickPos(-1, -1);
                        // Cursor was set at LFUN_MOUSE_PRESS or LFUN_MOUSE_MOTION time.
                        // If there is a new selection, update persistent selection;
                        // otherwise, single click does not clear persistent selection
@@ -5556,7 +5593,8 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                                                     from_utf8(N_(" not known")));
                }
                if (doInsertInset(cur, this, cmd, false, true))
-                       cur.posForward();
+                       // move inside
+                       (void) checkAndActivateInset(cur, true);
                break;
        }
 
@@ -5686,12 +5724,27 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
        }
 
        case LFUN_NOMENCL_PRINT:
-       case LFUN_NEWPAGE_INSERT:
                // do nothing fancy
                doInsertInset(cur, this, cmd, false, false);
                cur.posForward();
                break;
 
+       case LFUN_NEWPAGE_INSERT: {
+               // When we are in a heading, put the page break in a standard
+               // paragraph before the heading (if cur.pos() == 0) or after
+               // (if cur.pos() == cur.lastpos())
+               if (cur.text()->getTocLevel(cur.pit()) != Layout::NOT_IN_TOC) {
+                       lyx::dispatch(FuncRequest(LFUN_PARAGRAPH_BREAK));
+                       DocumentClass const & tc = bv->buffer().params().documentClass();
+                       lyx::dispatch(FuncRequest(LFUN_LAYOUT, from_ascii("\"") + tc.plainLayout().name()
+                                                 + from_ascii("\" ignoreautonests")));
+               }
+               // do nothing fancy
+               doInsertInset(cur, this, cmd, false, false);
+               cur.posForward();
+               break;
+       }
+
        case LFUN_SEPARATOR_INSERT: {
                doInsertInset(cur, this, cmd, false, false);
                cur.posForward();
@@ -5758,14 +5811,15 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                        InsetMathMacroTemplate * inset = new InsetMathMacroTemplate(cur.buffer(),
                                from_utf8(token(s, ' ', 0)), nargs, false, type);
                        inset->setBuffer(bv->buffer());
-                       insertInset(cur, inset);
-
-                       // enter macro inset and select the name
-                       cur.push(*inset);
-                       cur.top().pos() = cur.top().lastpos();
-                       cur.resetAnchor();
-                       cur.selection(true);
-                       cur.top().pos() = 0;
+                       if (insertInset(cur, inset)) {
+                               // If insertion is successful, enter macro inset and select the name
+                               cur.push(*inset);
+                               cur.top().pos() = cur.top().lastpos();
+                               cur.resetAnchor();
+                               cur.selection(true);
+                               cur.top().pos() = 0;
+                       } else
+                               delete inset;
                }
                break;
 
@@ -5908,7 +5962,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
                // Argument?
                if (!arg.empty()) {
                        if (isStrUnsignedInt(arg)) {
-                               num = convert<uint>(arg);
+                               num = convert<unsigned int>(arg);
                                if (num >= freeFonts.size()) {
                                        cur.message(_("Invalid argument (number exceeds stack size)!"));
                                        break;
@@ -6247,7 +6301,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
 
        case LFUN_OUTLINE_UP: {
                pos_type const opos = cur.pos();
-               outline(OutlineUp, cur, this);
+               outline(OutlineUp, cur, false);
                setCursor(cur, cur.pit(), opos);
                cur.forceBufferUpdate();
                needsUpdate = true;
@@ -6256,7 +6310,7 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
 
        case LFUN_OUTLINE_DOWN: {
                pos_type const opos = cur.pos();
-               outline(OutlineDown, cur, this);
+               outline(OutlineDown, cur, false);
                setCursor(cur, cur.pit(), opos);
                cur.forceBufferUpdate();
                needsUpdate = true;
@@ -6264,13 +6318,13 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
        }
 
        case LFUN_OUTLINE_IN:
-               outline(OutlineIn, cur, this);
+               outline(OutlineIn, cur, cmd.getArg(0) == "local");
                cur.forceBufferUpdate();
                needsUpdate = true;
                break;
 
        case LFUN_OUTLINE_OUT:
-               outline(OutlineOut, cur, this);
+               outline(OutlineOut, cur, cmd.getArg(0) == "local");
                cur.forceBufferUpdate();
                needsUpdate = true;
                break;
@@ -6336,30 +6390,31 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd)
 
        // FIXME: the following code should go in favor of fine grained
        // update flag treatment.
-       if (singleParUpdate) {
+       if (singleParUpdate || cur.result().screenUpdate() & Update::SinglePar) {
                // Inserting characters does not change par height in general. So, try
                // to update _only_ this paragraph. BufferView will detect if a full
                // metrics update is needed anyway.
                cur.screenUpdateFlags(Update::SinglePar | Update::FitCursor);
                return;
        }
-       if (!needsUpdate
-           && &oldTopSlice.inset() == &cur.inset()
-           && oldTopSlice.idx() == cur.idx()
-           && !oldSelection // oldSelection is a backup of cur.selection() at the beginning of the function.
-           && !cur.selection())
-               // FIXME: it would be better if we could just do this
-               //
-               //if (cur.result().update() != Update::FitCursor)
-               //      cur.noScreenUpdate();
-               //
-               // But some LFUNs do not set Update::FitCursor when needed, so we
-               // do it for all. This is not very harmfull as FitCursor will provoke
-               // a full redraw only if needed but still, a proper review of all LFUN
-               // should be done and this needsUpdate boolean can then be removed.
-               cur.screenUpdateFlags(Update::FitCursor);
-       else
+       if (needsUpdate)
                cur.screenUpdateFlags(Update::Force | Update::FitCursor);
+       else {
+               // oldSelection is a backup of cur.selection() at the beginning of the function.
+           if (!oldSelection && !cur.selection())
+                       // FIXME: it would be better if we could just do this
+                       //
+                       //if (cur.result().update() != Update::FitCursor)
+                       //      cur.noScreenUpdate();
+                       //
+                       // But some LFUNs do not set Update::FitCursor when needed, so we
+                       // do it for all. This is not very harmfull as FitCursor will provoke
+                       // a full redraw only if needed but still, a proper review of all LFUN
+                       // should be done and this needsUpdate boolean can then be removed.
+                       cur.screenUpdateFlags(Update::FitCursor);
+               else
+                       cur.screenUpdateFlags(Update::ForceDraw | Update::FitCursor);
+       }
 }
 
 
@@ -6548,6 +6603,8 @@ bool Text::getStatus(Cursor & cur, FuncRequest const & cmd,
                        s = from_ascii("Flex:") + s;
                if (!cur.buffer()->params().documentClass().hasInsetLayout(s))
                        enable = false;
+               else if (!cur.paragraph().allowedInContext(cur, cur.buffer()->params().documentClass().insetLayout(s)))
+                       enable = false;
                else {
                        InsetLyXType ilt =
                                cur.buffer()->params().documentClass().insetLayout(s).lyxtype();
@@ -6698,12 +6755,15 @@ bool Text::getStatus(Cursor & cur, FuncRequest const & cmd,
        case LFUN_MATH_BIGDELIM:
        case LFUN_MATH_DISPLAY:
        case LFUN_MATH_MODE:
-       case LFUN_MATH_MACRO:
        case LFUN_MATH_SUBSCRIPT:
        case LFUN_MATH_SUPERSCRIPT:
                code = MATH_HULL_CODE;
                break;
 
+       case LFUN_MATH_MACRO:
+               code = MATHMACRO_CODE;
+               break;
+
        case LFUN_REGEXP_MODE:
                code = MATH_HULL_CODE;
                enable = cur.buffer()->isInternal() && !cur.inRegexped();
@@ -6877,11 +6937,17 @@ bool Text::getStatus(Cursor & cur, FuncRequest const & cmd,
 
        case LFUN_OUTLINE_UP:
        case LFUN_OUTLINE_DOWN:
+               enable = cur.text()->getTocLevel(cur.pit()) != Layout::NOT_IN_TOC;
+               break;
        case LFUN_OUTLINE_IN:
+               enable = cur.text()->getTocLevel(cur.pit()) != Layout::NOT_IN_TOC
+                         && cur.text()->getTocLevel(cur.pit()) !=
+                               cur.buffer()->params().documentClass().max_toclevel();
+               break;
        case LFUN_OUTLINE_OUT:
-               // FIXME: LyX is not ready for outlining within inset.
-               enable = isMainText()
-                       && cur.buffer()->text().getTocLevel(cur.pit()) != Layout::NOT_IN_TOC;
+               enable = cur.text()->getTocLevel(cur.pit()) != Layout::NOT_IN_TOC
+                        && cur.text()->getTocLevel(cur.pit()) !=
+                               cur.buffer()->params().documentClass().min_toclevel();
                break;
 
        case LFUN_NEWLINE_INSERT:
@@ -6910,9 +6976,11 @@ bool Text::getStatus(Cursor & cur, FuncRequest const & cmd,
        }
 
        case LFUN_NEWPAGE_INSERT:
-               // not allowed in description items
+               // not allowed in description items and in the midst of sections
                code = NEWPAGE_CODE;
-               enable = !inDescriptionItem(cur);
+               enable = !inDescriptionItem(cur)
+                       && (cur.text()->getTocLevel(cur.pit()) == Layout::NOT_IN_TOC
+                           || cur.pos() == 0 || cur.pos() == cur.lastpos());
                break;
 
        case LFUN_LANGUAGE: