X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2FLayout.cpp;h=80393cb982fa447838f25c630ad46122f6a51555;hb=55a3dd7b346d29a52ba305a4558e9e380ef50f47;hp=769f76d23ba53b007e0f7b2d3e89178261bb5ccd;hpb=369d21f4e2dd903f34c4fd3d1bbf75287bdf4494;p=lyx.git diff --git a/src/Layout.cpp b/src/Layout.cpp index 769f76d23b..80393cb982 100644 --- a/src/Layout.cpp +++ b/src/Layout.cpp @@ -3,9 +3,9 @@ * This file is part of LyX, the document processor. * Licence details can be found in the file COPYING. * - * \author Lars Gullik Bjønnes + * \author Lars Gullik Bjønnes * \author Jean-Marc Lasgouttes - * \author André Pönitz + * \author André Pönitz * * Full author contact details are available in file CREDITS. */ @@ -13,15 +13,20 @@ #include #include "Layout.h" -#include "TextClass.h" +#include "Encoding.h" +#include "FontInfo.h" +#include "Language.h" #include "Lexer.h" -#include "Font.h" -#include "support/debug.h" - +#include "output_xhtml.h" +#include "TextClass.h" +#include "support/debug.h" +#include "support/lassert.h" #include "support/lstrings.h" +#include "support/Messages.h" +#include "support/regex.h" +#include "support/textutils.h" -#include using namespace std; using namespace lyx::support; @@ -38,21 +43,16 @@ enum LayoutTags { LT_ALIGNPOSSIBLE, LT_MARGIN, LT_BOTTOMSEP, + LT_CATEGORY, LT_COMMANDDEPTH, LT_COPYSTYLE, LT_DEPENDSON, LT_OBSOLETEDBY, - //LT_EMPTY, LT_END, - //LT_ENVIRONMENT_DEFAULT, - //LT_FANCYHDR, - LT_FILL_BOTTOM, - LT_FILL_TOP, - //LT_FIRST_COUNTER, LT_FONT, LT_FREE_SPACING, LT_PASS_THRU, - //LT_HEADINGS, + LT_PARBREAK_IS_NEWLINE, LT_ITEMSEP, LT_KEEPEMPTY, LT_LABEL_BOTTOMSEP, @@ -70,9 +70,6 @@ enum LayoutTags { LT_LATEXPARAM, LT_OPTARGS, LT_LATEXTYPE, - LT_LATEXHEADER, - LT_LATEXFOOTER, - LT_LATEXPARAGRAPH, LT_LEFTMARGIN, LT_NEED_PROTECT, LT_NEWLINE, @@ -80,8 +77,9 @@ enum LayoutTags { LT_PARINDENT, LT_PARSEP, LT_PARSKIP, - //LT_PLAIN, LT_PREAMBLE, + LT_LANGPREAMBLE, + LT_BABELPREAMBLE, LT_REQUIRES, LT_RIGHTMARGIN, LT_SPACING, @@ -90,6 +88,21 @@ enum LayoutTags { LT_INNERTAG, LT_LABELTAG, LT_ITEMTAG, + LT_HTMLTAG, + LT_HTMLATTR, + LT_HTMLITEM, + LT_HTMLITEMATTR, + LT_HTMLLABEL, + LT_HTMLLABELATTR, + LT_HTMLLABELFIRST, + LT_HTMLPREAMBLE, + LT_HTMLSTYLE, + LT_HTMLFORCECSS, + LT_INPREAMBLE, + LT_HTMLTITLE, + LT_SPELLCHECK, + LT_REFPREFIX, + LT_REQARGS, LT_INTITLE // keep this last! }; @@ -97,10 +110,11 @@ enum LayoutTags { Layout::Layout() { + unknown_ = false; margintype = MARGIN_STATIC; latextype = LATEX_PARAGRAPH; intitle = false; - optionalargs = 0; + inpreamble = false; needprotect = false; keepempty = false; font = inherit_font; @@ -120,35 +134,51 @@ Layout::Layout() endlabeltype = END_LABEL_NO_LABEL; // Should or should not. That is the question. // spacing.set(Spacing::OneHalf); - fill_top = false; - fill_bottom = false; newline_allowed = true; free_spacing = false; pass_thru = false; - is_environment = false; + parbreak_is_newline = false; toclevel = NOT_IN_TOC; commanddepth = 0; + htmllabelfirst_ = false; + htmlforcecss_ = false; + htmltitle_ = false; + spellcheck = true; + optargs = 0; + reqargs = 0; } -bool Layout::read(Lexer & lexrc, TextClass const & tclass) +bool Layout::read(Lexer & lex, TextClass const & tclass) { // This table is sorted alphabetically [asierra 30March96] - keyword_item layoutTags[] = { + LexerKeyword layoutTags[] = { { "align", LT_ALIGN }, { "alignpossible", LT_ALIGNPOSSIBLE }, + { "babelpreamble", LT_BABELPREAMBLE }, { "bottomsep", LT_BOTTOMSEP }, + { "category", LT_CATEGORY }, { "commanddepth", LT_COMMANDDEPTH }, { "copystyle", LT_COPYSTYLE }, { "dependson", LT_DEPENDSON }, { "end", LT_END }, { "endlabelstring", LT_ENDLABELSTRING }, { "endlabeltype", LT_ENDLABELTYPE }, - { "fill_bottom", LT_FILL_BOTTOM }, - { "fill_top", LT_FILL_TOP }, { "font", LT_FONT }, { "freespacing", LT_FREE_SPACING }, + { "htmlattr", LT_HTMLATTR }, + { "htmlforcecss", LT_HTMLFORCECSS }, + { "htmlitem", LT_HTMLITEM }, + { "htmlitemattr", LT_HTMLITEMATTR }, + { "htmllabel", LT_HTMLLABEL }, + { "htmllabelattr", LT_HTMLLABELATTR }, + { "htmllabelfirst", LT_HTMLLABELFIRST }, + { "htmlpreamble", LT_HTMLPREAMBLE }, + { "htmlstyle", LT_HTMLSTYLE }, + { "htmltag", LT_HTMLTAG }, + { "htmltitle", LT_HTMLTITLE }, { "innertag", LT_INNERTAG }, + { "inpreamble", LT_INPREAMBLE }, { "intitle", LT_INTITLE }, { "itemsep", LT_ITEMSEP }, { "itemtag", LT_ITEMTAG }, @@ -162,10 +192,8 @@ bool Layout::read(Lexer & lexrc, TextClass const & tclass) { "labelstringappendix", LT_LABELSTRING_APPENDIX }, { "labeltag", LT_LABELTAG }, { "labeltype", LT_LABELTYPE }, - { "latexfooter", LT_LATEXFOOTER }, - { "latexheader", LT_LATEXHEADER }, + { "langpreamble", LT_LANGPREAMBLE }, { "latexname", LT_LATEXNAME }, - { "latexparagraph", LT_LATEXPARAGRAPH }, { "latexparam", LT_LATEXPARAM }, { "latextype", LT_LATEXTYPE }, { "leftmargin", LT_LEFTMARGIN }, @@ -175,14 +203,18 @@ bool Layout::read(Lexer & lexrc, TextClass const & tclass) { "nextnoindent", LT_NEXTNOINDENT }, { "obsoletedby", LT_OBSOLETEDBY }, { "optionalargs", LT_OPTARGS }, + { "parbreakisnewline", LT_PARBREAK_IS_NEWLINE }, { "parindent", LT_PARINDENT }, { "parsep", LT_PARSEP }, { "parskip", LT_PARSKIP }, { "passthru", LT_PASS_THRU }, { "preamble", LT_PREAMBLE }, + { "refprefix", LT_REFPREFIX }, + { "requiredargs", LT_REQARGS }, { "requires", LT_REQUIRES }, { "rightmargin", LT_RIGHTMARGIN }, { "spacing", LT_SPACING }, + { "spellcheck", LT_SPELLCHECK }, { "textfont", LT_TEXTFONT }, { "toclevel", LT_TOCLEVEL }, { "topsep", LT_TOPSEP } @@ -190,319 +222,356 @@ bool Layout::read(Lexer & lexrc, TextClass const & tclass) bool error = false; bool finished = false; - lexrc.pushTable(layoutTags, LT_INTITLE); + lex.pushTable(layoutTags); + // parse style section - while (!finished && lexrc.isOK() && !error) { - int le = lexrc.lex(); + while (!finished && lex.isOK() && !error) { + int le = lex.lex(); // See comment in LyXRC.cpp. switch (le) { case Lexer::LEX_FEOF: continue; - case Lexer::LEX_UNDEF: // parse error - lexrc.printError("Unknown layout tag `$$Token'"); + case Lexer::LEX_UNDEF: + // parse error + lex.printError("Unknown layout tag `$$Token'"); error = true; continue; - default: break; + + default: + break; } switch (static_cast(le)) { - case LT_END: // end of structure + case LT_END: finished = true; break; - case LT_COPYSTYLE: // initialize with a known style - if (lexrc.next()) { - docstring const style = subst(lexrc.getDocString(), - '_', ' '); - - if (tclass.hasLayout(style)) { - docstring const tmpname = name_; - this->operator=(*tclass[style]); - name_ = tmpname; - } else { - lyxerr << "Cannot copy unknown style `" - << to_utf8(style) << "'\n" - << "All layouts so far:" - << endl; - TextClass::const_iterator it = - tclass.begin(); - TextClass::const_iterator end = - tclass.end(); - for (; it != end; ++it) { - lyxerr << to_utf8((*it)->name()) - << endl; - } - - //lexrc.printError("Cannot copy known " - // "style `$$Token'"); - } - } + case LT_CATEGORY: + lex >> category_; break; - case LT_OBSOLETEDBY: // replace with a known style - if (lexrc.next()) { - docstring const style = - subst(lexrc.getDocString(), '_', ' '); - - if (tclass.hasLayout(style)) { - docstring const tmpname = name_; - this->operator=(*tclass[style]); - name_ = tmpname; - if (obsoleted_by().empty()) - obsoleted_by_ = style; - } else { - lyxerr << "Cannot replace with unknown style `" - << to_utf8(style) << '\'' << endl; - - //lexrc.printError("Cannot replace with" - // " unknown style " - // "`$$Token'"); - } + case LT_COPYSTYLE: { + docstring style; + lex >> style; + style = subst(style, '_', ' '); + + if (tclass.hasLayout(style)) { + docstring const tmpname = name_; + this->operator=(tclass[style]); + name_ = tmpname; + } else { + LYXERR0("Cannot copy unknown style `" + << style << "'\n" + << "All layouts so far:"); + DocumentClass::const_iterator lit = tclass.begin(); + DocumentClass::const_iterator len = tclass.end(); + for (; lit != len; ++lit) + LYXERR0(lit->name()); } break; + } - case LT_DEPENDSON: - if (lexrc.next()) - depends_on_ = subst(lexrc.getDocString(), '_', ' '); - break; - - case LT_MARGIN: // margin style definition. - readMargin(lexrc); + case LT_OBSOLETEDBY: { + docstring style; + lex >> style; + style = subst(style, '_', ' '); + + if (tclass.hasLayout(style)) { + docstring const tmpname = name_; + this->operator=(tclass[style]); + name_ = tmpname; + if (obsoleted_by().empty()) + obsoleted_by_ = style; + } else { + LYXERR0("Cannot replace with unknown style `" + << style << '\''); + + //lex.printError("Cannot replace with" + // " unknown style " + // "`$$Token'"); + } break; + } - case LT_LATEXTYPE: // LaTeX style definition. - readLatexType(lexrc); + case LT_DEPENDSON: + lex >> depends_on_; + depends_on_ = subst(depends_on_, '_', ' '); break; - case LT_LATEXHEADER: // header for environments - lexrc.next(); - latexheader = lexrc.getString(); + case LT_MARGIN: + readMargin(lex); break; - case LT_LATEXFOOTER: // footer for environments - lexrc.next(); - latexfooter = lexrc.getString(); + case LT_LATEXTYPE: + readLatexType(lex); break; - case LT_LATEXPARAGRAPH: - lexrc.next(); - latexparagraph = lexrc.getString(); + case LT_INTITLE: + lex >> intitle; break; - case LT_INTITLE: - intitle = lexrc.next() && lexrc.getInteger(); + case LT_INPREAMBLE: + lex >> inpreamble; break; case LT_TOCLEVEL: - lexrc.next(); - toclevel = lexrc.getInteger(); + lex >> toclevel; break; case LT_OPTARGS: - if (lexrc.next()) - optionalargs = lexrc.getInteger(); + lex >> optargs; + break; + + case LT_REQARGS: + lex >> reqargs; break; case LT_NEED_PROTECT: - needprotect = lexrc.next() && lexrc.getInteger(); + lex >> needprotect; break; case LT_KEEPEMPTY: - keepempty = lexrc.next() && lexrc.getInteger(); + lex >> keepempty; break; case LT_FONT: - font = lyxRead(lexrc, font); + font = lyxRead(lex, font); labelfont = font; break; case LT_TEXTFONT: - font = lyxRead(lexrc, font); + font = lyxRead(lex, font); break; case LT_LABELFONT: - labelfont = lyxRead(lexrc, labelfont); + labelfont = lyxRead(lex, labelfont); break; - case LT_NEXTNOINDENT: // Indent next paragraph? - if (lexrc.next() && lexrc.getInteger()) - nextnoindent = true; - else - nextnoindent = false; + case LT_NEXTNOINDENT: + lex >> nextnoindent; break; case LT_COMMANDDEPTH: - lexrc.next(); - commanddepth = lexrc.getInteger(); + lex >> commanddepth; break; case LT_LATEXNAME: - if (lexrc.next()) - latexname_ = lexrc.getString(); + lex >> latexname_; break; case LT_LATEXPARAM: - if (lexrc.next()) - latexparam_ = subst(lexrc.getString(), """, "\""); + lex >> latexparam_; + latexparam_ = subst(latexparam_, """, "\""); break; case LT_INNERTAG: - if (lexrc.next()) - innertag_ = lexrc.getString(); + lex >> innertag_; break; case LT_LABELTAG: - if (lexrc.next()) - labeltag_ = lexrc.getString(); + lex >> labeltag_; break; case LT_ITEMTAG: - if (lexrc.next()) - itemtag_ = lexrc.getString(); + lex >> itemtag_; break; case LT_PREAMBLE: - preamble_ = from_utf8(lexrc.getLongString("EndPreamble")); + preamble_ = from_utf8(lex.getLongString("EndPreamble")); break; - case LT_LABELTYPE: - readLabelType(lexrc); + case LT_LANGPREAMBLE: + langpreamble_ = from_utf8(lex.getLongString("EndLangPreamble")); break; - case LT_ENDLABELTYPE: - readEndLabelType(lexrc); + case LT_BABELPREAMBLE: + babelpreamble_ = from_utf8(lex.getLongString("EndBabelPreamble")); break; - case LT_LEFTMARGIN: // left margin type - if (lexrc.next()) - leftmargin = lexrc.getDocString(); + case LT_LABELTYPE: + readLabelType(lex); break; - case LT_RIGHTMARGIN: // right margin type - if (lexrc.next()) - rightmargin = lexrc.getDocString(); + case LT_ENDLABELTYPE: + readEndLabelType(lex); break; - case LT_LABELINDENT: // label indenting flag - if (lexrc.next()) - labelindent = lexrc.getDocString(); + case LT_LEFTMARGIN: + lex >> leftmargin; break; - case LT_PARINDENT: // paragraph indent. flag - if (lexrc.next()) - parindent = lexrc.getDocString(); + case LT_RIGHTMARGIN: + lex >> rightmargin; break; - case LT_PARSKIP: // paragraph skip size - if (lexrc.next()) - parskip = lexrc.getFloat(); + case LT_LABELINDENT: + lex >> labelindent; break; - case LT_ITEMSEP: // item separation size - if (lexrc.next()) - itemsep = lexrc.getFloat(); + case LT_PARINDENT: + lex >> parindent; break; - case LT_TOPSEP: // top separation size - if (lexrc.next()) - topsep = lexrc.getFloat(); + case LT_PARSKIP: + lex >> parskip; break; - case LT_BOTTOMSEP: // bottom separation size - if (lexrc.next()) - bottomsep = lexrc.getFloat(); + case LT_ITEMSEP: + lex >> itemsep; break; - case LT_LABEL_BOTTOMSEP: // label bottom separation size - if (lexrc.next()) - labelbottomsep = lexrc.getFloat(); + case LT_TOPSEP: + lex >> topsep; break; - case LT_LABELSEP: // label separator - if (lexrc.next()) { - labelsep = from_utf8(subst(lexrc.getString(), 'x', ' ')); - } + case LT_BOTTOMSEP: + lex >> bottomsep; break; - case LT_PARSEP: // par. separation size - if (lexrc.next()) - parsep = lexrc.getFloat(); + case LT_LABEL_BOTTOMSEP: + lex >> labelbottomsep; break; - case LT_FILL_TOP: // fill top flag - if (lexrc.next()) - fill_top = lexrc.getInteger(); + case LT_LABELSEP: + lex >> labelsep; + labelsep = subst(labelsep, 'x', ' '); break; - case LT_FILL_BOTTOM: // fill bottom flag - if (lexrc.next()) - fill_bottom = lexrc.getInteger(); + case LT_PARSEP: + lex >> parsep; break; - case LT_NEWLINE: // newlines allowed? - if (lexrc.next()) - newline_allowed = lexrc.getInteger(); + case LT_NEWLINE: + lex >> newline_allowed; break; - case LT_ALIGN: // paragraph align - readAlign(lexrc); + case LT_ALIGN: + readAlign(lex); break; - case LT_ALIGNPOSSIBLE: // paragraph allowed align - readAlignPossible(lexrc); + + case LT_ALIGNPOSSIBLE: + readAlignPossible(lex); break; - case LT_LABELSTRING: // label string definition - if (lexrc.next()) { - labelstring_ = trim(lexrc.getDocString()); - labelstring_appendix_ = labelstring_; - } + case LT_LABELSTRING: + // FIXME: this means LT_ENDLABELSTRING may only + // occur after LT_LABELSTRING + lex >> labelstring_; + labelstring_ = trim(labelstring_); + labelstring_appendix_ = labelstring_; + break; + + case LT_ENDLABELSTRING: + lex >> endlabelstring_; + endlabelstring_ = trim(endlabelstring_); break; - case LT_ENDLABELSTRING: // endlabel string definition - if (lexrc.next()) - endlabelstring_ = trim(lexrc.getDocString()); + case LT_LABELSTRING_APPENDIX: + lex >> labelstring_appendix_; + labelstring_appendix_ = trim(labelstring_appendix_); break; - case LT_LABELSTRING_APPENDIX: // label string appendix definition - if (lexrc.next()) - labelstring_appendix_ = trim(lexrc.getDocString()); + case LT_LABELCOUNTER: + lex >> counter; + counter = trim(counter); break; - case LT_LABELCOUNTER: // name of counter to use - if (lexrc.next()) - counter = lyx::from_ascii(trim(lexrc.getString())); + case LT_FREE_SPACING: + lex >> free_spacing; break; - case LT_FREE_SPACING: // Allow for free spacing. - if (lexrc.next()) - free_spacing = lexrc.getInteger(); + case LT_PASS_THRU: + lex >> pass_thru; break; - case LT_PASS_THRU: // Allow for pass thru. - if (lexrc.next()) - pass_thru = lexrc.getInteger(); + case LT_PARBREAK_IS_NEWLINE: + lex >> parbreak_is_newline; break; - case LT_SPACING: // setspace.sty - readSpacing(lexrc); + case LT_SPACING: + readSpacing(lex); break; - case LT_REQUIRES: - lexrc.eatLine(); + case LT_REQUIRES: { + lex.eatLine(); vector const req = - getVectorFromString(lexrc.getString()); + getVectorFromString(lex.getString()); requires_.insert(req.begin(), req.end()); break; + } + + case LT_REFPREFIX: { + docstring arg; + lex >> arg; + if (arg == "OFF") + refprefix.clear(); + else + refprefix = arg; + break; + } + + case LT_HTMLTAG: + lex >> htmltag_; + break; + + case LT_HTMLATTR: + lex >> htmlattr_; + break; + + case LT_HTMLITEM: + lex >> htmlitemtag_; + break; + + case LT_HTMLITEMATTR: + lex >> htmlitemattr_; + break; + + case LT_HTMLLABEL: + lex >> htmllabeltag_; + break; + + case LT_HTMLLABELATTR: + lex >> htmllabelattr_; + break; + + case LT_HTMLLABELFIRST: + lex >> htmllabelfirst_; + break; + + case LT_HTMLSTYLE: + htmlstyle_ = from_utf8(lex.getLongString("EndHTMLStyle")); + break; + + case LT_HTMLFORCECSS: + lex >> htmlforcecss_; + break; + + case LT_HTMLPREAMBLE: + htmlpreamble_ = from_utf8(lex.getLongString("EndPreamble")); + break; + + case LT_HTMLTITLE: + lex >> htmltitle_; + break; + case LT_SPELLCHECK: + lex >> spellcheck; + break; } } - lexrc.popTable(); + lex.popTable(); + // make sure we only have inpreamble = true for commands + if (inpreamble && latextype != LATEX_COMMAND && latextype != LATEX_PARAGRAPH) { + LYXERR0("InPreamble not permitted except with command and paragraph layouts."); + LYXERR0("Layout name: " << name()); + inpreamble = false; + } - return !error; + return finished && !error; } -enum AlignTags { +enum { AT_BLOCK = 1, AT_LEFT, AT_RIGHT, @@ -511,25 +580,26 @@ enum AlignTags { }; -void Layout::readAlign(Lexer & lexrc) -{ - keyword_item alignTags[] = { - { "block", AT_BLOCK }, - { "center", AT_CENTER }, - { "layout", AT_LAYOUT }, - { "left", AT_LEFT }, - { "right", AT_RIGHT } - }; +LexerKeyword alignTags[] = { + { "block", AT_BLOCK }, + { "center", AT_CENTER }, + { "layout", AT_LAYOUT }, + { "left", AT_LEFT }, + { "right", AT_RIGHT } +}; + - PushPopHelper pph(lexrc, alignTags, AT_LAYOUT); - int le = lexrc.lex(); +void Layout::readAlign(Lexer & lex) +{ + PushPopHelper pph(lex, alignTags); + int le = lex.lex(); switch (le) { case Lexer::LEX_UNDEF: - lexrc.printError("Unknown alignment `$$Token'"); + lex.printError("Unknown alignment `$$Token'"); return; default: break; }; - switch (static_cast(le)) { + switch (le) { case AT_BLOCK: align = LYX_ALIGN_BLOCK; break; @@ -549,28 +619,20 @@ void Layout::readAlign(Lexer & lexrc) } -void Layout::readAlignPossible(Lexer & lexrc) +void Layout::readAlignPossible(Lexer & lex) { - keyword_item alignTags[] = { - { "block", AT_BLOCK }, - { "center", AT_CENTER }, - { "layout", AT_LAYOUT }, - { "left", AT_LEFT }, - { "right", AT_RIGHT } - }; - - lexrc.pushTable(alignTags, AT_LAYOUT); + lex.pushTable(alignTags); alignpossible = LYX_ALIGN_NONE | LYX_ALIGN_LAYOUT; - int lineno = lexrc.getLineNo(); + int lineno = lex.lineNumber(); do { - int le = lexrc.lex(); + int le = lex.lex(); switch (le) { case Lexer::LEX_UNDEF: - lexrc.printError("Unknown alignment `$$Token'"); + lex.printError("Unknown alignment `$$Token'"); continue; default: break; }; - switch (static_cast(le)) { + switch (le) { case AT_BLOCK: alignpossible |= LYX_ALIGN_BLOCK; break; @@ -587,49 +649,49 @@ void Layout::readAlignPossible(Lexer & lexrc) alignpossible |= LYX_ALIGN_LAYOUT; break; } - } while (lineno == lexrc.getLineNo()); - lexrc.popTable(); + } while (lineno == lex.lineNumber()); + lex.popTable(); } -enum LabelTypeTags { - LA_NO_LABEL = 1, - LA_MANUAL, - LA_TOP_ENVIRONMENT, - LA_CENTERED_TOP_ENVIRONMENT, - LA_STATIC, - LA_SENSITIVE, - LA_COUNTER, - LA_ENUMERATE, - LA_ITEMIZE, - LA_BIBLIO -}; +void Layout::readLabelType(Lexer & lex) +{ + enum { + LA_NO_LABEL = 1, + LA_MANUAL, + LA_TOP_ENVIRONMENT, + LA_CENTERED_TOP_ENVIRONMENT, + LA_STATIC, + LA_SENSITIVE, + LA_COUNTER, + LA_ENUMERATE, + LA_ITEMIZE, + LA_BIBLIO + }; -void Layout::readLabelType(Lexer & lexrc) -{ - keyword_item labelTypeTags[] = { - { "bibliography", LA_BIBLIO }, - { "centered_top_environment", LA_CENTERED_TOP_ENVIRONMENT }, - { "counter", LA_COUNTER }, - { "enumerate", LA_ENUMERATE }, - { "itemize", LA_ITEMIZE }, - { "manual", LA_MANUAL }, - { "no_label", LA_NO_LABEL }, - { "sensitive", LA_SENSITIVE }, - { "static", LA_STATIC }, - { "top_environment", LA_TOP_ENVIRONMENT } + LexerKeyword labelTypeTags[] = { + { "bibliography", LA_BIBLIO }, + { "centered_top_environment", LA_CENTERED_TOP_ENVIRONMENT }, + { "counter", LA_COUNTER }, + { "enumerate", LA_ENUMERATE }, + { "itemize", LA_ITEMIZE }, + { "manual", LA_MANUAL }, + { "no_label", LA_NO_LABEL }, + { "sensitive", LA_SENSITIVE }, + { "static", LA_STATIC }, + { "top_environment", LA_TOP_ENVIRONMENT } }; - PushPopHelper pph(lexrc, labelTypeTags, LA_BIBLIO); - int le = lexrc.lex(); + PushPopHelper pph(lex, labelTypeTags); + int le = lex.lex(); switch (le) { case Lexer::LEX_UNDEF: - lexrc.printError("Unknown labeltype tag `$$Token'"); + lex.printError("Unknown labeltype tag `$$Token'"); return; default: break; } - switch (static_cast(le)) { + switch (le) { case LA_NO_LABEL: labeltype = LABEL_NO_LABEL; break; @@ -664,23 +726,20 @@ void Layout::readLabelType(Lexer & lexrc) } -static keyword_item endlabelTypeTags[] = +void Layout::readEndLabelType(Lexer & lex) { - { "box", END_LABEL_BOX }, - { "filled_box", END_LABEL_FILLED_BOX }, - { "no_label", END_LABEL_NO_LABEL }, - { "static", END_LABEL_STATIC } -}; - + static LexerKeyword endlabelTypeTags[] = { + { "box", END_LABEL_BOX }, + { "filled_box", END_LABEL_FILLED_BOX }, + { "no_label", END_LABEL_NO_LABEL }, + { "static", END_LABEL_STATIC } + }; -void Layout::readEndLabelType(Lexer & lexrc) -{ - PushPopHelper pph(lexrc, endlabelTypeTags, - END_LABEL_ENUM_LAST-END_LABEL_ENUM_FIRST+1); - int le = lexrc.lex(); + PushPopHelper pph(lex, endlabelTypeTags); + int le = lex.lex(); switch (le) { case Lexer::LEX_UNDEF: - lexrc.printError("Unknown labeltype tag `$$Token'"); + lex.printError("Unknown labeltype tag `$$Token'"); break; case END_LABEL_STATIC: case END_LABEL_BOX: @@ -689,16 +748,15 @@ void Layout::readEndLabelType(Lexer & lexrc) endlabeltype = static_cast(le); break; default: - lyxerr << "Unhandled value " << le - << " in Layout::readEndLabelType." << endl; + LYXERR0("Unhandled value " << le); break; } } -void Layout::readMargin(Lexer & lexrc) +void Layout::readMargin(Lexer & lex) { - keyword_item marginTags[] = { + LexerKeyword marginTags[] = { { "dynamic", MARGIN_DYNAMIC }, { "first_dynamic", MARGIN_FIRST_DYNAMIC }, { "manual", MARGIN_MANUAL }, @@ -706,12 +764,12 @@ void Layout::readMargin(Lexer & lexrc) { "static", MARGIN_STATIC } }; - PushPopHelper pph(lexrc, marginTags, MARGIN_RIGHT_ADDRESS_BOX); + PushPopHelper pph(lex, marginTags); - int le = lexrc.lex(); + int le = lex.lex(); switch (le) { case Lexer::LEX_UNDEF: - lexrc.printError("Unknown margin type tag `$$Token'"); + lex.printError("Unknown margin type tag `$$Token'"); return; case MARGIN_STATIC: case MARGIN_MANUAL: @@ -721,16 +779,15 @@ void Layout::readMargin(Lexer & lexrc) margintype = static_cast(le); break; default: - lyxerr << "Unhandled value " << le - << " in Layout::readMargin." << endl; + LYXERR0("Unhandled value " << le); break; } } -void Layout::readLatexType(Lexer & lexrc) +void Layout::readLatexType(Lexer & lex) { - keyword_item latexTypeTags[] = { + LexerKeyword latexTypeTags[] = { { "bib_environment", LATEX_BIB_ENVIRONMENT }, { "command", LATEX_COMMAND }, { "environment", LATEX_ENVIRONMENT }, @@ -739,11 +796,11 @@ void Layout::readLatexType(Lexer & lexrc) { "paragraph", LATEX_PARAGRAPH } }; - PushPopHelper pph(lexrc, latexTypeTags, LATEX_LIST_ENVIRONMENT); - int le = lexrc.lex(); + PushPopHelper pph(lex, latexTypeTags); + int le = lex.lex(); switch (le) { case Lexer::LEX_UNDEF: - lexrc.printError("Unknown latextype tag `$$Token'"); + lex.printError("Unknown latextype tag `$$Token'"); return; case LATEX_PARAGRAPH: case LATEX_COMMAND: @@ -754,39 +811,37 @@ void Layout::readLatexType(Lexer & lexrc) latextype = static_cast(le); break; default: - lyxerr << "Unhandled value " << le - << " in Layout::readLatexType." << endl; + LYXERR0("Unhandled value " << le); break; } } -enum SpacingTags { - ST_SPACING_SINGLE = 1, - ST_SPACING_ONEHALF, - ST_SPACING_DOUBLE, - ST_OTHER -}; - - -void Layout::readSpacing(Lexer & lexrc) +void Layout::readSpacing(Lexer & lex) { - keyword_item spacingTags[] = { + enum { + ST_SPACING_SINGLE = 1, + ST_SPACING_ONEHALF, + ST_SPACING_DOUBLE, + ST_OTHER + }; + + LexerKeyword spacingTags[] = { {"double", ST_SPACING_DOUBLE }, {"onehalf", ST_SPACING_ONEHALF }, {"other", ST_OTHER }, {"single", ST_SPACING_SINGLE } }; - PushPopHelper pph(lexrc, spacingTags, ST_OTHER); - int le = lexrc.lex(); + PushPopHelper pph(lex, spacingTags); + int le = lex.lex(); switch (le) { case Lexer::LEX_UNDEF: - lexrc.printError("Unknown spacing token `$$Token'"); + lex.printError("Unknown spacing token `$$Token'"); return; default: break; } - switch (static_cast(le)) { + switch (le) { case ST_SPACING_SINGLE: spacing.set(Spacing::Single); break; @@ -797,45 +852,245 @@ void Layout::readSpacing(Lexer & lexrc) spacing.set(Spacing::Double); break; case ST_OTHER: - lexrc.next(); - spacing.set(Spacing::Other, lexrc.getString()); + lex.next(); + spacing.set(Spacing::Other, lex.getString()); break; } } -docstring const & Layout::name() const +namespace { + +docstring const i18npreamble(Language const * lang, Encoding const & enc, + docstring const & templ, bool const polyglossia) { - return name_; + if (templ.empty()) + return templ; + + string preamble = polyglossia ? + subst(to_utf8(templ), "$$lang", lang->polyglossia()) : + subst(to_utf8(templ), "$$lang", lang->babel()); + +#ifdef TEX2LYX + // tex2lyx does not have getMessages() + LASSERT(false, /**/); + (void)enc; +#else + string const langenc = lang->encoding()->iconvName(); + string const texenc = lang->encoding()->latexName(); + string const bufenc = enc.iconvName(); + // First and second character of plane 15 (Private Use Area) + string const s1 = "\xf3\xb0\x80\x80"; // U+F0000 + string const s2 = "\xf3\xb0\x80\x81"; // U+F0001 + // FIXME UNICODE + // lyx::regex is not unicode-safe. + // Should use QRegExp or (boost::u32regex, but that requires ICU) + static regex const reg("_\\(([^\\)]+)\\)"); + smatch sub; + while (regex_search(preamble, sub, reg)) { + string const key = sub.str(1); + string translated = to_utf8(lang->translateLayout(key)); + if (langenc != bufenc) + translated = "\\inputencoding{" + texenc + "}" + + s1 + langenc + s2 + translated + + s1 + bufenc + s2; + preamble = subst(preamble, sub.str(), translated); + } +#endif + return from_utf8(preamble); +} + } -void Layout::setName(docstring const & name) +docstring const Layout::langpreamble(Language const * lang, + Encoding const & enc, bool const polyglossia) const { - name_ = name; + return i18npreamble(lang, enc, langpreamble_, polyglossia); } -docstring const & Layout::obsoleted_by() const +docstring const Layout::babelpreamble(Language const * lang, + Encoding const & enc, bool const polyglossia) const { - return obsoleted_by_; + return i18npreamble(lang, enc, babelpreamble_, polyglossia); } -docstring const & Layout::depends_on() const -{ - return depends_on_; +string const & Layout::htmltag() const +{ + if (htmltag_.empty()) + htmltag_ = "div"; + return htmltag_; +} + + +string const & Layout::htmlattr() const +{ + if (htmlattr_.empty()) + htmlattr_ = "class=\"" + defaultCSSClass() + "\""; + return htmlattr_; +} + + +string const & Layout::htmlitemtag() const +{ + if (htmlitemtag_.empty()) + htmlitemtag_ = "div"; + return htmlitemtag_; +} + + +string const & Layout::htmlitemattr() const +{ + if (htmlitemattr_.empty()) + htmlitemattr_ = "class=\"" + defaultCSSItemClass() + "\""; + return htmlitemattr_; } -Layout * Layout::forCaption() +string const & Layout::htmllabeltag() const +{ + if (htmllabeltag_.empty()) { + if (labeltype != LABEL_TOP_ENVIRONMENT && + labeltype != LABEL_CENTERED_TOP_ENVIRONMENT) + htmllabeltag_ = "span"; + else + htmllabeltag_ = "div"; + } + return htmllabeltag_; +} + + +string const & Layout::htmllabelattr() const +{ + if (htmllabelattr_.empty()) + htmllabelattr_ = "class=\"" + defaultCSSLabelClass() + "\""; + return htmllabelattr_; +} + + +docstring Layout::htmlstyle() const { + if (!htmlstyle_.empty() && !htmlforcecss_) + return htmlstyle_; + if (htmldefaultstyle_.empty()) + makeDefaultCSS(); + docstring retval = htmldefaultstyle_; + if (!htmlstyle_.empty()) + retval += '\n' + htmlstyle_; + return retval; +} + + +string Layout::defaultCSSClass() const +{ + if (!defaultcssclass_.empty()) + return defaultcssclass_; + docstring d; + docstring::const_iterator it = name().begin(); + docstring::const_iterator en = name().end(); + for (; it != en; ++it) { + char_type const c = *it; + if (!isAlphaASCII(c)) { + if (d.empty()) + // make sure we don't start with an underscore, + // as that sometimes causes problems. + d = from_ascii("lyx_"); + else + d += '_'; + } else if (islower(c)) + d += c; + else + // this is slow, so do it only if necessary + d += lowercase(c); + } + defaultcssclass_ = to_utf8(d); + return defaultcssclass_; +} + + +namespace { + string makeMarginValue(char const * side, double d) { + ostringstream os; + os << "margin-" << side << ": " << d << "ex;\n"; + return os.str(); + } +} + + +void Layout::makeDefaultCSS() const { + // this never needs to be redone, since reloading layouts will + // wipe out what we did before. + if (!htmldefaultstyle_.empty()) + return; + + // main font + htmldefaultstyle_ = font.asCSS(); + + // bottom margins + string tmp; + if (topsep > 0) + tmp += makeMarginValue("top", topsep); + if (bottomsep > 0) + tmp += makeMarginValue("bottom", bottomsep); + if (!leftmargin.empty()) { + // we can't really do what LyX does with the margin, so + // we'll just figure out how many characters it is + int const len = leftmargin.length(); + tmp += makeMarginValue("left", len); + } + if (!rightmargin.empty()) { + int const len = rightmargin.length(); + tmp += makeMarginValue("right", len); + } + + if (!tmp.empty()) { + if (!htmldefaultstyle_.empty()) + htmldefaultstyle_ += from_ascii("\n"); + htmldefaultstyle_ += from_ascii(tmp); + } + +// tex2lyx does not see output_xhtml.cpp +#ifndef TEX2LYX + // alignment + string where = alignmentToCSS(align); + if (!where.empty()) { + htmldefaultstyle_ += from_ascii("text-align: " + where + ";\n"); + } +#endif + + // wrap up what we have, if anything + if (!htmldefaultstyle_.empty()) + htmldefaultstyle_ = + from_ascii(htmltag() + "." + defaultCSSClass() + " {\n") + + htmldefaultstyle_ + from_ascii("\n}\n"); + + if (labeltype == LABEL_NO_LABEL || htmllabeltag() == "NONE") + return; + + docstring labelCSS; + + // label font + if (labelfont != font) + labelCSS = labelfont.asCSS() + from_ascii("\n"); + if (labeltype == LABEL_CENTERED_TOP_ENVIRONMENT) + labelCSS += from_ascii("text-align: center;\n"); + + if (!labelCSS.empty()) + htmldefaultstyle_ += + from_ascii(htmllabeltag() + "." + defaultCSSLabelClass() + " {\n") + + labelCSS + from_ascii("\n}\n"); +} + + +bool Layout::operator==(Layout const & rhs) const { - Layout * lay = new Layout(); - lay->name_ = from_ascii("Caption"); - lay->latexname_ = "caption"; - lay->latextype = LATEX_COMMAND; - lay->optionalargs = 1; - return lay; + // This is enough for the applications we actually make, + // at least at the moment. But we could check more. + return name() == rhs.name() + && latexname() == rhs.latexname() + && latextype == rhs.latextype; } + } // namespace lyx