From b0097bcddbc2c99755db192c0720f693825ef319 Mon Sep 17 00:00:00 2001 From: Richard Heck Date: Fri, 4 Jun 2010 21:50:08 +0000 Subject: [PATCH] Introduce a new "RequiredArgs" tag for layouts. This functions much as the OptionalArgs tag does and is implemented by the now misnamed InsetOptArgs, except that its content gets wrapped in "{}" rather than "[]". Required arguments do not actually have to be provided, but they are always output. This will allow e.g. beamer's Block environment to be implemented without ERT. Documentation to follow. git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@34591 a592a061-630c-0410-9148-cb99ea01b6c8 --- lib/scripts/layout2layout.py | 7 ++-- src/Layout.cpp | 9 +++-- src/Layout.h | 11 +++++-- src/Text3.cpp | 8 +++-- src/TextClass.cpp | 2 +- src/insets/InsetCaption.cpp | 4 +-- src/insets/InsetOptArg.cpp | 9 ++--- src/insets/InsetOptArg.h | 5 +-- src/output_latex.cpp | 64 ++++++++++++++++++++++++++++-------- src/output_latex.h | 12 ++++--- src/tex2lyx/text.cpp | 19 ++++++++++- 11 files changed, 113 insertions(+), 37 deletions(-) diff --git a/lib/scripts/layout2layout.py b/lib/scripts/layout2layout.py index 782a02637e..0c85e57ad7 100644 --- a/lib/scripts/layout2layout.py +++ b/lib/scripts/layout2layout.py @@ -94,6 +94,9 @@ import os, re, string, sys # Incremented to format 26, 29 March 2010 by rgh # Added CiteFormat. +# Incremented to format 27, 4 June 2010 by rgh +# Added RequiredArgs tag. + # Do not forget to document format change in Customization # Manual (section "Declaring a new text class"). @@ -101,7 +104,7 @@ import os, re, string, sys # development/tools/updatelayouts.sh script to update all # layout files to the new format. -currentFormat = 26 +currentFormat = 27 def usage(prog_name): @@ -274,7 +277,7 @@ def convert(lines): continue # Only new features - if format >= 24 and format <= 25: + if format >= 24 and format <= 26: i += 1 continue diff --git a/src/Layout.cpp b/src/Layout.cpp index 7a26c8cf65..cd7b5d4323 100644 --- a/src/Layout.cpp +++ b/src/Layout.cpp @@ -106,6 +106,7 @@ enum LayoutTags { LT_HTMLTITLE, LT_SPELLCHECK, LT_REFPREFIX, + LT_REQARGS, LT_INTITLE // keep this last! }; @@ -118,7 +119,6 @@ Layout::Layout() latextype = LATEX_PARAGRAPH; intitle = false; inpreamble = false; - optionalargs = 0; needprotect = false; keepempty = false; font = inherit_font; @@ -214,6 +214,7 @@ bool Layout::read(Lexer & lex, TextClass const & tclass) { "passthru", LT_PASS_THRU }, { "preamble", LT_PREAMBLE }, { "refprefix", LT_REFPREFIX }, + { "requiredargs", LT_REQARGS }, { "requires", LT_REQUIRES }, { "rightmargin", LT_RIGHTMARGIN }, { "spacing", LT_SPACING }, @@ -320,7 +321,11 @@ bool Layout::read(Lexer & lex, TextClass const & tclass) break; case LT_OPTARGS: - lex >> optionalargs ; + lex >> optargs; + break; + + case LT_REQARGS: + lex >> reqargs; break; case LT_NEED_PROTECT: diff --git a/src/Layout.h b/src/Layout.h index 73edd052fc..0a398d31c2 100644 --- a/src/Layout.h +++ b/src/Layout.h @@ -241,8 +241,15 @@ public: bool intitle; /// Is the content to go in the preamble rather than the body? bool inpreamble; - /// Does this layout allow for an optional parameter? - int optionalargs; + /// Number of requried arguments for this command or environment + unsigned int reqargs; + /// Number of optional arguments for this command or environment + /// These MUST come at the beginning, so: + /// \cmd[opt1][opt2]{req1}{here is the text from LyX} + /// is fine. But: + /// \cmd[opt1]{req1}[opt2]{here is the text from LyX} + /// is not. + unsigned int optargs; /// Which counter to step docstring counter; /// Prefix to use when creating labels diff --git a/src/Text3.cpp b/src/Text3.cpp index 0dd3b6492c..e9c08f403e 100644 --- a/src/Text3.cpp +++ b/src/Text3.cpp @@ -2341,11 +2341,13 @@ bool Text::getStatus(Cursor & cur, FuncRequest const & cmd, case LFUN_INFO_INSERT: code = INFO_CODE; break; - case LFUN_OPTIONAL_INSERT: + case LFUN_OPTIONAL_INSERT: { code = OPTARG_CODE; - enable = cur.paragraph().insetList().count(OPTARG_CODE) - < cur.paragraph().layout().optionalargs; + Layout const & lay = cur.paragraph().layout(); + int const numargs = lay.reqargs + lay.optargs; + enable = cur.paragraph().insetList().count(OPTARG_CODE) < numargs; break; + } case LFUN_INDEX_INSERT: code = INDEX_CODE; break; diff --git a/src/TextClass.cpp b/src/TextClass.cpp index bbf54cc946..3b72f4b592 100644 --- a/src/TextClass.cpp +++ b/src/TextClass.cpp @@ -65,7 +65,7 @@ private: }; // Keep the changes documented in the Customization manual. -int const FORMAT = 26; +int const FORMAT = 27; bool layout2layout(FileName const & filename, FileName const & tempfile) diff --git a/src/insets/InsetCaption.cpp b/src/insets/InsetCaption.cpp index ab696b9339..c3661594aa 100644 --- a/src/insets/InsetCaption.cpp +++ b/src/insets/InsetCaption.cpp @@ -229,7 +229,7 @@ int InsetCaption::latex(odocstream & os, // optional argument. runparams.moving_arg = true; os << "\\caption"; - int l = latexOptArgInsets(paragraphs()[0], os, runparams, 1); + int l = latexArgInsets(paragraphs()[0], os, runparams, 0, 1); os << '{'; l += InsetText::latex(os, runparams); os << "}\n"; @@ -285,7 +285,7 @@ int InsetCaption::getArgument(odocstream & os, int InsetCaption::getOptArg(odocstream & os, OutputParams const & runparams) const { - return latexOptArgInsets(paragraphs()[0], os, runparams, 1); + return latexArgInsets(paragraphs()[0], os, runparams, 0, 1); } diff --git a/src/insets/InsetOptArg.cpp b/src/insets/InsetOptArg.cpp index 544b213aae..340dac55a4 100644 --- a/src/insets/InsetOptArg.cpp +++ b/src/insets/InsetOptArg.cpp @@ -56,15 +56,16 @@ docstring InsetOptArg::xhtml(XHTMLStream &, OutputParams const &) const return docstring(); } -int InsetOptArg::latexOptional(odocstream & os, - OutputParams const & runparams) const +int InsetOptArg::latexArgument(odocstream & os, + OutputParams const & runparams, bool optional) const { odocstringstream ss; int ret = InsetText::latex(ss, runparams); docstring str = ss.str(); - if (str.find(']') != docstring::npos) + if (optional && str.find(']') != docstring::npos) str = '{' + str + '}'; - os << '[' << str << ']'; + os << (optional ? '[' : '{') << str + << (optional ? ']' : '}'); return ret; } diff --git a/src/insets/InsetOptArg.h b/src/insets/InsetOptArg.h index 2584049a61..c1cbeeccbe 100644 --- a/src/insets/InsetOptArg.h +++ b/src/insets/InsetOptArg.h @@ -29,8 +29,9 @@ public: /// InsetOptArg(Buffer *); - /// Outputting the optional parameter of a LaTeX command - int latexOptional(odocstream &, OutputParams const &) const; + /// Outputting the parameter of a LaTeX command + int latexArgument(odocstream &, OutputParams const &, + bool optional) const; /// bool hasSettings() const { return false; } diff --git a/src/output_latex.cpp b/src/output_latex.cpp index cdd42aaf43..727fe4206d 100644 --- a/src/output_latex.cpp +++ b/src/output_latex.cpp @@ -34,6 +34,7 @@ #include "support/lstrings.h" #include +#include using namespace std; using namespace lyx::support; @@ -167,9 +168,8 @@ TeXEnvironment(Buffer const & buf, if (style.isEnvironment()) { os << "\\begin{" << from_ascii(style.latexname()) << '}'; - if (style.optionalargs > 0) { - int ret = latexOptArgInsets(*pit, os, runparams, - style.optionalargs); + if (style.optargs != 0 || style.reqargs != 0) { + int ret = latexArgInsets(*pit, os, runparams, style.reqargs, style.optargs); while (ret > 0) { texrow.newline(); --ret; @@ -279,24 +279,61 @@ TeXEnvironment(Buffer const & buf, } // namespace anon -int latexOptArgInsets(Paragraph const & par, odocstream & os, - OutputParams const & runparams, int number) +int latexArgInsets(Paragraph const & par, odocstream & os, + OutputParams const & runparams, unsigned int reqargs, + unsigned int optargs) { - int lines = 0; + unsigned int totalargs = reqargs + optargs; + list ilist; InsetList::const_iterator it = par.insetList().begin(); InsetList::const_iterator end = par.insetList().end(); - for (; it != end && number > 0 ; ++it) { + for (; it != end; ++it) { if (it->inset->lyxCode() == OPTARG_CODE) { - InsetOptArg * ins = - static_cast(it->inset); - lines += ins->latexOptional(os, runparams); - --number; + if (ilist.size() >= totalargs) { + LYXERR0("WARNING: Found extra argument inset."); + continue; + } + InsetOptArg const * ins = + static_cast(it->inset); + ilist.push_back(ins); + } + } + + if (!reqargs && ilist.size() == 0) + return 0; + + int lines = 0; + bool const have_optional_args = ilist.size() > reqargs; + if (have_optional_args) { + unsigned int todo = ilist.size() - reqargs; + for (unsigned int i = 0; i < todo; ++i) { + InsetOptArg const * ins = ilist.front(); + ilist.pop_front(); + lines += ins->latexArgument(os, runparams, true); + } + } + + // we should now have no more insets than there are required + // arguments. + LASSERT(ilist.size() <= reqargs, /* */); + if (!reqargs) + return lines; + + for (unsigned int i = 0; i < reqargs; ++i) { + if (ilist.empty()) + // a required argument wasn't given, so we output {} + os << "{}"; + else { + InsetOptArg const * ins = ilist.front(); + ilist.pop_front(); + lines += ins->latexArgument(os, runparams, false); } } return lines; } + // FIXME: this should be anonymous ParagraphList::const_iterator TeXOnePar(Buffer const & buf, Text const & text, @@ -543,9 +580,8 @@ ParagraphList::const_iterator TeXOnePar(Buffer const & buf, os << '\\' << from_ascii(style.latexname()); // Separate handling of optional argument inset. - if (style.optionalargs > 0) { - int ret = latexOptArgInsets(*pit, os, runparams, - style.optionalargs); + if (style.optargs != 0 || style.reqargs != 0) { + int ret = latexArgInsets(*pit, os, runparams, style.reqargs, style.optargs); while (ret > 0) { texrow.newline(); --ret; diff --git a/src/output_latex.h b/src/output_latex.h index 84bd800a8a..9a7de7ed69 100644 --- a/src/output_latex.h +++ b/src/output_latex.h @@ -25,15 +25,19 @@ namespace lyx { class Buffer; class BufferParams; class Encoding; +class Layout; class Paragraph; class OutputParams; class TexRow; class Text; -/// Export up to \p number optarg insets -int latexOptArgInsets(Paragraph const & par, - odocstream & os, OutputParams const & runparams, - int number); +/// Export up to \p reqargs required arguments and +/// \p optargs optional ones. If not enough required +/// ones are given, we'll output: {}. The optional ones +/// must all come first. +int latexArgInsets(Paragraph const & par, + odocstream & os, OutputParams const & runparams, + unsigned int reqargs, unsigned int optargs); /** Export \p paragraphs of buffer \p buf to LaTeX. Don't use a temporary stringstream for \p os if the final output is diff --git a/src/tex2lyx/text.cpp b/src/tex2lyx/text.cpp index a39a460233..ab6a101706 100644 --- a/src/tex2lyx/text.cpp +++ b/src/tex2lyx/text.cpp @@ -454,7 +454,8 @@ void output_command_layout(ostream & os, Parser & p, bool outer, } context.check_deeper(os); context.check_layout(os); - if (context.layout->optionalargs > 0) { + unsigned int optargs = 0; + while (optargs < context.layout->optargs) { eat_whitespace(p, os, context, false); if (p.next_token().character() == '[') { p.get_token(); // eat '[' @@ -463,6 +464,20 @@ void output_command_layout(ostream & os, Parser & p, bool outer, parse_text_in_inset(p, os, FLAG_BRACK_LAST, outer, context); end_inset(os); eat_whitespace(p, os, context, false); + optargs++; + } + } + unsigned int reqargs = 0; + while (reqargs < context.layout->reqargs) { + eat_whitespace(p, os, context, false); + if (p.next_token().character() == '{') { + p.get_token(); // eat '[' + begin_inset(os, "OptArg\n"); + os << "status collapsed\n\n"; + parse_text_in_inset(p, os, FLAG_BRACE_LAST, outer, context); + end_inset(os); + eat_whitespace(p, os, context, false); + reqargs++; } } parse_text(p, os, FLAG_ITEM, outer, context); @@ -1150,6 +1165,8 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, if (t.character() == ']' && (flags & FLAG_BRACK_LAST)) return; + if (t.character() == '}' && (flags & FLAG_BRACE_LAST)) + return; // // cat codes