The attached patch adds a facility for file-specific layout, e.g.:
\begin_local_layout
Format 6
InsetLayout CharStyle:MenuItem
LyxType charstyle
LabelString menu
LatexType command
LatexName menuitem
Font
Family Sans
EndFont
Preamble
\newcommand{\menuitem}[1]{\sffamily{#1}}
EndPreamble
End
\end_local_layout
which I presently have working in the headers of Customization.lyx. As
I've started to use 1.6 a bit, I've found that this kind of
file-specific layout is incredibly useful. If I'm working on a file, and
I want to define a new character style, or paragraph layout, or
whatever, I may want it only for that file. I don't want to have to
create a *.module and then copy it somewhere, etc, etc. I just want to
create layout.
Comments?
At present, I'm proposing to commit the patch as-is, without UI, and
then add UI later. (This should be simple enough.) It's very much an
"advanced feature", so I'd like to discourage people from using it,
actually, unless they REALLY know what they are doing. Any thoughts
about that?
Ultimately, this could also help solve some of Bo's worries about
bundling. In principle, one could embed an entire layout file the same way.
Richard
Index: src/BufferParams.h
===================================================================
--- src/BufferParams.h (revision 23883)
+++ src/BufferParams.h (working copy)
@@ -220,6 +220,8 @@
///
std::string preamble;
///
+ std::string local_layout;
+ ///
std::string options;
///
std::string float_placement;
@@ -316,6 +318,8 @@
///
void readPreamble(Lexer &);
///
+ void readLocalLayout(Lexer &);
+ ///
void readLanguage(Lexer &);
///
void readGraphicsDriver(Lexer &);
Index: src/BufferParams.cpp
===================================================================
--- src/BufferParams.cpp (revision 23883)
+++ src/BufferParams.cpp (working copy)
@@ -506,6 +506,8 @@
} else if (token == "\\begin_preamble") {
readPreamble(lex);
+ } else if (token == "\\begin_local_layout") {
+ readLocalLayout(lex);
} else if (token == "\\begin_modules") {
readModules(lex);
} else if (token == "\\options") {
@@ -722,6 +724,15 @@
os << "\\end_modules" << '\n';
}
+ // local layout information
+ if (!local_layout.empty()) {
+ // remove '\n' from the end
+ string const tmplocal = rtrim(local_layout, "\n");
+ os << "\\begin_local_layout\n"
+ << tmplocal
+ << "\n\\end_local_layout\n";
+ }
+
// then the text parameters
if (language != ignore_language)
os << "\\language " << language->lang() << '\n';
@@ -1501,6 +1512,12 @@
frontend::Alert::warning(_("Read Error"), msg);
}
}
+ if (!local_layout.empty()) {
+ if (!doc_class_->read(local_layout, TextClass::MODULE)) {
+ docstring const msg = _("Error reading internal layout information");
+ frontend::Alert::warning(_("Read Error"), msg);
+ }
+ }
}
@@ -1555,6 +1572,16 @@
}
+void BufferParams::readLocalLayout(Lexer & lex)
+{
+ if (lex.getString() != "\\begin_local_layout")
+ lyxerr << "Error (BufferParams::readLocalLayout):"
+ "consistency check failed." << endl;
+
+ local_layout = lex.getLongString("\\end_local_layout");
+}
+
+
void BufferParams::readLanguage(Lexer & lex)
{
if (!lex.next()) return;
Index: src/TextClass.h
===================================================================
--- src/TextClass.h (revision 23883)
+++ src/TextClass.h (working copy)
@@ -129,9 +129,20 @@
MERGE, //>This is a file included in a layout file
MODULE //>This is a layout module
};
+ /// return values for read()
+ enum ReturnValues {
+ OK,
+ ERROR,
+ FORMAT_MISMATCH
+ };
+
/// Performs the read of the layout file.
/// \return true on success.
bool read(support::FileName const & filename, ReadType rt = BASECLASS);
+ ///
+ bool read(std::string const & str, ReadType rt = BASECLASS);
+ ///
+ ReturnValues read(Lexer & lex, ReadType rt = BASECLASS);
///////////////////////////////////////////////////////////////////
// loading
@@ -242,6 +253,8 @@
///////////////////////////////////////////////////////////////////
///
bool deleteLayout(docstring const &);
+ ///
+ bool convertLayoutFormat(support::FileName const &, ReadType);
/// \return true for success.
bool readStyle(Lexer &, Layout &);
///
Index: src/TextClass.cpp
===================================================================
--- src/TextClass.cpp (revision 23883)
+++ src/TextClass.cpp (working copy)
@@ -180,14 +180,7 @@
};
-// Reads a textclass structure from file.
-bool TextClass::read(FileName const & filename, ReadType rt)
-{
- if (!filename.isReadableFile()) {
- lyxerr << "Cannot read layout file `" << filename << "'."
- << endl;
- return false;
- }
+namespace {
keyword_item textClassTags[] = {
{ "classoptions", TC_CLASSOPTIONS },
@@ -216,14 +209,36 @@
{ "titlelatextype", TC_TITLELATEXTYPE },
{ "tocdepth", TC_TOCDEPTH }
};
+
+} //namespace anon
+
+bool TextClass::convertLayoutFormat(support::FileName const & filename, ReadType rt)
+{
+ LYXERR(Debug::TCLASS, "Converting layout file to " << FORMAT);
+ FileName const tempfile = FileName::tempName();
+ bool success = layout2layout(filename, tempfile);
+ if (success)
+ read(tempfile, rt);
+ tempfile.removeFile();
+ return success;
+}
+
+bool TextClass::read(FileName const & filename, ReadType rt)
+{
+ if (!filename.isReadableFile()) {
+ lyxerr << "Cannot read layout file `" << filename << "'."
+ << endl;
+ return false;
+ }
+
LYXERR(Debug::TCLASS, "Reading " + translateRT(rt) + ": " +
to_utf8(makeDisplayPath(filename.absFilename())));
// Define the `empty' layout used in table cells, ert, etc. Note that
// we do this before loading any layout file, so that classes can
// override features of this layout if they should choose to do so.
- if (rt == BASECLASS) {
+ if (rt == BASECLASS && !hasLayout(emptylayout_)) {
static char const * s = "Margin Static\n"
"LatexType Paragraph\n"
"LatexName dummy\n"
@@ -243,11 +258,43 @@
};
layoutlist_.push_back(lay);
}
+ Lexer lexrc(textClassTags,
+ sizeof(textClassTags) / sizeof(textClassTags[0]));
+ lexrc.setFile(filename);
+ ReturnValues retval = read(lexrc, rt);
+
+ LYXERR(Debug::TCLASS, "Finished reading " + translateRT(rt) + ": " +
+ to_utf8(makeDisplayPath(filename.absFilename())));
+
+ if (retval != FORMAT_MISMATCH)
+ return retval == OK;
+
+ bool const worx = convertLayoutFormat(filename, rt);
+ if (!worx) {
+ lyxerr << "Unable to convert " << filename <<
+ " to format " << FORMAT << std::endl;
+ return false;
+ }
+ return true;
+}
+
+
+bool TextClass::read(std::string const & str, ReadType rt)
+{
Lexer lexrc(textClassTags,
sizeof(textClassTags) / sizeof(textClassTags[0]));
+ istringstream is(str);
+ lexrc.setStream(is);
+ ReturnValues retval = read(lexrc, rt);
+ // FIXME We should deal with format errors here, too.
+ return retval == OK;
+}
- lexrc.setFile(filename);
+
+// Reads a textclass structure from file.
+TextClass::ReturnValues TextClass::read(Lexer & lexrc, ReadType rt)
+{
bool error = !lexrc.isOK();
// Format of files before the 'Format' tag was introduced
@@ -482,22 +529,11 @@
break;
}
- if (format != FORMAT) {
- LYXERR(Debug::TCLASS, "Converting layout file from format "
- << format << " to " << FORMAT);
- FileName const tempfile = FileName::tempName();
- bool success = layout2layout(filename, tempfile);
- if (success)
- read(tempfile, rt);
- tempfile.removeFile();
- return success;
- }
+ if (format != FORMAT)
+ return FORMAT_MISMATCH;
- LYXERR(Debug::TCLASS, "Finished reading " + translateRT(rt) + ": " +
- to_utf8(makeDisplayPath(filename.absFilename())));
-
if (rt != BASECLASS)
- return !error;
+ return (error ? ERROR : OK);
if (defaultlayout_.empty()) {
lyxerr << "Error: Textclass '" << name_
@@ -547,7 +583,7 @@
LYXERR(Debug::TCLASS, "Minimum TocLevel is " << min_toclevel_
<< ", maximum is " << max_toclevel_);
- return !error;
+ return (error ? ERROR : OK);
}