commit b1a6edcd77bdbf0efc7585828efc5f3c9618084a
Author: Juergen Spitzmueller <sp...@lyx.org>
Date:   Thu May 15 12:20:53 2025 +0200

    Implement MultiPar to layouts (#10590)
---
 lib/doc/Customization.lyx    | 59 +++++++++++++++++++++++++++++++++++++++++++-
 lib/doc/de/Customization.lyx | 59 +++++++++++++++++++++++++++++++++++++++++++-
 lib/scripts/layout2layout.py |  5 +++-
 src/Layout.cpp               |  8 +++++-
 src/Layout.h                 |  4 +++
 src/Paragraph.cpp            |  4 +--
 src/output_latex.cpp         | 52 ++++++++++++++++++++++++++++++--------
 7 files changed, 175 insertions(+), 16 deletions(-)

diff --git a/lib/doc/Customization.lyx b/lib/doc/Customization.lyx
index 5e45337483..1edd3fba10 100644
--- a/lib/doc/Customization.lyx
+++ b/lib/doc/Customization.lyx
@@ -1,5 +1,5 @@
 #LyX 2.5 created this file. For more info see https://www.lyx.org/
-\lyxformat 638
+\lyxformat 640
 \begin_document
 \begin_header
 \save_transient_properties true
@@ -15347,6 +15347,57 @@ Right_Address_Box
 \end_layout
 
 \end_deeper
+\begin_layout Description
+
+\change_inserted -712698321 1747303660
+\begin_inset Flex Code
+status collapsed
+
+\begin_layout Plain Layout
+
+\change_inserted -712698321 1747303589
+MultiPar
+\end_layout
+
+\end_inset
+
+ [
+\begin_inset Flex Code
+status collapsed
+
+\begin_layout Plain Layout
+
+\change_inserted -712698321 1747303589
+
+\emph on
+0
+\end_layout
+
+\end_inset
+
+,
+\begin_inset space \thinspace{}
+\end_inset
+
+
+\begin_inset Flex Code
+status collapsed
+
+\begin_layout Plain Layout
+
+\change_inserted -712698321 1747303589
+1
+\end_layout
+
+\end_inset
+
+] Whether multiple paragraphs are permitted in this layout.
+ This only applies to command layouts.
+ If true,
+ multiple paragraphs are put within the same command (rather than starting new 
commands for each paragraph).
+ Default is false.
+\end_layout
+
 \begin_layout Description
 \begin_inset Flex Code
 status collapsed
@@ -16941,6 +16992,8 @@ status collapsed
 
 \change_inserted -712698321 1745643926
 TheoremCrossRefName
+\change_unchanged
+
 \end_layout
 
 \end_inset
@@ -16973,6 +17026,8 @@ status collapsed
 
 \change_inserted -712698321 1745645504
 TheoremCrossRefPluralName
+\change_unchanged
+
 \end_layout
 
 \end_inset
@@ -16985,6 +17040,8 @@ status collapsed
 
 \change_inserted -712698321 1745644987
 TheoremCrossRefName
+\change_unchanged
+
 \end_layout
 
 \end_inset
diff --git a/lib/doc/de/Customization.lyx b/lib/doc/de/Customization.lyx
index 1044fb14dc..2d29921d33 100644
--- a/lib/doc/de/Customization.lyx
+++ b/lib/doc/de/Customization.lyx
@@ -1,5 +1,5 @@
 #LyX 2.5 created this file. For more info see https://www.lyx.org/
-\lyxformat 638
+\lyxformat 640
 \begin_document
 \begin_header
 \save_transient_properties true
@@ -13843,6 +13843,63 @@ Right_Address_Box
 \begin_inset Flex Code
 status collapsed
 
+\begin_layout Plain Layout
+MultiPar
+\end_layout
+
+\end_inset
+
+ [
+\begin_inset Flex Code
+status collapsed
+
+\begin_layout Plain Layout
+
+\emph on
+0
+\end_layout
+
+\end_inset
+
+,
+\begin_inset space \thinspace{}
+\end_inset
+
+
+\begin_inset Flex Code
+status collapsed
+
+\begin_layout Plain Layout
+1
+\end_layout
+
+\end_inset
+
+] Legt fest,
+ ob innerhalb dieses Layouts mehrere Absätze erlaubt sind.
+ Dies betrifft nur Layouts des Typs 
+\begin_inset Quotes gld
+\end_inset
+
+
+\lang english
+command
+\lang ngerman
+
+\begin_inset Quotes grd
+\end_inset
+
+.
+ Falls dies aktiviert ist,
+ werden mehrere Absätze als Argument ein und desselben Befehls ausgegeben 
(statt dass für jeden Absatz ein neuer Befehl ausgegeben wird).
+ Voreinstellung:
+ deaktiviert.
+\end_layout
+
+\begin_layout Description
+\begin_inset Flex Code
+status collapsed
+
 \begin_layout Plain Layout
 NeedProtect
 \end_layout
diff --git a/lib/scripts/layout2layout.py b/lib/scripts/layout2layout.py
index 176fd2643e..b3485e820e 100644
--- a/lib/scripts/layout2layout.py
+++ b/lib/scripts/layout2layout.py
@@ -364,6 +364,9 @@ currentFormat = 108
 # "TheoremCounter", "TheoremParentCounter", "TheoremStyle",
 # "TheoremCrossRefName", "TheoremCrossRefPluralName"
 
+# Incremented to format 109, 15 May 2025 by spitz
+# New Layout tag "MultiPar"
+
 # Do not forget to document format change in Customization
 # Manual (section "Declaring a new text class").
 
@@ -598,7 +601,7 @@ def convert(lines, end_format):
                 i += 1
             continue
 
-        if 101 <= format <= 107:
+        if 101 <= format <= 108:
             # nothing to do.
             i += 1
             continue
diff --git a/src/Layout.cpp b/src/Layout.cpp
index 09626bbb22..0c14c79d61 100644
--- a/src/Layout.cpp
+++ b/src/Layout.cpp
@@ -74,6 +74,7 @@ enum LayoutTags {
        LT_LATEXTYPE,
        LT_LEFTDELIM,
        LT_LEFTMARGIN,
+       LT_MULTIPAR,
        LT_NEED_CPROTECT,
        LT_NEED_MBOXPROTECT,
        LT_NEED_PROTECT,
@@ -161,7 +162,7 @@ enum LayoutTags {
 /////////////////////
 
 Layout::Layout()
-       : add_to_toc_(false), is_toc_caption_(true)
+       : add_to_toc_(false), multi_par_(false), is_toc_caption_(true)
 {
        unknown_ = false;
        margintype = MARGIN_STATIC;
@@ -324,6 +325,7 @@ bool Layout::readIgnoreForcelocal(Lexer & lex, TextClass 
const & tclass,
                { "leftdelim",      LT_LEFTDELIM },
                { "leftmargin",     LT_LEFTMARGIN },
                { "margin",         LT_MARGIN },
+               { "multipar",       LT_MULTIPAR },
                { "needcprotect",    LT_NEED_CPROTECT },
                { "needmboxprotect", LT_NEED_MBOXPROTECT },
                { "needprotect",    LT_NEED_PROTECT },
@@ -679,6 +681,10 @@ bool Layout::readIgnoreForcelocal(Lexer & lex, TextClass 
const & tclass,
                        lex >> newline_allowed;
                        break;
 
+               case LT_MULTIPAR:
+                       lex >> multi_par_;
+                       break;
+
                case LT_ALIGN:
                        readAlign(lex);
                        break;
diff --git a/src/Layout.h b/src/Layout.h
index 4722866b54..af179f6533 100644
--- a/src/Layout.h
+++ b/src/Layout.h
@@ -298,6 +298,8 @@ public:
        /// are handled as one group?
        bool isParagraphGroup() const { return par_group_; }
        ///
+       bool isMultiparCommand() const { return isCommand() && multi_par_; }
+       ///
        bool labelIsInline() const {
                return labeltype == LABEL_STATIC
                        || labeltype == LABEL_SENSITIVE
@@ -686,6 +688,8 @@ private:
        ///
        bool add_to_toc_;
        ///
+       bool multi_par_;
+       ///
        std::string toc_type_;
        ///
        bool is_toc_caption_;
diff --git a/src/Paragraph.cpp b/src/Paragraph.cpp
index 234ce3fb4b..b897c03951 100644
--- a/src/Paragraph.cpp
+++ b/src/Paragraph.cpp
@@ -2755,7 +2755,7 @@ void Paragraph::latex(BufferParams const & bparams,
        if (empty()) {
                // For InTitle commands, we have already opened a group
                // in output_latex::TeXOnePar.
-               if (style.isCommand() && !style.intitle) {
+               if (style.isCommand() && !style.intitle && 
!style.isMultiparCommand()) {
                        os << '{';
                        ++column;
                }
@@ -2795,7 +2795,7 @@ void Paragraph::latex(BufferParams const & bparams,
                        }
                        // For InTitle commands, we have already opened a group
                        // in output_latex::TeXOnePar.
-                       if (style.isCommand() && !style.intitle) {
+                       if (style.isCommand() && !style.intitle && 
!style.isMultiparCommand()) {
                                os << '{';
                                ++column;
                        }
diff --git a/src/output_latex.cpp b/src/output_latex.cpp
index 9fdc901727..b804cf4f2f 100644
--- a/src/output_latex.cpp
+++ b/src/output_latex.cpp
@@ -305,6 +305,23 @@ static TeXEnvironmentData prepareEnvironment(Buffer const 
& buf,
                                       "listpreamble:");
                }
        }
+
+       if (style.isMultiparCommand() && !style.latexname().empty()) {
+               if (!runparams.no_cprotect && 
pit->needsCProtection(runparams.moving_arg)) {
+                       if (contains(runparams.active_chars, '^'))
+                               // cprotect relies on ^ being on catcode 7
+                               os << "\\begingroup\\catcode`\\^=7";
+                       os << "\\cprotect";
+               }
+               os << "\\" << from_ascii(style.latexname());
+               // Command arguments
+               if (!style.latexargs().empty()) {
+                       OutputParams rp = runparams;
+                       rp.local_font = &pit->getFirstFontSettings(bparams);
+                       latexArgInsets(paragraphs, pit, os, rp, 
style.latexargs());
+               }
+               os << from_ascii(style.latexparam()) << "{%";
+       }
        data.style = &style;
 
        // in multilingual environments, the CJK tags have to be nested properly
@@ -340,8 +357,9 @@ static void finishEnvironment(otexstream & os, OutputParams 
const & runparams,
                state->open_encoding_ = none;
        }
 
-       if (data.style->isEnvironment()) {
-               os << breakln;
+       if (data.style->isEnvironment() || data.style->isMultiparCommand()) {
+               if (data.style->isEnvironment())
+                       os << breakln;
                bool const using_begin_end =
                        runparams.use_polyglossia ||
                                !lyxrc.language_command_end.empty();
@@ -365,8 +383,12 @@ static void finishEnvironment(otexstream & os, 
OutputParams const & runparams,
                        os << '\n';
                state->nest_level_ -= 1;
                string const & name = data.style->latexname();
-               if (!name.empty())
-                       os << "\\end{" << from_ascii(name) << "}\n";
+               if (!name.empty()) {
+                       if (data.style->isEnvironment())
+                               os << "\\end{" << from_ascii(name) << "}\n";
+                       else
+                               os << "}\n";
+               }
                state->prev_env_language_ = data.par_language;
                if (runparams.encoding != data.prev_encoding) {
                        runparams.encoding = data.prev_encoding;
@@ -738,6 +760,8 @@ namespace {
 void parStartCommand(Paragraph const & par, otexstream & os,
                     OutputParams const & runparams, Layout const & style)
 {
+       if (style.isMultiparCommand())
+               return;
        switch (style.latextype) {
        case LATEX_COMMAND:
                if (!runparams.no_cprotect && 
par.needsCProtection(runparams.moving_arg)) {
@@ -1232,7 +1256,8 @@ void TeXOnePar(Buffer const & buf,
                                                         par.parEndChange(), 
runparams);
                                os << 
bparams.encoding().latexString(docstring(1, 0x00b6)).first << "}";
                        }
-                       os << '}';
+                       if (!style.isMultiparCommand())
+                               os << '}';
                        if (!style.postcommandargs().empty())
                                latexArgInsets(par, os, runparams, 
style.postcommandargs(), "post:");
                        if (!runparams.post_macro.empty()) {
@@ -1403,7 +1428,8 @@ void TeXOnePar(Buffer const & buf,
 
        // InTitle commands need to be closed after the language has been 
closed.
        if (intitle_command) {
-               os << '}';
+               if (!style.isMultiparCommand())
+                       os << '}';
                if (!style.postcommandargs().empty())
                        latexArgInsets(par, os, runparams, 
style.postcommandargs(), "post:");
                if (!runparams.post_macro.empty()) {
@@ -1429,7 +1455,12 @@ void TeXOnePar(Buffer const & buf,
                os << bparams.encoding().latexString(docstring(1, 
0x00b6)).first << "}";
        }
 
-       if (pending_newline) {
+       // with multipar layouts, do not output new line for last par in group
+       bool last_multipar_command = false;
+       if (nextpar && par.layout().isMultiparCommand()
+           && nextpar->layout().latexname() != par.layout().latexname())
+               last_multipar_command = true;
+       if (pending_newline && !last_multipar_command) {
                if (unskip_newline)
                        // prevent unwanted whitespace
                        os << '%';
@@ -1514,7 +1545,7 @@ void TeXOnePar(Buffer const & buf,
        // we don't need a newline for the last paragraph!!!
        // Note from JMarc: we will re-add a \n explicitly in
        // TeXEnvironment, because it is needed in this case
-       if (nextpar && !os.afterParbreak() && !last_was_separator) {
+       if (nextpar && !os.afterParbreak() && !last_was_separator && 
!last_multipar_command) {
                if (!text.inset().getLayout().parbreakIgnored() && !merged_par)
                        // Make sure to start a new line
                        os << breakln;
@@ -1725,8 +1756,9 @@ void latexParagraphs(Buffer const & buf,
                        }
                }
 
-               if (!layout.isEnvironment() && 
par->params().leftIndent().zero()) {
-                       // This is a standard top level paragraph, TeX it and 
continue.
+               if (!layout.isEnvironment() && !layout.isMultiparCommand()
+                    && par->params().leftIndent().zero()) {
+                       // This is a standard top level single-par paragraph, 
TeX it and continue.
                        TeXOnePar(buf, text, pit, os, runparams, everypar);
                        continue;
                }
-- 
lyx-cvs mailing list
lyx-cvs@lists.lyx.org
https://lists.lyx.org/mailman/listinfo/lyx-cvs

Reply via email to