]> git.lyx.org Git - lyx.git/commitdiff
tex2lyx: import minted listings
authorEnrico Forestieri <forenr@lyx.org>
Sat, 17 Jun 2017 00:23:00 +0000 (02:23 +0200)
committerEnrico Forestieri <forenr@lyx.org>
Sat, 17 Jun 2017 00:23:00 +0000 (02:23 +0200)
This commit updates tex2lyx in order to also import minted listings.
For the floating version of a listing, minted uses the listing
environment, a concept that is not shared with the listings package,
towards which our listings inset is geared.
For this reason, a kludge is necessary when importing minted listings
not previously exported by LyX itself.
If the floating listing contains only a caption and a label (other
than the listing itself), everything is fine and the import is (or
aims to be) perfect. But, as in all other floating ebvironments,
one can also stick there other elements, which don't have a place
in the listings inset. So, in order to avoid a data loss, tex2lyx
sticks everything into the caption. In this way, things may be
rearranged in the GUI, if necessary. There is no other way, apart
from a complete redesign of the listings inset, of course. However,
I think that this is an acceptable compromise.

20 files changed:
src/tex2lyx/Preamble.cpp
src/tex2lyx/Preamble.h
src/tex2lyx/TODO.txt
src/tex2lyx/test/CJK.lyx.lyx
src/tex2lyx/test/CJKutf8.lyx.lyx
src/tex2lyx/test/DummyDocument.lyx.lyx
src/tex2lyx/test/Dummy~Document.lyx.lyx
src/tex2lyx/test/XeTeX-polyglossia.lyx.lyx
src/tex2lyx/test/algo2e.lyx.lyx
src/tex2lyx/test/box-color-size-space-align.lyx.lyx
src/tex2lyx/test/test-insets-basic.lyx.lyx
src/tex2lyx/test/test-insets.lyx.lyx
src/tex2lyx/test/test-memoir.lyx.lyx
src/tex2lyx/test/test-modules.lyx.lyx
src/tex2lyx/test/test-refstyle-theorems.lyx.lyx
src/tex2lyx/test/test-scr.lyx.lyx
src/tex2lyx/test/test-structure.lyx.lyx
src/tex2lyx/test/test.lyx.lyx
src/tex2lyx/test/verbatim.lyx.lyx
src/tex2lyx/text.cpp

index 6324a91c7930276c7a377e0afe165e6a86a13c6f..6650cf3fbbfc79cee7bb616c1a4653a360ba8a09 100644 (file)
@@ -183,9 +183,10 @@ const char * const known_xetex_packages[] = {"arabxetex", "fixlatvian",
 const char * const known_lyx_packages[] = {"amsbsy", "amsmath", "amssymb",
 "amstext", "amsthm", "array", "babel", "booktabs", "calc", "CJK", "color",
 "float", "fontspec", "framed", "graphicx", "hhline", "ifthen", "longtable",
-"makeidx", "multirow", "nomencl", "pdfpages", "prettyref", "refstyle", "rotating",
-"rotfloat", "splitidx", "setspace", "subscript", "textcomp", "tipa", "tipx",
-"tone", "ulem", "url", "varioref", "verbatim", "wrapfig", "xcolor", "xunicode", 0};
+"makeidx", "minted", "multirow", "nomencl", "pdfpages", "prettyref", "refstyle",
+"rotating", "rotfloat", "splitidx", "setspace", "subscript", "textcomp", "tipa",
+"tipx", "tone", "ulem", "url", "varioref", "verbatim", "wrapfig", "xcolor",
+"xunicode", 0};
 
 // codes used to remove packages that are loaded automatically by LyX.
 // Syntax: package_beg_sep<name>package_mid_sep<package loading code>package_end_sep
@@ -554,6 +555,7 @@ Preamble::Preamble() : one_language(true), explicit_babel(false),
        h_use_hyperref            = "false";
        h_use_microtype           = "false";
        h_use_refstyle            = false;
+       h_use_minted              = false;
        h_use_packages["amsmath"]    = "1";
        h_use_packages["amssymb"]    = "0";
        h_use_packages["cancel"]     = "0";
@@ -990,6 +992,8 @@ void Preamble::handle_package(Parser &p, string const & name,
        else if (is_known(name, known_lyx_packages) && options.empty()) {
                if (name == "splitidx")
                        h_use_indices = "true";
+               if (name == "minted")
+                       h_use_minted = "true";
                if (name == "refstyle")
                        h_use_refstyle = true;
                else if (name == "prettyref")
@@ -1261,7 +1265,8 @@ bool Preamble::writeLyXHeader(ostream & os, bool subdoc, string const & outfiled
           << "\\paperorientation " << h_paperorientation << '\n'
           << "\\suppress_date " << h_suppress_date << '\n'
           << "\\justification " << h_justification << '\n'
-          << "\\use_refstyle " << h_use_refstyle << '\n';
+          << "\\use_refstyle " << h_use_refstyle << '\n'
+          << "\\use_minted " << h_use_minted << '\n';
        if (!h_fontcolor.empty())
                os << "\\fontcolor " << h_fontcolor << '\n';
        if (!h_notefontcolor.empty())
index 342cc6873487a21f848797181f73110bf6bb4271..5dcc6718d7b4bd79efd2f0fc2bb3600feeb026b6 100644 (file)
@@ -48,6 +48,8 @@ public:
        std::string fontCJK() const { return h_font_cjk; }
        ///
        void fontCJK(std::string const & f) { h_font_cjk_set = true; h_font_cjk = f; }
+       ///
+       bool minted() const { return h_use_minted; }
        /// The document language
        std::string docLanguage() const { return h_language; }
        /// The language of text which is not explicitly marked
@@ -216,6 +218,7 @@ private:
        std::string h_use_default_options;
        std::string h_use_hyperref;
        bool h_use_refstyle;
+       bool h_use_minted;
 
        /*!
         * Add package \p name with options \p options to used_packages.
index 327420dbfd2337a1adaa565237831c1a58cf5bfc..2c835dd64c203e73fb4aae11c79e2afb8cffc172 100644 (file)
@@ -151,19 +151,6 @@ Format LaTeX feature                        LyX feature
                                              btprint "bibbysection"
 534   Chapterbib support
       \usepackage{chapterbib}              \multibib child
-544   Minted support
-      Non-floating:                        InsetListings
-        \begin{minted}[opts]{language}
-        ...
-        \end{minted}
-      Floating:
-        \begin{listing}[placement]
-          \begin{minted}[opts]{language}
-          ...
-          \end{minted}
-        \end{listing}
-      Inline (where '?' is any char):
-        \mintinline[opts]{language}?...?
                                            
                                            
 
index 82bbba31715cfe68457c32048743cbf1a72d57db..59d3729c3a00db49be848d99cb06065acdcccd40 100644 (file)
@@ -63,6 +63,7 @@
 \suppress_date false
 \justification true
 \use_refstyle 0
+\use_minted 0
 \index Index
 \shortcut idx
 \color #008000
index 7e3dbc883e77a3bb49cb290d70a158a57184f164..7eeec41b148e4d65b18158a28d074debb66d834b 100644 (file)
@@ -63,6 +63,7 @@
 \suppress_date false
 \justification true
 \use_refstyle 0
+\use_minted 0
 \index Index
 \shortcut idx
 \color #008000
index 86e20d489b50cda04fc2caa11cb3513f4f49b6b2..03a67e005ab8522c5caceafe7302d00902ef69d1 100644 (file)
@@ -61,6 +61,7 @@
 \suppress_date false
 \justification true
 \use_refstyle 0
+\use_minted 0
 \index Index
 \shortcut idx
 \color #008000
index 79bf881a68e36dbc5d1df97cbac7ba462f88b85a..30196892b0acbe42a5a9c46a5d845bbba4c1fb8e 100644 (file)
@@ -61,6 +61,7 @@
 \suppress_date false
 \justification true
 \use_refstyle 0
+\use_minted 0
 \index Index
 \shortcut idx
 \color #008000
index 8162a985f9d982603f4510d031236ef276fbe25f..fac9a9573a1833ade41a60ea5aa3e0bd8c748c92 100644 (file)
@@ -62,6 +62,7 @@
 \suppress_date false
 \justification true
 \use_refstyle 0
+\use_minted 0
 \index Index
 \shortcut idx
 \color #008000
index 39e9689787ff6018dd25394352ef149276a6dfb0..fa60631d38f2c3c45304ae5a9423e9035ba0b6ab 100644 (file)
@@ -61,6 +61,7 @@ algorithm2e
 \suppress_date false
 \justification true
 \use_refstyle 0
+\use_minted 0
 \index Index
 \shortcut idx
 \color #008000
index d399999a5d14c6810000ef6e31ae1b9692126f75..30a2b15551df1fc86d11979584bbf2f5c917c06b 100644 (file)
@@ -87,6 +87,7 @@
 \suppress_date false
 \justification true
 \use_refstyle 0
+\use_minted 0
 \notefontcolor #0000ff
 \backgroundcolor #ff5500
 \boxbgcolor #ffff00
index 0862f8a91555b0e89e072d292057c6cbfe8222c8..3e29da26021b3067efa3f0e41721352774c90eb2 100644 (file)
@@ -97,6 +97,7 @@
 \suppress_date false
 \justification true
 \use_refstyle 0
+\use_minted 0
 \index Index
 \shortcut idx
 \color #008000
index 42fa3e628ff4b97017034c13aa74a45236f9a1bd..0aa2ee886a1f7b0123823654388cd6fe725fa318 100644 (file)
@@ -73,6 +73,7 @@
 \suppress_date false
 \justification true
 \use_refstyle 0
+\use_minted 0
 \index Index
 \shortcut idx
 \color #008000
index e1dc00b824ab4373981026c1bbc71e8309119936..d777c5e4f95a2e543c511290b375ed6aa3c2c6e4 100644 (file)
@@ -59,6 +59,7 @@
 \suppress_date false
 \justification true
 \use_refstyle 0
+\use_minted 0
 \index Index
 \shortcut idx
 \color #008000
index 9f754c4661e4258dde9e60ea8321105f6e76c62b..034010a454fd3e5326aed0c1654f1f009f9a95da 100644 (file)
@@ -59,6 +59,7 @@ theorems-ams
 \suppress_date false
 \justification true
 \use_refstyle 0
+\use_minted 0
 \index Index
 \shortcut idx
 \color #008000
index fa573b6ff6080b0b64dc18e496c57c7db8e0e4ba..0e5491f750c207859b13d6f680da100f5b23ce82 100644 (file)
@@ -59,6 +59,7 @@ theorems-ams
 \suppress_date false
 \justification true
 \use_refstyle 1
+\use_minted 0
 \index Index
 \shortcut idx
 \color #008000
index 35f494649e415714542e2c5a93e58319c2f28d62..61d3fd80c33d5e3a126224bc7176170f7bc4f28e 100644 (file)
@@ -56,6 +56,7 @@
 \suppress_date false
 \justification true
 \use_refstyle 0
+\use_minted 0
 \index Index
 \shortcut idx
 \color #008000
index 1ec7c69c701460f6e02008d251e2b1d9416ff7fb..b1cb6808a83b0723a860e715bfff06a59c95d190 100644 (file)
@@ -92,6 +92,7 @@ logicalmkup
 \suppress_date true
 \justification true
 \use_refstyle 0
+\use_minted 0
 \index Index
 \shortcut idx
 \color #008000
index 31e21063d39aa887e16aa326bc3daa6236e9fe72..99ed5a4d0f573fb5cdaf84af45a8dce956820c8c 100644 (file)
@@ -63,6 +63,7 @@
 \suppress_date false
 \justification true
 \use_refstyle 0
+\use_minted 0
 \index Index
 \shortcut idx
 \color #008000
index ba3c82ec7a657df4221ddbe4380581aed054c9a8..569473260edd094046b2fe43dbb0a6ab7b42e58c 100644 (file)
@@ -52,6 +52,7 @@
 \suppress_date false
 \justification true
 \use_refstyle 0
+\use_minted 0
 \index Index
 \shortcut idx
 \color #008000
index 811883e9f19ac6824edb5c74f13b547adebf339d..af2abeb82ff2c54c5a210c990b7f45e4f4126e3b 100644 (file)
@@ -321,6 +321,15 @@ char const * const known_tones[] = {"15", "51", "45", "12", "454", 0};
 // string to store the float type to be able to determine the type of subfloats
 string float_type = "";
 
+// string to store the float status of minted listings
+string minted_float = "";
+
+// whether a caption has been parsed for a floating minted listing
+bool minted_float_has_caption = false;
+
+// The caption for non-floating minted listings
+string minted_nonfloat_caption = "";
+
 
 /// splits "x=z, y=b" into a map and an ordered keyword vector
 void split_map(string const & s, map<string, string> & res, vector<string> & keys)
@@ -1312,12 +1321,22 @@ void parse_outer_box(Parser & p, ostream & os, unsigned flags, bool outer,
 }
 
 
-void parse_listings(Parser & p, ostream & os, Context & parent_context, bool in_line)
+void parse_listings(Parser & p, ostream & os, Context & parent_context,
+                   bool in_line, bool use_minted)
 {
        parent_context.check_layout(os);
        begin_inset(os, "listings\n");
-       if (p.hasOpt()) {
-               string arg = p.verbatimOption();
+       string arg = p.hasOpt() ? p.verbatimOption() : string();
+       if (use_minted) {
+               string const language = p.getArg('{', '}');
+               p.skip_spaces(true);
+               arg += string(arg.empty() ? "" : ",") + "language=" + language;
+               if (!minted_float.empty()) {
+                       arg += string(arg.empty() ? "" : ",") + minted_float;
+                       minted_nonfloat_caption.clear();
+               }
+       }
+       if (!arg.empty()) {
                os << "lstparams " << '"' << arg << '"' << '\n';
                if (arg.find("\\color") != string::npos)
                        preamble.registerAutomaticallyLoadedPackage("color");
@@ -1329,6 +1348,19 @@ void parse_listings(Parser & p, ostream & os, Context & parent_context, bool in_
        os << "status collapsed\n";
        Context context(true, parent_context.textclass);
        context.layout = &parent_context.textclass.plainLayout();
+       if (use_minted && prefixIs(minted_nonfloat_caption, "[t]")) {
+               minted_nonfloat_caption.erase(0,3);
+               os << "\n\\begin_layout Plain Layout\n";
+               begin_inset(os, "Caption Standard\n");
+               Context newcontext(true, context.textclass,
+                                  context.layout, 0, context.font);
+               newcontext.check_layout(os);
+               os << minted_nonfloat_caption << "\n";
+               newcontext.check_end_layout(os);
+               end_inset(os);
+               os << "\n\\end_layout\n";
+               minted_nonfloat_caption.clear();
+       }
        string s;
        if (in_line) {
                // set catcodes to verbatim early, just in case.
@@ -1337,10 +1369,41 @@ void parse_listings(Parser & p, ostream & os, Context & parent_context, bool in_
                //FIXME: handler error condition
                s = p.verbatimStuff(delim).second;
 //             context.new_paragraph(os);
-       } else
+       } else if (use_minted) {
+               s = p.verbatimEnvironment("minted");
+       } else {
                s = p.verbatimEnvironment("lstlisting");
+       }
        output_ert(os, s, context);
-       end_inset(os);
+       if (use_minted && prefixIs(minted_nonfloat_caption, "[b]")) {
+               minted_nonfloat_caption.erase(0,3);
+               os << "\n\\begin_layout Plain Layout\n";
+               begin_inset(os, "Caption Standard\n");
+               Context newcontext(true, context.textclass,
+                                  context.layout, 0, context.font);
+               newcontext.check_layout(os);
+               os << minted_nonfloat_caption << "\n";
+               newcontext.check_end_layout(os);
+               end_inset(os);
+               os << "\n\\end_layout\n";
+               minted_nonfloat_caption.clear();
+       }
+       // Don't close the inset here for floating minted listings.
+       // It will be closed at the end of the listing environment.
+       if (!use_minted || minted_float.empty())
+               end_inset(os);
+       else {
+               eat_whitespace(p, os, parent_context, true);
+               Token t = p.get_token();
+               if (t.asInput() != "\\end") {
+                       // If anything follows, collect it into a caption.
+                       minted_float_has_caption = true;
+                       os << "\n\\begin_layout Plain Layout\n"; // outer layout
+                       begin_inset(os, "Caption Standard\n");
+                       os << "\n\\begin_layout Plain Layout\n"; // inner layout
+               }
+               p.putback();
+       }
 }
 
 
@@ -1707,9 +1770,104 @@ void parse_environment(Parser & p, ostream & os, bool outer,
                preamble.registerAutomaticallyLoadedPackage("framed");
        }
 
-       else if (name == "lstlisting") {
+       else if (name == "listing") {
+               minted_float = "float";
+               eat_whitespace(p, os, parent_context, false);
+               string const opt = p.hasOpt() ? p.getArg('[', ']') : string();
+               if (!opt.empty())
+                       minted_float += "=" + opt;
+               // If something precedes \begin{minted}, we output it at the end
+               // as a caption, in order to keep it inside the listings inset.
+               eat_whitespace(p, os, parent_context, true);
+               p.pushPosition();
+               Token const & t = p.get_token();
+               p.skip_spaces(true);
+               string const envname = p.next_token().cat() == catBegin
+                                               ? p.getArg('{', '}') : string();
+               bool prologue = t.asInput() != "\\begin" || envname != "minted";
+               p.popPosition();
+               minted_float_has_caption = false;
+               string content = parse_text_snippet(p, FLAG_END, outer,
+                                                   parent_context);
+               size_t i = content.find("\\begin_inset listings");
+               bool minted_env = i != string::npos;
+               string caption;
+               if (prologue) {
+                       caption = content.substr(0, i);
+                       content.erase(0, i);
+               }
+               parent_context.check_layout(os);
+               if (minted_env && minted_float_has_caption) {
+                       eat_whitespace(p, os, parent_context, true);
+                       os << content << "\n";
+                       if (!caption.empty())
+                               os << caption << "\n";
+                       os << "\n\\end_layout\n"; // close inner layout
+                       end_inset(os);            // close caption inset
+                       os << "\n\\end_layout\n"; // close outer layout
+               } else if (!caption.empty()) {
+                       if (!minted_env) {
+                               begin_inset(os, "listings\n");
+                               os << "lstparams " << '"' << minted_float << '"' << '\n';
+                               os << "inline false\n";
+                               os << "status collapsed\n";
+                       }
+                       os << "\n\\begin_layout Plain Layout\n";
+                       begin_inset(os, "Caption Standard\n");
+                       Context newcontext(true, parent_context.textclass,
+                                          0, 0, parent_context.font);
+                       newcontext.check_layout(os);
+                       os << caption << "\n";
+                       newcontext.check_end_layout(os);
+                       end_inset(os);
+                       os << "\n\\end_layout\n";
+               } else if (content.empty()) {
+                       begin_inset(os, "listings\n");
+                       os << "lstparams " << '"' << minted_float << '"' << '\n';
+                       os << "inline false\n";
+                       os << "status collapsed\n";
+               } else {
+                       os << content << "\n";
+               }
+               end_inset(os); // close listings inset
+               parent_context.check_end_layout(os);
+               parent_context.new_paragraph(os);
+               p.skip_spaces();
+               minted_float.clear();
+               minted_float_has_caption = false;
+       }
+
+       else if (name == "lstlisting" || name == "minted") {
+               bool use_minted = name == "minted";
                eat_whitespace(p, os, parent_context, false);
-               parse_listings(p, os, parent_context, false);
+               if (use_minted && minted_float.empty()) {
+                       // look ahead for a bottom caption
+                       p.pushPosition();
+                       bool found_end_minted = false;
+                       while (!found_end_minted && p.good()) {
+                               Token const & t = p.get_token();
+                               p.skip_spaces();
+                               string const envname =
+                                       p.next_token().cat() == catBegin
+                                               ? p.getArg('{', '}') : string();
+                               found_end_minted = t.asInput() == "\\end"
+                                                       && envname == "minted";
+                       }
+                       eat_whitespace(p, os, parent_context, true);
+                       Token const & t = p.get_token();
+                       p.skip_spaces(true);
+                       if (t.asInput() == "\\lyxmintcaption") {
+                               string const pos = p.getArg('[', ']');
+                               if (pos == "b") {
+                                       string const caption =
+                                               parse_text_snippet(p, FLAG_ITEM,
+                                                       false, parent_context);
+                                       minted_nonfloat_caption = "[b]" + caption;
+                               }
+                       }
+                       p.popPosition();
+               }
+               parse_listings(p, os, parent_context, false, use_minted);
                p.skip_spaces();
        }
 
@@ -2503,10 +2661,16 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                }
 
                else if (p.isParagraph()) {
-                       if (context.new_layout_allowed)
-                               context.new_paragraph(os);
-                       else
-                               output_ert_inset(os, "\\par ", context);
+                       // In minted floating listings we will collect
+                       // everything into the caption, where multiple
+                       // paragraphs are forbidden.
+                       if (minted_float.empty()) {
+                               if (context.new_layout_allowed)
+                                       context.new_paragraph(os);
+                               else
+                                       output_ert_inset(os, "\\par ", context);
+                       } else
+                               os << ' ';
                        eat_whitespace(p, os, context, true);
                }
 
@@ -3165,9 +3329,10 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                        end_inset(os);
                }
 
-               else if (t.cs() == "lstinline") {
+               else if (t.cs() == "lstinline" || t.cs() == "mintinline") {
+                       bool const use_minted = t.cs() == "mintinline";
                        p.skip_spaces();
-                       parse_listings(p, os, context, true);
+                       parse_listings(p, os, context, true, use_minted);
                }
 
                else if (t.cs() == "ensuremath") {
@@ -3190,13 +3355,22 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                                output_ert_inset(os, t.asInput(), context);
                }
 
-               else if (t.cs() == "tableofcontents" || t.cs() == "lstlistoflistings") {
+               else if (t.cs() == "tableofcontents"
+                               || t.cs() == "lstlistoflistings"
+                               || t.cs() == "listoflistings") {
+                       string name = t.cs();
+                       if (preamble.minted() && name == "listoflistings")
+                               name.insert(0, "lst");
                        context.check_layout(os);
-                       begin_command_inset(os, "toc", t.cs());
+                       begin_command_inset(os, "toc", name);
                        end_inset(os);
                        skip_spaces_braces(p);
-                       if (t.cs() == "lstlistoflistings")
-                               preamble.registerAutomaticallyLoadedPackage("listings");
+                       if (name == "lstlistoflistings") {
+                               if (preamble.minted())
+                                       preamble.registerAutomaticallyLoadedPackage("minted");
+                               else
+                                       preamble.registerAutomaticallyLoadedPackage("listings");
+                       }
                }
 
                else if (t.cs() == "listoffigures" || t.cs() == "listoftables") {
@@ -3719,6 +3893,20 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                        end_inset(os);
                }
 
+               else if (t.cs() == "lyxmintcaption") {
+                       string const pos = p.getArg('[', ']');
+                       if (pos == "t") {
+                               string const caption =
+                                       parse_text_snippet(p, FLAG_ITEM, false,
+                                                          context);
+                               minted_nonfloat_caption = "[t]" + caption;
+                       } else {
+                               // We already got the caption at the bottom,
+                               // so simply skip it.
+                               p.getArg('{', '}');
+                       }
+               }
+
                else if (t.cs() == "printindex" || t.cs() == "printsubindex") {
                        context.check_layout(os);
                        string commandname = t.cs();
@@ -4613,14 +4801,19 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                        docstring const name = newinsetlayout->name();
                        bool const caption = name.find(from_ascii("Caption:")) == 0;
                        if (caption) {
-                               begin_inset(os, "Caption ");
-                               os << to_utf8(name.substr(8)) << '\n';
+                               // Already done for floating minted listings.
+                               if (minted_float.empty()) {
+                                       begin_inset(os, "Caption ");
+                                       os << to_utf8(name.substr(8)) << '\n';
+                               }
                        } else {
                                begin_inset(os, "Flex ");
                                os << to_utf8(name) << '\n'
                                   << "status collapsed\n";
                        }
-                       if (newinsetlayout->isPassThru()) {
+                       if (!minted_float.empty()) {
+                               parse_text_snippet(p, os, FLAG_ITEM, false, context);
+                       } else if (newinsetlayout->isPassThru()) {
                                // set catcodes to verbatim early, just in case.
                                p.setCatcodes(VERBATIM_CATCODES);
                                string delim = p.get_token().asInput();
@@ -4636,7 +4829,10 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                                parse_text_in_inset(p, os, FLAG_ITEM, false, context, newinsetlayout);
                        if (caption)
                                p.skip_spaces();
-                       end_inset(os);
+                       // Minted caption insets are not closed here because
+                       // we collect everything into the caption.
+                       if (minted_float.empty())
+                               end_inset(os);
                }
 
                else if (t.cs() == "includepdf") {