From b9b619641bf3a5cac120abba2e1b67e43995a384 Mon Sep 17 00:00:00 2001 From: Jean-Marc Lasgouttes Date: Sat, 6 Nov 2010 15:06:19 +0000 Subject: [PATCH] This patch implements proper ERT behaviour for normal layouts. In particular, it makes paragraph breaks generate single \n in latex output when ParbreakIsNewline is true This means that it is not necessary anymore to use newlines to break lines. Plain paragraph breaks can be used instead, like is done now in ERT/Listings. This is mainly aimed at sweave support. lyx2lyx support courtesy of Richard Heck git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@36163 a592a061-630c-0410-9148-cb99ea01b6c8 --- lib/layouts/chess.layout | 1 + lib/layouts/db_lyxmacros.inc | 1 + lib/layouts/db_stdlayouts.inc | 1 + lib/layouts/elsart.layout | 2 + lib/layouts/lilypond.module | 1 + lib/layouts/linguistics.module | 2 + lib/layouts/literate-scrap.inc | 6 +- lib/layouts/noweb.module | 14 +--- lib/layouts/revtex4.layout | 3 + lib/layouts/sweave.module | 13 ++- lib/lyx2lyx/lyx2lyx_tools.py | 2 +- lib/lyx2lyx/lyx_2_0.py | 142 ++++++++++++++++++++++++++++++++- src/Buffer.cpp | 2 +- src/Cursor.cpp | 14 ++-- src/CutAndPaste.cpp | 7 +- src/Text.cpp | 9 +-- src/output_latex.cpp | 30 ++++++- 17 files changed, 205 insertions(+), 45 deletions(-) diff --git a/lib/layouts/chess.layout b/lib/layouts/chess.layout index 78ea216432..910800074a 100644 --- a/lib/layouts/chess.layout +++ b/lib/layouts/chess.layout @@ -42,6 +42,7 @@ Style Mainline LabelString "Mainline:" Newline 0 PassThru 1 + ParbreakIsNewline 1 TopSep 0.0 ParSep 0.0 LabelFont diff --git a/lib/layouts/db_lyxmacros.inc b/lib/layouts/db_lyxmacros.inc index 4b3f790b13..8db8e8fa8f 100644 --- a/lib/layouts/db_lyxmacros.inc +++ b/lib/layouts/db_lyxmacros.inc @@ -13,6 +13,7 @@ Style Code LatexType Environment LatexName screen PassThru 1 + ParbreakIsNewline 1 End Style LyX-Code diff --git a/lib/layouts/db_stdlayouts.inc b/lib/layouts/db_stdlayouts.inc index 45a654f8bc..533fc57a81 100644 --- a/lib/layouts/db_stdlayouts.inc +++ b/lib/layouts/db_stdlayouts.inc @@ -12,6 +12,7 @@ Style Literal LatexType Environment LatexName literallayout PassThru 1 + ParbreakIsNewline 1 End diff --git a/lib/layouts/elsart.layout b/lib/layouts/elsart.layout index b09230e4af..c48eff7781 100644 --- a/lib/layouts/elsart.layout +++ b/lib/layouts/elsart.layout @@ -149,6 +149,7 @@ Style Author_Email LatexType Command InTitle 1 PassThru 1 + ParbreakIsNewline 1 LatexName ead Align Center Labeltype Static @@ -169,6 +170,7 @@ Style Author_URL LatexType Command InTitle 1 PassThru 1 + ParbreakIsNewline 1 LatexName ead LatexParam "[url]" Align Center diff --git a/lib/layouts/lilypond.module b/lib/layouts/lilypond.module index 45508bab60..a01d68a682 100644 --- a/lib/layouts/lilypond.module +++ b/lib/layouts/lilypond.module @@ -28,5 +28,6 @@ InsetLayout LilyPond ForcePlain true FreeSpacing true PassThru true + ParbreakIsNewline true ForceLTR true End diff --git a/lib/layouts/linguistics.module b/lib/layouts/linguistics.module index 80772aabb7..aadaf927a0 100644 --- a/lib/layouts/linguistics.module +++ b/lib/layouts/linguistics.module @@ -75,6 +75,7 @@ InsetLayout Flex:Glosse CustomPars false ForcePlain true PassThru true + ParbreakIsNewline true FreeSpacing true ForceLTR true Requires covington @@ -103,6 +104,7 @@ InsetLayout Flex:Tri-Glosse CustomPars false ForcePlain true PassThru true + ParbreakIsNewline true FreeSpacing true ForceLTR true InToc true diff --git a/lib/layouts/literate-scrap.inc b/lib/layouts/literate-scrap.inc index 3b0017de0d..b51553606f 100644 --- a/lib/layouts/literate-scrap.inc +++ b/lib/layouts/literate-scrap.inc @@ -13,14 +13,10 @@ Style Scrap Margin First_Dynamic LatexType Paragraph LatexName dummy - NewLine 0 LeftMargin MMM - ParSep 0.4 - TopSep 0.4 - BottomSep 0.4 - ItemSep 0.4 Align Left AlignPossible Block,Left + NewLine 0 FreeSpacing 1 PassThru 1 ParbreakIsNewline 1 diff --git a/lib/layouts/noweb.module b/lib/layouts/noweb.module index cc71c338a8..aff85627a3 100644 --- a/lib/layouts/noweb.module +++ b/lib/layouts/noweb.module @@ -4,14 +4,6 @@ #DescriptionEnd #Category: literate -# Suggested style to write your code: -# Within same scrap, lines are separated by newlines (Ctrl-Return), use: -# ItemSep 0.4 -# . disavantage: must type ctrl-return every single line -# . advantage: looks better (IMHO) -# resembles more closely the produced paper doc (more WYSIWYG) -# - Format 30 OutputType literate @@ -20,14 +12,10 @@ Style Scrap Margin First_Dynamic LatexType Paragraph LatexName dummy - NewLine 0 LeftMargin MMM - ParSep 0.4 - TopSep 0.4 - BottomSep 0.4 - ItemSep 0.4 Align Left AlignPossible Block,Left + NewLine 0 FreeSpacing 1 PassThru 1 ParbreakIsNewline 1 diff --git a/lib/layouts/revtex4.layout b/lib/layouts/revtex4.layout index 15fc8dce80..87e99917cf 100644 --- a/lib/layouts/revtex4.layout +++ b/lib/layouts/revtex4.layout @@ -171,6 +171,7 @@ End Style AltAffiliation CopyStyle Affiliation PassThru 1 + ParbreakIsNewline 1 LatexName altaffiliation OptionalArgs 1 LabelString "AltAffiliation" @@ -196,6 +197,7 @@ End Style Author_Email CopyStyle Affiliation PassThru 1 + ParbreakIsNewline 1 LatexName email OptionalArgs 1 LabelString "Electronic Address:" @@ -211,6 +213,7 @@ End Style Author_URL CopyStyle Author_Email PassThru 1 + ParbreakIsNewline 1 LatexName homepage OptionalArgs 1 LabelString "URL:" diff --git a/lib/layouts/sweave.module b/lib/layouts/sweave.module index a6821ac49a..836ff73e85 100644 --- a/lib/layouts/sweave.module +++ b/lib/layouts/sweave.module @@ -22,10 +22,6 @@ Style Chunk LatexType Paragraph LatexName dummy Margin static - ParSep 0.4 - TopSep 0.4 - BottomSep 0.4 - ItemSep 0.4 Align Left AlignPossible Block, Left, Right, Center NewLine 0 @@ -59,7 +55,8 @@ InsetLayout "Sweave Options" Size Small EndFont MultiPar false - PassThru true + PassThru 1 + ParbreakIsNewline 1 FreeSpacing true ForceLTR true End @@ -79,7 +76,8 @@ InsetLayout "S/R expression" Size Small EndFont MultiPar false - PassThru true + PassThru 1 + ParbreakIsNewline 1 FreeSpacing true ForceLTR true End @@ -99,7 +97,8 @@ InsetLayout "Sweave Input File" Size Small EndFont MultiPar false - PassThru true + PassThru 1 + ParbreakIsNewline 1 FreeSpacing true ForceLTR true End diff --git a/lib/lyx2lyx/lyx2lyx_tools.py b/lib/lyx2lyx/lyx2lyx_tools.py index 426e11d969..bff4808596 100644 --- a/lib/lyx2lyx/lyx2lyx_tools.py +++ b/lib/lyx2lyx/lyx2lyx_tools.py @@ -65,7 +65,7 @@ from unicode_symbols import unicode_reps # This will accept either a list of lines or a single line. -# It is bad practice to pass something with embedded newlines, +# It is bad practice to pass something with embedded newlines, # though we will handle that. def add_to_preamble(document, text): " Add text to the preamble if it is not already there. " diff --git a/lib/lyx2lyx/lyx_2_0.py b/lib/lyx2lyx/lyx_2_0.py index 8f60458d0f..624bad9347 100644 --- a/lib/lyx2lyx/lyx_2_0.py +++ b/lib/lyx2lyx/lyx_2_0.py @@ -1952,6 +1952,142 @@ def convert_bibtex_clearpage(document): j = k + len(subst) +def check_passthru(document): + tc = document.textclass + ok = (tc == "literate-article" or tc == "literate-book" or tc == "literate-report") + if not ok: + mods = document.get_module_list() + for mod in mods: + if mod == "sweave" or mod == "noweb": + ok = True + break + return ok + + +def convert_passthru(document): + " http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg161298.html " + if not check_passthru: + return + + rx = re.compile("\\\\begin_layout \s*(\w+)") + beg = 0 + for lay in ["Chunk", "Scrap"]: + while True: + beg = find_token(document.body, "\\begin_layout " + lay, beg) + if beg == -1: + break + end = find_end_of_layout(document.body, beg) + if end == -1: + document.warning("Can't find end of layout at line " + str(beg)) + beg += 1 + continue + # we are now going to replace newline insets within this layout + # by new instances of this layout. so we have repeated layouts + # instead of newlines. + ns = beg + while True: + ns = find_token(document.body, "\\begin_inset Newline newline", ns, end) + if ns == -1: + break + ne = find_end_of_inset(document.body, ns) + if ne == -1 or ne > end: + document.warning("Can't find end of inset at line " + str(nb)) + ns += 1 + continue + if document.body[ne + 1] == "": + ne += 1 + subst = ["\\end_layout", "", "\\begin_layout " + lay] + document.body[ns:ne + 1] = subst + # now we need to adjust end, in particular, but might as well + # do ns properly, too + newlines = (ne - ns) - len(subst) + ns += newlines + 2 + end += newlines + 1 + # ok, we now want to find out if the next layout is the + # same as this one. if so, we will insert an extra copy of it + didit = False + next = find_token(document.body, "\\begin_layout", end) + if next != -1: + m = rx.match(document.body[next]) + if m: + nextlay = m.group(1) + if nextlay == lay: + subst = ["\\begin_layout " + lay, "", "\\end_layout", ""] + document.body[next:next] = subst + didit = True + beg = end + 1 + if didit: + beg += 4 # for the extra layout + + +def revert_passthru(document): + " http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg161298.html " + if not check_passthru: + return + rx = re.compile("\\\\begin_layout \s*(\w+)") + beg = 0 + for lay in ["Chunk", "Scrap"]: + while True: + beg = find_token(document.body, "\\begin_layout " + lay, beg) + if beg == -1: + break + end = find_end_of_layout(document.body, beg) + if end == -1: + document.warning("Can't find end of layout at line " + str(beg)) + beg += 1 + continue + + # we now want to find out if the next layout is the + # same as this one. but we will need to do this over and + # over again. + while True: + next = find_token(document.body, "\\begin_layout", end) + if next == -1: + break + m = rx.match(document.body[next]) + if not m: + break + nextlay = m.group(1) + if nextlay != lay: + break + # so it is the same layout again. we now want to know if it is empty. + # but first let's check and make sure there is no content between the + # two layouts. i'm not sure if that can happen or not. + for l in range(end + 1, next): + document.warning("c'" + document.body[l] + "'") + if document.body[l] != "": + document.warning("Found content between adjacent " + lay + " layouts!") + break + nextend = find_end_of_layout(document.body, next) + if nextend == -1: + document.warning("Can't find end of layout at line " + str(next)) + break + empty = True + for l in range(next + 1, nextend): + document.warning("e'" + document.body[l] + "'") + if document.body[l] != "": + empty = False + break + if empty: + # empty layouts just get removed + # should we check if it's before yet another such layout? + del document.body[next : nextend + 1] + # and we do not want to check again. we know the next layout + # should be another Chunk and should be left as is. + break + else: + # if it's not empty, then we want to insert a newline in place + # of the layout switch + subst = ["\\begin_inset Newline newline", "\\end_inset", ""] + document.body[end : next + 1] = subst + # and now we have to find the end of the new, larger layout + newend = find_end_of_layout(document.body, beg) + if newend == -1: + document.warning("Can't find end of new layout at line " + str(beg)) + break + end = newend + beg = end + 1 + ## # Conversion hub # @@ -2016,10 +2152,12 @@ convert = [[346, []], [402, [convert_bibtex_clearpage]], [403, [convert_flexnames]], [404, [convert_prettyref]], - [405, []] + [405, []], + [406, [convert_passthru]] ] -revert = [[404, []], +revert = [[405, [revert_passthru]], + [404, []], [403, [revert_refstyle]], [402, [revert_flexnames]], [401, []], diff --git a/src/Buffer.cpp b/src/Buffer.cpp index 2d2ede3c44..bf8e496d51 100644 --- a/src/Buffer.cpp +++ b/src/Buffer.cpp @@ -128,7 +128,7 @@ namespace { // Do not remove the comment below, so we get merge conflict in // independent branches. Instead add your own. -int const LYX_FORMAT = 405; // vfr: author hash +int const LYX_FORMAT = 406; // rgh: passthru changes typedef map DepClean; typedef map > RefCache; diff --git a/src/Cursor.cpp b/src/Cursor.cpp index f6d10cbc97..c2b6d72989 100644 --- a/src/Cursor.cpp +++ b/src/Cursor.cpp @@ -26,6 +26,7 @@ #include "FuncCode.h" #include "FuncRequest.h" #include "Language.h" +#include "Layout.h" #include "LyXAction.h" #include "LyXRC.h" #include "Paragraph.h" @@ -2016,15 +2017,18 @@ void Cursor::errorMessage(docstring const & msg) const } -static docstring parbreak(InsetCode code) +namespace { +docstring parbreak(Cursor const * cur) { odocstringstream os; os << '\n'; - // only add blank line if we're not in an ERT or Listings inset - if (code != ERT_CODE && code != LISTINGS_CODE) + // only add blank line if we're not in a ParbreakIsNewline situation + if (!cur->inset().getLayout().parbreakIsNewline() + && !cur->paragraph().layout().parbreak_is_newline) os << '\n'; return os.str(); } +} docstring Cursor::selectionAsString(bool with_label) const @@ -2060,13 +2064,13 @@ docstring Cursor::selectionAsString(bool with_label) const // First paragraph in selection docstring result = pars[startpit]. asString(startpos, pars[startpit].size(), label) - + parbreak(inset().lyxCode()); + + parbreak(this); // The paragraphs in between (if any) for (pit_type pit = startpit + 1; pit != endpit; ++pit) { Paragraph const & par = pars[pit]; result += par.asString(0, par.size(), label) - + parbreak(inset().lyxCode()); + + parbreak(this); } // Last paragraph in selection diff --git a/src/CutAndPaste.cpp b/src/CutAndPaste.cpp index 18993152f3..9bed935d38 100644 --- a/src/CutAndPaste.cpp +++ b/src/CutAndPaste.cpp @@ -124,10 +124,9 @@ pasteSelectionHelper(Cursor & cur, ParagraphList const & parlist, // Now remove all out of the pars which is NOT allowed in the // new environment and set also another font if that is required. - // Convert newline to paragraph break in ERT inset. - // This should not be here! - InsetCode const code = target_inset->lyxCode(); - if (code == ERT_CODE || code == LISTINGS_CODE) { + // Convert newline to paragraph break in ParbreakIsNewline + if (target_inset->getLayout().parbreakIsNewline() + || pars[pit].layout().parbreak_is_newline) { for (size_t i = 0; i != insertion.size(); ++i) { for (pos_type j = 0; j != insertion[i].size(); ++j) { if (insertion[i].isNewline(j)) { diff --git a/src/Text.cpp b/src/Text.cpp index f6f75d9045..63cf1734b9 100644 --- a/src/Text.cpp +++ b/src/Text.cpp @@ -599,7 +599,6 @@ static void breakParagraph(Text & text, pit_type par_offset, pos_type pos, // end of a paragraph tmp->setPlainOrDefaultLayout(bparams.documentClass()); - // layout stays the same with latex-environments if (keep_layout) { tmp->setLayout(par.layout()); tmp->setLabelWidthString(par.params().labelWidthString()); @@ -665,7 +664,6 @@ static void breakParagraph(Text & text, pit_type par_offset, pos_type pos, par.setPlainOrDefaultLayout(bparams.documentClass()); } - // layout stays the same with latex-environments if (keep_layout) { par.setLayout(tmp->layout()); par.setLabelWidthString(tmp->params().labelWidthString()); @@ -701,9 +699,10 @@ void Text::breakParagraph(Cursor & cur, bool inverse_logic) cpar.eraseChar(cur.pos(), cur.buffer()->params().trackChanges); // What should the layout for the new paragraph be? - bool keep_layout = inverse_logic ? - !layout.isEnvironment() - : layout.isEnvironment(); + bool keep_layout = layout.isEnvironment() + || (layout.isParagraph() && layout.parbreak_is_newline); + if (inverse_logic) + keep_layout = !keep_layout; // We need to remember this before we break the paragraph, because // that invalidates the layout variable diff --git a/src/output_latex.cpp b/src/output_latex.cpp index 391ccfaee1..ea4d035367 100644 --- a/src/output_latex.cpp +++ b/src/output_latex.cpp @@ -374,14 +374,18 @@ ParagraphList::const_iterator TeXOnePar(Buffer const & buf, open_encoding_ = none; } - if (runparams.pass_thru) { + if (text.inset().getLayout().isPassThru()) { int const dist = distance(paragraphs.begin(), pit); Font const outerfont = text.outerFont(dist); - // No newline if only one paragraph in this lyxtext + // No newline before first paragraph in this lyxtext if (dist > 0) { os << '\n'; texrow.newline(); + if (!text.inset().getLayout().parbreakIsNewline()) { + os << '\n'; + texrow.newline(); + } } pit->latex(bparams, outerfont, os, texrow, @@ -389,6 +393,28 @@ ParagraphList::const_iterator TeXOnePar(Buffer const & buf, return nextpit; } + if (style.pass_thru) { + int const dist = distance(paragraphs.begin(), pit); + Font const outerfont = text.outerFont(dist); + pit->latex(bparams, outerfont, os, texrow, + runparams, start_pos, end_pos); + os << '\n'; + texrow.newline(); + if (!style.parbreak_is_newline) { + os << '\n'; + texrow.newline(); + } else if (nextpit != paragraphs.end()) { + Layout const nextstyle = text.inset().forcePlainLayout() ? + bparams.documentClass().plainLayout() : nextpit->layout(); + if (nextstyle.name() != style.name()) { + os << '\n'; + texrow.newline(); + } + } + + return nextpit; + } + // This paragraph's language Language const * const par_language = pit->getParLanguage(bparams); // The document's language