From f18af303fe2f9dca05beae7852f3904ac4bfddba Mon Sep 17 00:00:00 2001 From: Juergen Spitzmueller Date: Tue, 9 Oct 2012 07:17:36 +0200 Subject: [PATCH] Introduce textclass categories The categories are ascribed by \DeclareCategory{} in the layout file header. UI follows. --- lib/chkconfig.ltx | 14 +++++++++- lib/configure.py | 58 ++++++++++++++++++++++++++++++--------- src/LayoutFile.cpp | 67 +++++++++++++++++++++++++++++----------------- src/LayoutFile.h | 1 + src/TextClass.cpp | 4 +-- src/TextClass.h | 6 ++++- 6 files changed, 110 insertions(+), 40 deletions(-) diff --git a/lib/chkconfig.ltx b/lib/chkconfig.ltx index 3af74b9df1..141aba9b46 100644 --- a/lib/chkconfig.ltx +++ b/lib/chkconfig.ltx @@ -64,7 +64,13 @@ \newcommand{\AddLayout}[5][\default]{ \def\default{#2} - \immediate\write\layouts{"#2" "#1" "#3" "#4" "#5"}} + \@ifundefined{category@#2}{% + \immediate\write\layouts{"#2" "#1" "#3" "#4" "#5" ""}% + }{% + \immediate\write\layouts{"#2" "#1" "#3" "#4" "#5" "\@nameuse{category@#2}"}% + } +} + \newcommand{\AddVariable}[2]{ \immediate\write\vars{chk_#1='#2'}} @@ -148,6 +154,12 @@ {\AddLayout[\firstelement]{\layoutname}{#2}{false}{\missingelements}} } +\newcommand{\DeclareCategory}[2]{ + \@ifundefined{category@#1} + {\global\@namedef{category@#1}{#2}}% + {}% we have already defined this one. +} + % Only for compatibility. Will be removed later. \let\DeclareSGMLClass=\DeclareDocBookClass diff --git a/lib/configure.py b/lib/configure.py index b1f42d739b..ea0bbab1f0 100644 --- a/lib/configure.py +++ b/lib/configure.py @@ -1006,17 +1006,29 @@ def checkOtherEntries(): def processLayoutFile(file, bool_docbook): ''' process layout file and get a line of result - Declare lines look like this: (article.layout, scrbook.layout, svjog.layout) - + Declare lines look like this: + + \DeclareLaTeXClass[]{} + + Optionally, a \DeclareCategory line follows: + + \DeclareCategory{} + + So for example (article.layout, scrbook.layout, svjog.layout) + \DeclareLaTeXClass{article} + \DeclareCategory{Articles} + \DeclareLaTeXClass[scrbook]{book (koma-script)} + \DeclareCategory{Books} + \DeclareLaTeXClass[svjour,svjog.clo]{article (Springer - svjour/jog)} - we expect output: + we'd expect this output: - "article" "article" "article" "false" "article.cls" - "scrbook" "scrbook" "book (koma-script)" "false" "scrbook.cls" - "svjog" "svjour" "article (Springer - svjour/jog)" "false" "svjour.cls,svjog.clo" + "article" "article" "article" "false" "article.cls" "Articles" + "scrbook" "scrbook" "book (koma-script)" "false" "scrbook.cls" "Books" + "svjog" "svjour" "article (Springer - svjour/jog)" "false" "svjour.cls,svjog.clo" "" ''' def checkForClassExtension(x): '''if the extension for a latex class is not @@ -1028,8 +1040,12 @@ def processLayoutFile(file, bool_docbook): classname = file.split(os.sep)[-1].split('.')[0] # return ('LaTeX', '[a,b]', 'a', ',b,c', 'article') for \DeclareLaTeXClass[a,b,c]{article} p = re.compile(r'\Declare(LaTeX|DocBook)Class\s*(\[([^,]*)(,.*)*\])*\s*{(.*)}') + q = re.compile(r'\DeclareCategory{(.*)}') + classdeclaration = "" + categorydeclaration = '""' for line in open(file).readlines(): res = p.search(line) + qres = q.search(line) if res != None: (classtype, optAll, opt, opt1, desc) = res.groups() avai = {'LaTeX':'false', 'DocBook':bool_docbook}[classtype] @@ -1042,7 +1058,15 @@ def processLayoutFile(file, bool_docbook): prereq_latex = ','.join(prereq_list) prereq_docbook = {'true':'', 'false':'docbook'}[bool_docbook] prereq = {'LaTeX':prereq_latex, 'DocBook':prereq_docbook}[classtype] - return '"%s" "%s" "%s" "%s" "%s"\n' % (classname, opt, desc, avai, prereq) + classdeclaration = '"%s" "%s" "%s" "%s" "%s"' % (classname, opt, desc, avai, prereq) + if categorydeclaration != "": + return classdeclaration + " " + categorydeclaration + if qres != None: + categorydeclaration = '"%s"' % (qres.groups()[0]) + if classdeclaration != "": + return classdeclaration + " " + categorydeclaration + if classdeclaration != "": + return classdeclaration + " " + categorydeclaration logger.warning("Layout file " + file + " has no \DeclareXXClass line. ") return "" @@ -1112,6 +1136,7 @@ def checkLatexConfig(check_config, bool_docbook): # build the list of available layout files and convert it to commands # for chkconfig.ltx declare = re.compile(r'\Declare(LaTeX|DocBook)Class\s*(\[([^,]*)(,.*)*\])*\s*{(.*)}') + category = re.compile(r'\DeclareCategory{(.*)}') empty = re.compile(r'^\s*$') testclasses = list() for file in glob.glob( os.path.join('layouts', '*.layout') ) + \ @@ -1120,14 +1145,23 @@ def checkLatexConfig(check_config, bool_docbook): if not os.path.isfile(file): continue classname = file.split(os.sep)[-1].split('.')[0] + decline = "" + catline = "" for line in open(file).readlines(): if not empty.match(line) and line[0] != '#': - logger.warning("Failed to find valid \Declare line for layout file `" + file + "'.\n\t=> Skipping this file!") - nodeclaration = True + if decline == "": + logger.warning("Failed to find valid \Declare line for layout file `" + file + "'.\n\t=> Skipping this file!") + nodeclaration = True + # A class, but no category declaration. Just break. break - if declare.search(line) == None: + if declare.search(line) != None: + decline = "\\TestDocClass{%s}{%s}" % (classname, line[1:].strip()) + testclasses.append(decline) + elif category.search(line) != None: + catline = "\\DeclareCategory{%s}{%s}" % (classname, category.search(line).groups()[0]) + testclasses.append(catline) + if catline == "" or decline == "": continue - testclasses.append("\\TestDocClass{%s}{%s}" % (classname, line[1:].strip())) break if nodeclaration: continue @@ -1151,7 +1185,7 @@ def checkLatexConfig(check_config, bool_docbook): if rmcopy: removeFiles( [ 'chkconfig.ltx' ] ) # - # currently, values in chhkconfig are only used to set + # currently, values in chkconfig are only used to set # \font_encoding values = {} for line in open('chkconfig.vars').readlines(): diff --git a/src/LayoutFile.cpp b/src/LayoutFile.cpp index f70209b3b0..4337956170 100644 --- a/src/LayoutFile.cpp +++ b/src/LayoutFile.cpp @@ -40,13 +40,14 @@ namespace lyx { LayoutFile::LayoutFile(string const & fn, string const & cln, - string const & desc, string const & prereq, - bool texclassavail) + string const & desc, string const & prereq, + string const & category, bool texclassavail) { name_ = fn; latexname_ = cln; description_ = desc; prerequisites_ = prereq; + category_ = category; tex_class_avail_ = texclassavail; } @@ -141,9 +142,13 @@ bool LayoutFileList::read() break; string const prereq = lex.getString(); LYXERR(Debug::TCLASS, "Prereq: " << prereq); + if (!lex.next()) + break; + string const category = lex.getString(); + LYXERR(Debug::TCLASS, "Category: " << category); // This code is run when we have // fname, clname, desc, prereq, and avail - LayoutFile * tmpl = new LayoutFile(fname, clname, desc, prereq, avail); + LayoutFile * tmpl = new LayoutFile(fname, clname, desc, prereq, category, avail); if (lyxerr.debugging(Debug::TCLASS)) { // only system layout files are loaded here so no // buffer path is needed. @@ -182,7 +187,8 @@ void LayoutFileList::reset(LayoutFileIndex const & classname) { LayoutFile * tc = classmap_[classname]; LayoutFile * tmpl = new LayoutFile(tc->name(), tc->latexname(), tc->description(), - tc->prerequisites(), tc->isTeXClassAvailable()); + tc->prerequisites(), tc->category(), + tc->isTeXClassAvailable()); classmap_[classname] = tmpl; delete tc; } @@ -227,7 +233,7 @@ LayoutFileIndex LayoutFileList::addEmptyClass(string const & textclass) // the last parameter to true will suppress a warning message about missing // tex class. LayoutFile * tc = new LayoutFile(textclass, textclass, - "Unknown text class " + textclass, textclass + ".cls", true); + "Unknown text class " + textclass, textclass + ".cls", "", true); if (!tc->load(tempLayout.absFileName())) { // The only way this happens is because the hardcoded layout file @@ -272,7 +278,12 @@ LayoutFileIndex ifstream ifs(layout_file.toFilesystemEncoding().c_str()); static regex const reg("^#\\s*\\\\Declare(LaTeX|DocBook)Class\\s*" "(?:\\[([^,]*)(?:,.*)*\\])*\\s*\\{(.*)\\}\\s*"); + static regex const catreg("^#\\s*\\\\DeclareCategory\\{(.*)\\}"); string line; + string class_name; + string class_prereq; + string category; + bool have_declaration = false; while (getline(ifs, line)) { // look for the \DeclareXXXClass line smatch sub; @@ -280,26 +291,34 @@ LayoutFileIndex // returns: whole string, classtype (not used here), class name, description LASSERT(sub.size() == 4, /**/); // now, create a TextClass with description containing path information - string class_name(sub.str(2) == "" ? textclass : sub.str(2)); - string class_prereq(class_name + ".cls"); - LayoutFile * tmpl = - new LayoutFile(textclass, class_name, textclass, class_prereq, true); - //FIXME: The prerequisites are available from the layout file and - // can be extracted from the above regex, but for now this - // field is simply set to class_name + ".cls" - // This textclass is added on request so it will definitely be - // used. Load it now because other load() calls may fail if they - // are called in a context without buffer path information. - tmpl->load(path); - // There will be only one textclass with this name, even if different - // layout files are loaded from different directories. - if (haveClass(textclass)) { - LYXERR0("Existing textclass " << textclass << " is redefined by " << fullName); - delete classmap_[textclass]; - } - classmap_[textclass] = tmpl; - return textclass; + class_name = (sub.str(2) == "" ? textclass : sub.str(2)); + class_prereq = class_name + ".cls"; + have_declaration = true; + } + else if (regex_match(line, sub, catreg)) { + category = sub.str(1); + } + if (have_declaration && !category.empty()) + break; + } + if (have_declaration) { + LayoutFile * tmpl = + new LayoutFile(textclass, class_name, textclass, class_prereq, category, true); + //FIXME: The prerequisites are available from the layout file and + // can be extracted from the above regex, but for now this + // field is simply set to class_name + ".cls" + // This textclass is added on request so it will definitely be + // used. Load it now because other load() calls may fail if they + // are called in a context without buffer path information. + tmpl->load(path); + // There will be only one textclass with this name, even if different + // layout files are loaded from different directories. + if (haveClass(textclass)) { + LYXERR0("Existing textclass " << textclass << " is redefined by " << fullName); + delete classmap_[textclass]; } + classmap_[textclass] = tmpl; + return textclass; } } // If .layout is not in local directory, or an invalid layout is found, return null diff --git a/src/LayoutFile.h b/src/LayoutFile.h index b71f123009..31031eae8e 100644 --- a/src/LayoutFile.h +++ b/src/LayoutFile.h @@ -76,6 +76,7 @@ private: std::string const & className = std::string(), std::string const & description = std::string(), std::string const & prerequisites = std::string(), + std::string const & category = std::string(), bool texclassavail = false); /// The only class that should create a LayoutFile is /// LayoutFileList, which calls the private constructor. diff --git a/src/TextClass.cpp b/src/TextClass.cpp index b352ca2954..d19c08b924 100644 --- a/src/TextClass.cpp +++ b/src/TextClass.cpp @@ -1228,11 +1228,11 @@ bool TextClass::readFloat(Lexer & lexrc) } -string const & TextClass::prerequisites() const +string const & TextClass::prerequisites(string const & sep) const { if (contains(prerequisites_, ',')) { vector const pres = getVectorFromString(prerequisites_); - prerequisites_ = getStringFromVector(pres, "\n\t"); + prerequisites_ = getStringFromVector(pres, sep); } return prerequisites_; } diff --git a/src/TextClass.h b/src/TextClass.h index 1bf35f6219..b3daa4c5b5 100644 --- a/src/TextClass.h +++ b/src/TextClass.h @@ -189,11 +189,13 @@ public: /// std::string const & name() const { return name_; } /// + std::string const & category() const { return category_; } + /// std::string const & description() const { return description_; } /// std::string const & latexname() const { return latexname_; } /// - std::string const & prerequisites() const; + std::string const & prerequisites(std::string const & sep = "\n\t") const; /// Can be LaTeX, DocBook, etc. OutputType outputType() const { return outputType_; } /// Can be latex, docbook ... (the name of a format) @@ -231,6 +233,8 @@ protected: mutable LayoutList layoutlist_; /// Layout file name std::string name_; + /// Class category + std::string category_; /// document class name std::string latexname_; /// document class description -- 2.39.5