From 8f044f3c953798bc8046193b0fce613da6228e34 Mon Sep 17 00:00:00 2001 From: Richard Heck Date: Thu, 30 May 2013 09:12:48 -0400 Subject: [PATCH] Patch to convert Sweave chunk paragraphs to insets (bug #8588). Work by Liviu (C++) and Richard (Python). --- lib/Makefile.am | 1 + lib/layouts/knitr.module | 27 +----- lib/layouts/litinsets.inc | 41 +++++++++ lib/layouts/noweb.module | 23 +---- lib/layouts/sweave.module | 27 +----- lib/lyx2lyx/lyx_2_1.py | 169 +++++++++++++++++++++++++++++++++++- lib/lyx2lyx/parser_tools.py | 5 +- src/version.h | 2 +- 8 files changed, 217 insertions(+), 78 deletions(-) create mode 100644 lib/layouts/litinsets.inc diff --git a/lib/Makefile.am b/lib/Makefile.am index cfdbc94b69..39340a2d57 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -1932,6 +1932,7 @@ dist_layouts_DATA =\ layouts/lettre.layout \ layouts/lilypond.module \ layouts/linguistics.module \ + layouts/litinsets.inc \ layouts/llncs.layout \ layouts/logicalmkup.module \ layouts/ltugboat.layout \ diff --git a/lib/layouts/knitr.module b/lib/layouts/knitr.module index 020397324a..e7ccb34222 100644 --- a/lib/layouts/knitr.module +++ b/lib/layouts/knitr.module @@ -7,35 +7,10 @@ #Excludes: lilypond | sweave Format 45 +Input litinsets.inc OutputType literate OutputFormat knitr -Style Chunk - Category Sweave - LatexType Paragraph - LatexName dummy - Margin static - Align Left - AlignPossible Block, Left, Right, Center - TopSep 0.7 - BottomSep 0.7 - NewLine 0 - FreeSpacing 1 - PassThru 1 - ParbreakIsNewline 1 - Spellcheck 0 - ## What is LabelType used for? - LabelType Static - TextFont - Color latex - Family Typewriter - EndFont -End - -Style Scrap - ObsoletedBy Chunk -End - InsetLayout "Flex:Sweave Options" LabelString "Sweave opts" LatexType Command diff --git a/lib/layouts/litinsets.inc b/lib/layouts/litinsets.inc new file mode 100644 index 0000000000..4f95019451 --- /dev/null +++ b/lib/layouts/litinsets.inc @@ -0,0 +1,41 @@ +# Literate Chunk inset definitions. +# This defines the Chunk inset used in the literate modules. +# +# Author: Liviu Andronic +# +# Note that this file is included in sweave.module, +# knitr.module and noweb.module. + +Format 45 + +InsetLayout "Flex:Chunk" + LabelString "Chunk" + LatexType none + LyXType Custom + RightDelim
@ + Decoration Classic + Font + Color latex + Family typewriter + EndFont + #LabelFont + #Color latex + #Size Small + #EndFont + MultiPar true + CustomPars false + ForcePlain true + PassThru 1 + ParbreakIsNewline 1 + KeepEmpty true + Spellcheck 0 + FreeSpacing true + ForceLTR true + Argument 1 + Mandatory 1 + LabelString "Options" + Tooltip "Options" + LeftDelim << + RightDelim >>=
+ EndArgument +End diff --git a/lib/layouts/noweb.module b/lib/layouts/noweb.module index fc105fd051..da8e96b8aa 100644 --- a/lib/layouts/noweb.module +++ b/lib/layouts/noweb.module @@ -5,30 +5,9 @@ #Category: literate Format 45 +Input litinsets.inc OutputType literate AddToPreamble \usepackage{noweb} EndPreamble - -Style Chunk - Margin First_Dynamic - LatexType Paragraph - LatexName dummy - LeftMargin MMM - Align Left - AlignPossible Block,Left - NewLine 0 - FreeSpacing 1 - PassThru 1 - ParbreakIsNewline 1 - Spellcheck 0 - LabelType Static - LabelFont - Color magenta - EndFont - TextFont - Color latex - Family Typewriter - EndFont -End diff --git a/lib/layouts/sweave.module b/lib/layouts/sweave.module index 912642040d..dd0e642ef1 100644 --- a/lib/layouts/sweave.module +++ b/lib/layouts/sweave.module @@ -7,6 +7,7 @@ #Excludes: lilypond Format 45 +Input litinsets.inc OutputType literate OutputFormat sweave @@ -20,32 +21,6 @@ AddToPreamble @ EndPreamble -Style Chunk - Category Sweave - LatexType Paragraph - LatexName dummy - Margin static - Align Left - AlignPossible Block, Left, Right, Center - TopSep 0.7 - BottomSep 0.7 - NewLine 0 - FreeSpacing 1 - PassThru 1 - ParbreakIsNewline 1 - Spellcheck 0 - ## What is LabelType used for? - LabelType Static - TextFont - Color latex - Family Typewriter - EndFont -End - -Style Scrap - ObsoletedBy Chunk -End - InsetLayout "Flex:Sweave Options" LabelString "Sweave opts" LatexType Command diff --git a/lib/lyx2lyx/lyx_2_1.py b/lib/lyx2lyx/lyx_2_1.py index 0c38796f6f..c95e94b174 100644 --- a/lib/lyx2lyx/lyx_2_1.py +++ b/lib/lyx2lyx/lyx_2_1.py @@ -4229,6 +4229,171 @@ def revert_tibetan(document): j = len(document.body) +############# +# +# Chunk stuff +# +############# + +# the idea here is that we will have a sequence of chunk paragraphs +# we want to convert them to paragraphs in a chunk inset +# the last will be discarded +# the first should look like: <>= +# will will discard the delimiters, and put the contents into the +# optional argument of the inset +def convert_chunks(document): + first_re = re.compile(r'<<(.*)>>=') + k = 0 + while True: + # the beginning of this sequence + i = k + # find start of a block of chunks + i = find_token(document.body, "\\begin_layout Chunk", i) + if i == -1: + return + start = i + end = -1 + contents = [] + + while True: + # process the one we just found + j = find_end_of_layout(document.body, i) + if j == -1: + document.warning("Malformed LyX documents. Can't find end of Chunk layout!") + break + thischunk = "".join(document.body[i + 1:j]) + contents.append(thischunk) + + if thischunk == "@": + break + + # look for the next one + i = j + i = find_token(document.body, "\\begin_layout", i) + if i == -1: + break + + layout = get_value(document.body, "\\begin_layout", i) + #sys.stderr.write(layout+ '\n') + if layout != "Chunk": + k = i + break + + if j == -1: + # error, but we can try to continue + k = j + 1 + continue + + end = j + 1 + k = end + + sys.stderr.write('\n'.join(contents) + '\n\n') + + # the last chunk should simply have an "@" in it + # we could check that + contents.pop() + + # the first item should look like: <>= + # we want the inside + optarg = contents[0] + optarg.strip() + match = first_re.search(optarg) + if match: + optarg = match.groups()[0] + contents.pop(0) + + newstuff = ['\\begin_layout Standard', + '\\begin_inset Flex Chunk', + 'status open', '', + '\\begin_layout Plain Layout', ''] + + if match: + newstuff.extend( + ['\\begin_inset Argument 1', + 'status open', '', + '\\begin_layout Plain Layout', + optarg, + '\\end_layout', '', + '\\end_inset', '']) + + didone = False + for c in contents: + if didone: + newstuff.extend(['', '\\begin_layout Plain Layout', '']) + else: + didone = True + newstuff.extend([c, '\\end_layout']) + + newstuff.extend(['', '\\end_inset', '', '\\end_layout', '']) + + document.body[start:end] = newstuff + + k += len(newstuff) - (end - start) + + +def revert_chunks(document): + i = 0 + while True: + i = find_token(document.body, "\\begin_inset Flex Chunk", i) + if i == -1: + return + + iend = find_end_of_inset(document.body, i) + if iend == -1: + document.warning("Can't find end of Chunk!") + i += 1 + continue + + # Look for optional argument + have_optarg = False + ostart = find_token(document.body, "\\begin_inset Argument 1", i, iend) + if ostart != -1: + oend = find_end_of_inset(document.body, ostart) + k = find_token(document.body, "\\begin_layout Plain Layout", ostart, oend) + if k == -1: + document.warning("Malformed LyX document: Can't find argument contents!") + else: + m = find_end_of_layout(document.body, k) + optarg = "".join(document.body[k+1:m]) + have_optarg = True + + # We now remove the optional argument, so we have something + # uniform on which to work + document.body[ostart : oend + 1] = [] + # iend is now invalid + iend = find_end_of_inset(document.body, i) + + retval = get_containing_layout(document.body, i) + if not retval: + document.warning("Can't find containing layout for Chunk!") + i = iend + continue + (lname, lstart, lend, pstart) = retval + # we now want to work through the various paragraphs, and collect their contents + parlist = [] + k = i + while True: + k = find_token(document.body, "\\begin_layout Plain Layout", k, lend) + if k == -1: + break + j = find_end_of_layout(document.body, k) + if j == -1: + document.warning("Can't find end of layout inside chunk!") + break + parlist.append(document.body[k+1:j]) + k = j + # we now need to wrap all of these paragraphs in chunks + newlines = [] + if have_optarg: + newlines.extend(["\\begin_layout Chunk", "", "<<" + optarg + ">>=", "\\end_layout", ""]) + for stuff in parlist: + newlines.extend(["\\begin_layout Chunk"] + stuff + ["\\end_layout", ""]) + newlines.extend(["\\begin_layout Chunk", "", "@", "\\end_layout", ""]) + # replace old content with new content + document.body[lstart : lend + 1] = newlines + i = lstart + len(newlines) + + ## # Conversion hub # @@ -4294,10 +4459,12 @@ convert = [ [470, []], [471, [convert_cite_engine_type_default]], [472, []], - [473, []] + [473, []], + [474, [convert_chunks]], ] revert = [ + [473, [revert_chunks]], [472, [revert_tibetan]], [471, [revert_aa1,revert_aa2]], [470, [revert_cite_engine_type_default]], diff --git a/lib/lyx2lyx/parser_tools.py b/lib/lyx2lyx/parser_tools.py index 4c5197a534..c989515e41 100644 --- a/lib/lyx2lyx/parser_tools.py +++ b/lib/lyx2lyx/parser_tools.py @@ -449,9 +449,10 @@ def get_containing_inset(lines, i): def get_containing_layout(lines, i): ''' Finds out what kind of layout line i is within. Returns a - list containing (i) what follows \begin_layout on the line + list containing what follows \begin_layout on the line on which the layout begins, plus the starting and ending line - and the start of the apargraph (after all params). + and the start of the paragraph (after all params). I.e, returns: + (layoutname, layoutstart, layoutend, startofcontent) Returns False on any kind of error. ''' j = i diff --git a/src/version.h b/src/version.h index 3aa8ce8330..99c446760e 100644 --- a/src/version.h +++ b/src/version.h @@ -30,7 +30,7 @@ extern char const * const lyx_version_info; // Do not remove the comment below, so we get merge conflict in // independent branches. Instead add your own. -#define LYX_FORMAT_LYX 473 // uwestoehr: support Tibetan as document language +#define LYX_FORMAT_LYX 474 // rgh: dummy format change for Chunk switch #define LYX_FORMAT_TEX2LYX 473 #if LYX_FORMAT_TEX2LYX != LYX_FORMAT_LYX -- 2.39.2