]> git.lyx.org Git - lyx.git/commitdiff
Allow captions also on non-floating minted listings
authorEnrico Forestieri <forenr@lyx.org>
Sat, 10 Jun 2017 16:43:23 +0000 (18:43 +0200)
committerEnrico Forestieri <forenr@lyx.org>
Sat, 10 Jun 2017 16:43:23 +0000 (18:43 +0200)
Minted provides for captions only with floating listings. However,
listings always allows captions, and our machinery is geared accordingly.
So, instead of discriminating the floating and non-floating cases,
always allow for captions with minted, too. When minted does not provide
for a caption, we will provide one.
In the child document case the caption will always be before the listing,
while for the inset case the caption will be before the listing if it
is entered as the first line, after the listing otherwise.

src/LaTeXFeatures.cpp
src/insets/InsetInclude.cpp
src/insets/InsetListings.cpp

index b10a9a27544623df2181f059a8f9ad668cbf9ad6..bf8cf24f0744fdfec7856af72a829f7cb057863f 100644 (file)
@@ -419,6 +419,17 @@ static docstring const rtloutputdblcol_def = from_ascii(
        "}\n"
        "\\@mparswitchtrue\n");
 
+static docstring const lyxmintcaption_def = from_ascii(
+       "\\long\\def\\lyxmintcaption[#1]#2{%\n"
+       "  \\ifx#1t\\vskip\\baselineskip\\fi%\n"
+       "  \\refstepcounter{listing}\\noindent%\n"
+       "  \\setbox\\@tempboxa\\hbox{\\listingscaption~\\thelisting: #2}%\n"
+       "  \\ifdim \\wd\\@tempboxa >\\linewidth%\n"
+       "  \\parbox[t]{\\linewidth}{\\unhbox\\@tempboxa}\\else%\n"
+       "  \\hbox to\\linewidth{\\hfil\\box\\@tempboxa\\hfil}\\fi%\n"
+       "  \\ifx#1b\\vskip\\baselineskip\\fi\n"
+       "}\n");
+
 
 /////////////////////////////////////////////////////////////////////
 //
@@ -1491,6 +1502,9 @@ TexString LaTeXFeatures::getMacros() const
        if (mustProvide("rtloutputdblcol"))
                macros << rtloutputdblcol_def;
 
+       if (mustProvide("lyxmintcaption"))
+               macros << lyxmintcaption_def;
+
        return macros.release();
 }
 
index 6ae77a657cc69d233e2302f1bd28134aca90e84b..02da0f78cbfe16e027e644db7ec66df1fdbf95e4 100644 (file)
@@ -602,8 +602,11 @@ void InsetInclude::latex(otexstream & os, OutputParams const & runparams) const
                // Using listings, it is always possible to have a caption,
                // even for non-floats. Using minted, only floats can have a
                // caption. So, with minted we use the following strategy.
-               // If a caption or the float parameter are specified, we
-               // assume that the listing is floating. In this case, the
+               // If a caption was specified but the float parameter was not,
+               // we ourselves add a caption above the listing (because the
+               // listing comes from a file and might span several pages).
+               // Otherwise, if float was specified, the floating listing
+               // environment provided by minted is used. In either case, the
                // label parameter is taken as the label by which the float
                // can be referenced, otherwise it will have the meaning
                // intended by minted. In this last case, the label will
@@ -620,7 +623,7 @@ void InsetInclude::latex(otexstream & os, OutputParams const & runparams) const
                string caption;
                string label;
                string placement;
-               bool isfloat = false;
+               bool isfloat = lstparams.isFloat();
                if (use_minted) {
                        // Get float placement, language, caption, and
                        // label, then remove the relative options.
@@ -628,7 +631,6 @@ void InsetInclude::latex(otexstream & os, OutputParams const & runparams) const
                                getVectorFromString(parameters, ",", false);
                        for (size_t i = 0; i < opts.size(); ++i) {
                                if (prefixIs(opts[i], "float")) {
-                                       isfloat = true;
                                        if (prefixIs(opts[i], "float="))
                                                placement = opts[i].substr(6);
                                        opts.erase(opts.begin() + i--);
@@ -636,7 +638,6 @@ void InsetInclude::latex(otexstream & os, OutputParams const & runparams) const
                                        language = opts[i].substr(9);
                                        opts.erase(opts.begin() + i--);
                                } else if (prefixIs(opts[i], "caption=")) {
-                                       isfloat = true;
                                        caption = opts[i].substr(8);
                                        opts.erase(opts.begin() + i--);
                                } else if (prefixIs(opts[i], "label=")) {
@@ -645,7 +646,7 @@ void InsetInclude::latex(otexstream & os, OutputParams const & runparams) const
                                }
                        }
                        if (!label.empty()) {
-                               if (isfloat)
+                               if (isfloat || !caption.empty())
                                        label = trim(label, "{}");
                                else
                                        opts.push_back("label=" + label);
@@ -659,6 +660,11 @@ void InsetInclude::latex(otexstream & os, OutputParams const & runparams) const
                        if (!placement.empty())
                                os << '[' << placement << "]";
                        os << breakln;
+               } else if (use_minted && !caption.empty()) {
+                       os << breakln << "\\lyxmintcaption[t]{" << caption;
+                       if (!label.empty())
+                               os << "\\label{" << label << "}";
+                       os << "}\n";
                }
                os << (use_minted ? "\\inputminted" : "\\lstinputlisting");
                if (!parameters.empty())
@@ -1029,9 +1035,13 @@ void InsetInclude::validate(LaTeXFeatures & features) const
        if (isVerbatim(params()))
                features.require("verbatim");
        else if (isListings(params())) {
-               if (buffer().params().use_minted)
+               if (buffer().params().use_minted) {
                        features.require("minted");
-               else
+                       string const opts = to_utf8(params()["lstparams"]);
+                       InsetListingsParams lstpars(opts);
+                       if (!lstpars.isFloat() && contains(opts, "caption="))
+                               features.require("lyxmintcaption");
+               } else
                        features.require("listings");
        }
 
index 84eb4831cb6a843e02509b5054e04b5a25646f3a..b847131f57acb95002b3e707dc73fea573e045f3 100644 (file)
@@ -187,6 +187,9 @@ void InsetListings::latex(otexstream & os, OutputParams const & runparams) const
                encoding_switched = true;
        }
 
+       bool const captionfirst = !isfloat && par->isInset(0)
+                               && par->getInset(0)->lyxCode() == CAPTION_CODE;
+
        while (par != end) {
                pos_type siz = par->size();
                bool captionline = false;
@@ -277,10 +280,16 @@ void InsetListings::latex(otexstream & os, OutputParams const & runparams) const
                }
                os << delim << code << delim;
        } else if (use_minted) {
+               OutputParams rp = runparams;
+               rp.moving_arg = true;
+               TexString caption = getCaption(rp);
                if (isfloat) {
                        os << breakln << "\\begin{listing}";
                        if (!float_placement.empty())
                                os << '[' << float_placement << "]";
+               } else if (captionfirst && !caption.str.empty()) {
+                       os << breakln << "\\lyxmintcaption[t]{"
+                          << move(caption) << "}\n";
                }
                os << breakln << "\\begin{minted}";
                if (!param_string.empty())
@@ -288,12 +297,12 @@ void InsetListings::latex(otexstream & os, OutputParams const & runparams) const
                os << "{" << minted_language << "}\n"
                   << code << breakln << "\\end{minted}\n";
                if (isfloat) {
-                       OutputParams rp = runparams;
-                       rp.moving_arg = true;
-                       TexString caption = getCaption(rp);
                        if (!caption.str.empty())
                                os << "\\caption{" << move(caption) << "}\n";
                        os << "\\end{listing}\n";
+               } else if (!captionfirst && !caption.str.empty()) {
+                       os << breakln << "\\lyxmintcaption[b]{"
+                          << move(caption) << "}";
                }
        } else {
                OutputParams rp = runparams;
@@ -427,9 +436,7 @@ bool InsetListings::getStatus(Cursor & cur, FuncRequest const & cmd,
                        return true;
                case LFUN_CAPTION_INSERT: {
                        // the inset outputs at most one caption
-                       bool const use_minted = buffer().params().use_minted;
-                       if (params().isInline() || getCaptionInset() ||
-                           (use_minted && !params().isFloat())) {
+                       if (params().isInline() || getCaptionInset()) {
                                status.setEnabled(false);
                                return true;
                        }
@@ -452,14 +459,18 @@ docstring const InsetListings::buttonLabel(BufferView const & bv) const
 
 void InsetListings::validate(LaTeXFeatures & features) const
 {
-       if (buffer().params().use_minted)
-               features.require("minted");
-       else
-               features.require("listings");
        features.useInsetLayout(getLayout());
        string param_string = params().params();
-       if (param_string.find("\\color") != string::npos)
-               features.require("color");
+       if (buffer().params().use_minted) {
+               features.require("minted");
+               OutputParams rp = features.runparams();
+               if (!params().isFloat() && !getCaption(rp).str.empty())
+                       features.require("lyxmintcaption");
+       } else {
+               features.require("listings");
+               if (contains(param_string, "\\color"))
+                       features.require("color");
+       }
        InsetCaptionable::validate(features);
 }