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
This commit is contained in:
Jean-Marc Lasgouttes 2010-11-06 15:06:19 +00:00
parent 04e6076ebb
commit b9b619641b
17 changed files with 205 additions and 45 deletions

View File

@ -42,6 +42,7 @@ Style Mainline
LabelString "Mainline:" LabelString "Mainline:"
Newline 0 Newline 0
PassThru 1 PassThru 1
ParbreakIsNewline 1
TopSep 0.0 TopSep 0.0
ParSep 0.0 ParSep 0.0
LabelFont LabelFont

View File

@ -13,6 +13,7 @@ Style Code
LatexType Environment LatexType Environment
LatexName screen LatexName screen
PassThru 1 PassThru 1
ParbreakIsNewline 1
End End
Style LyX-Code Style LyX-Code

View File

@ -12,6 +12,7 @@ Style Literal
LatexType Environment LatexType Environment
LatexName literallayout LatexName literallayout
PassThru 1 PassThru 1
ParbreakIsNewline 1
End End

View File

@ -149,6 +149,7 @@ Style Author_Email
LatexType Command LatexType Command
InTitle 1 InTitle 1
PassThru 1 PassThru 1
ParbreakIsNewline 1
LatexName ead LatexName ead
Align Center Align Center
Labeltype Static Labeltype Static
@ -169,6 +170,7 @@ Style Author_URL
LatexType Command LatexType Command
InTitle 1 InTitle 1
PassThru 1 PassThru 1
ParbreakIsNewline 1
LatexName ead LatexName ead
LatexParam "[url]" LatexParam "[url]"
Align Center Align Center

View File

@ -28,5 +28,6 @@ InsetLayout LilyPond
ForcePlain true ForcePlain true
FreeSpacing true FreeSpacing true
PassThru true PassThru true
ParbreakIsNewline true
ForceLTR true ForceLTR true
End End

View File

@ -75,6 +75,7 @@ InsetLayout Flex:Glosse
CustomPars false CustomPars false
ForcePlain true ForcePlain true
PassThru true PassThru true
ParbreakIsNewline true
FreeSpacing true FreeSpacing true
ForceLTR true ForceLTR true
Requires covington Requires covington
@ -103,6 +104,7 @@ InsetLayout Flex:Tri-Glosse
CustomPars false CustomPars false
ForcePlain true ForcePlain true
PassThru true PassThru true
ParbreakIsNewline true
FreeSpacing true FreeSpacing true
ForceLTR true ForceLTR true
InToc true InToc true

View File

@ -13,14 +13,10 @@ Style Scrap
Margin First_Dynamic Margin First_Dynamic
LatexType Paragraph LatexType Paragraph
LatexName dummy LatexName dummy
NewLine 0
LeftMargin MMM LeftMargin MMM
ParSep 0.4
TopSep 0.4
BottomSep 0.4
ItemSep 0.4
Align Left Align Left
AlignPossible Block,Left AlignPossible Block,Left
NewLine 0
FreeSpacing 1 FreeSpacing 1
PassThru 1 PassThru 1
ParbreakIsNewline 1 ParbreakIsNewline 1

View File

@ -4,14 +4,6 @@
#DescriptionEnd #DescriptionEnd
#Category: literate #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 Format 30
OutputType literate OutputType literate
@ -20,14 +12,10 @@ Style Scrap
Margin First_Dynamic Margin First_Dynamic
LatexType Paragraph LatexType Paragraph
LatexName dummy LatexName dummy
NewLine 0
LeftMargin MMM LeftMargin MMM
ParSep 0.4
TopSep 0.4
BottomSep 0.4
ItemSep 0.4
Align Left Align Left
AlignPossible Block,Left AlignPossible Block,Left
NewLine 0
FreeSpacing 1 FreeSpacing 1
PassThru 1 PassThru 1
ParbreakIsNewline 1 ParbreakIsNewline 1

View File

@ -171,6 +171,7 @@ End
Style AltAffiliation Style AltAffiliation
CopyStyle Affiliation CopyStyle Affiliation
PassThru 1 PassThru 1
ParbreakIsNewline 1
LatexName altaffiliation LatexName altaffiliation
OptionalArgs 1 OptionalArgs 1
LabelString "AltAffiliation" LabelString "AltAffiliation"
@ -196,6 +197,7 @@ End
Style Author_Email Style Author_Email
CopyStyle Affiliation CopyStyle Affiliation
PassThru 1 PassThru 1
ParbreakIsNewline 1
LatexName email LatexName email
OptionalArgs 1 OptionalArgs 1
LabelString "Electronic Address:" LabelString "Electronic Address:"
@ -211,6 +213,7 @@ End
Style Author_URL Style Author_URL
CopyStyle Author_Email CopyStyle Author_Email
PassThru 1 PassThru 1
ParbreakIsNewline 1
LatexName homepage LatexName homepage
OptionalArgs 1 OptionalArgs 1
LabelString "URL:" LabelString "URL:"

View File

@ -22,10 +22,6 @@ Style Chunk
LatexType Paragraph LatexType Paragraph
LatexName dummy LatexName dummy
Margin static Margin static
ParSep 0.4
TopSep 0.4
BottomSep 0.4
ItemSep 0.4
Align Left Align Left
AlignPossible Block, Left, Right, Center AlignPossible Block, Left, Right, Center
NewLine 0 NewLine 0
@ -59,7 +55,8 @@ InsetLayout "Sweave Options"
Size Small Size Small
EndFont EndFont
MultiPar false MultiPar false
PassThru true PassThru 1
ParbreakIsNewline 1
FreeSpacing true FreeSpacing true
ForceLTR true ForceLTR true
End End
@ -79,7 +76,8 @@ InsetLayout "S/R expression"
Size Small Size Small
EndFont EndFont
MultiPar false MultiPar false
PassThru true PassThru 1
ParbreakIsNewline 1
FreeSpacing true FreeSpacing true
ForceLTR true ForceLTR true
End End
@ -99,7 +97,8 @@ InsetLayout "Sweave Input File"
Size Small Size Small
EndFont EndFont
MultiPar false MultiPar false
PassThru true PassThru 1
ParbreakIsNewline 1
FreeSpacing true FreeSpacing true
ForceLTR true ForceLTR true
End End

View File

@ -1952,6 +1952,142 @@ def convert_bibtex_clearpage(document):
j = k + len(subst) 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 # Conversion hub
# #
@ -2016,10 +2152,12 @@ convert = [[346, []],
[402, [convert_bibtex_clearpage]], [402, [convert_bibtex_clearpage]],
[403, [convert_flexnames]], [403, [convert_flexnames]],
[404, [convert_prettyref]], [404, [convert_prettyref]],
[405, []] [405, []],
[406, [convert_passthru]]
] ]
revert = [[404, []], revert = [[405, [revert_passthru]],
[404, []],
[403, [revert_refstyle]], [403, [revert_refstyle]],
[402, [revert_flexnames]], [402, [revert_flexnames]],
[401, []], [401, []],

View File

@ -128,7 +128,7 @@ namespace {
// Do not remove the comment below, so we get merge conflict in // Do not remove the comment below, so we get merge conflict in
// independent branches. Instead add your own. // independent branches. Instead add your own.
int const LYX_FORMAT = 405; // vfr: author hash int const LYX_FORMAT = 406; // rgh: passthru changes
typedef map<string, bool> DepClean; typedef map<string, bool> DepClean;
typedef map<docstring, pair<InsetLabel const *, Buffer::References> > RefCache; typedef map<docstring, pair<InsetLabel const *, Buffer::References> > RefCache;

View File

@ -26,6 +26,7 @@
#include "FuncCode.h" #include "FuncCode.h"
#include "FuncRequest.h" #include "FuncRequest.h"
#include "Language.h" #include "Language.h"
#include "Layout.h"
#include "LyXAction.h" #include "LyXAction.h"
#include "LyXRC.h" #include "LyXRC.h"
#include "Paragraph.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; odocstringstream os;
os << '\n'; os << '\n';
// only add blank line if we're not in an ERT or Listings inset // only add blank line if we're not in a ParbreakIsNewline situation
if (code != ERT_CODE && code != LISTINGS_CODE) if (!cur->inset().getLayout().parbreakIsNewline()
&& !cur->paragraph().layout().parbreak_is_newline)
os << '\n'; os << '\n';
return os.str(); return os.str();
} }
}
docstring Cursor::selectionAsString(bool with_label) const docstring Cursor::selectionAsString(bool with_label) const
@ -2060,13 +2064,13 @@ docstring Cursor::selectionAsString(bool with_label) const
// First paragraph in selection // First paragraph in selection
docstring result = pars[startpit]. docstring result = pars[startpit].
asString(startpos, pars[startpit].size(), label) asString(startpos, pars[startpit].size(), label)
+ parbreak(inset().lyxCode()); + parbreak(this);
// The paragraphs in between (if any) // The paragraphs in between (if any)
for (pit_type pit = startpit + 1; pit != endpit; ++pit) { for (pit_type pit = startpit + 1; pit != endpit; ++pit) {
Paragraph const & par = pars[pit]; Paragraph const & par = pars[pit];
result += par.asString(0, par.size(), label) result += par.asString(0, par.size(), label)
+ parbreak(inset().lyxCode()); + parbreak(this);
} }
// Last paragraph in selection // Last paragraph in selection

View File

@ -124,10 +124,9 @@ pasteSelectionHelper(Cursor & cur, ParagraphList const & parlist,
// Now remove all out of the pars which is NOT allowed in the // Now remove all out of the pars which is NOT allowed in the
// new environment and set also another font if that is required. // new environment and set also another font if that is required.
// Convert newline to paragraph break in ERT inset. // Convert newline to paragraph break in ParbreakIsNewline
// This should not be here! if (target_inset->getLayout().parbreakIsNewline()
InsetCode const code = target_inset->lyxCode(); || pars[pit].layout().parbreak_is_newline) {
if (code == ERT_CODE || code == LISTINGS_CODE) {
for (size_t i = 0; i != insertion.size(); ++i) { for (size_t i = 0; i != insertion.size(); ++i) {
for (pos_type j = 0; j != insertion[i].size(); ++j) { for (pos_type j = 0; j != insertion[i].size(); ++j) {
if (insertion[i].isNewline(j)) { if (insertion[i].isNewline(j)) {

View File

@ -599,7 +599,6 @@ static void breakParagraph(Text & text, pit_type par_offset, pos_type pos,
// end of a paragraph // end of a paragraph
tmp->setPlainOrDefaultLayout(bparams.documentClass()); tmp->setPlainOrDefaultLayout(bparams.documentClass());
// layout stays the same with latex-environments
if (keep_layout) { if (keep_layout) {
tmp->setLayout(par.layout()); tmp->setLayout(par.layout());
tmp->setLabelWidthString(par.params().labelWidthString()); 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()); par.setPlainOrDefaultLayout(bparams.documentClass());
} }
// layout stays the same with latex-environments
if (keep_layout) { if (keep_layout) {
par.setLayout(tmp->layout()); par.setLayout(tmp->layout());
par.setLabelWidthString(tmp->params().labelWidthString()); 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); cpar.eraseChar(cur.pos(), cur.buffer()->params().trackChanges);
// What should the layout for the new paragraph be? // What should the layout for the new paragraph be?
bool keep_layout = inverse_logic ? bool keep_layout = layout.isEnvironment()
!layout.isEnvironment() || (layout.isParagraph() && layout.parbreak_is_newline);
: layout.isEnvironment(); if (inverse_logic)
keep_layout = !keep_layout;
// We need to remember this before we break the paragraph, because // We need to remember this before we break the paragraph, because
// that invalidates the layout variable // that invalidates the layout variable

View File

@ -374,14 +374,18 @@ ParagraphList::const_iterator TeXOnePar(Buffer const & buf,
open_encoding_ = none; open_encoding_ = none;
} }
if (runparams.pass_thru) { if (text.inset().getLayout().isPassThru()) {
int const dist = distance(paragraphs.begin(), pit); int const dist = distance(paragraphs.begin(), pit);
Font const outerfont = text.outerFont(dist); 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) { if (dist > 0) {
os << '\n'; os << '\n';
texrow.newline(); texrow.newline();
if (!text.inset().getLayout().parbreakIsNewline()) {
os << '\n';
texrow.newline();
}
} }
pit->latex(bparams, outerfont, os, texrow, pit->latex(bparams, outerfont, os, texrow,
@ -389,6 +393,28 @@ ParagraphList::const_iterator TeXOnePar(Buffer const & buf,
return nextpit; 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 // This paragraph's language
Language const * const par_language = pit->getParLanguage(bparams); Language const * const par_language = pit->getParLanguage(bparams);
// The document's language // The document's language