Attached is the most recent version of this patch. There is still some
work to be done here, but comments are welcome on the general approach.

One question is how spacing and alignment should be handled in commands
that have moving arguments. The existing code is inconsistent:
\begin{onehalfspacing}
\section{\protect\begin{flushright}Section Name\protect\end{flushright}}
\end{onehalfspacing}
So the alignment goes with the argument, the spacing outside it. My view
is that both should go outside, lest the user get an odd surprise in the
table of contents and page headings. (Another option would be simply to
prohibit this kind of thing altogether. As Andre' said, it's really a
misuse of LaTeX.) The present code sets a bool const to choose my
preferred behavior. That could eventually be set from elsewhere or,
obviously, changed.

Other question: Part of what causes a problem in tables is the
occurrence of \par at the end of every \begin{flushright}, etc,
environment that LyX outputs. (I've removed it from the above.) Is this
really necessary? Surely it's not always necessary, and it's the cause
of a lot of problems here. The current patch just removes it, but it's
trivial to put it back, and it wouldn't be too much harder if we wanted
it sometimes but not other times. I just need to know when we need it
and when we don't.

Richard

-- 
==================================================================
Richard G Heck, Jr
Professor of Philosophy
Brown University
http://frege.brown.edu/heck/
==================================================================
Get my public key from http://sks.keyserver.penguin.de
Hash: 0x1DE91F1E66FFBDEC
Learn how to sign your email using Thunderbird and GnuPG at:
http://dudu.dyn.2-h.org/nist/gpg-enigmail-howto

Index: paragraph.C
===================================================================
--- paragraph.C	(revision 17918)
+++ paragraph.C	(working copy)
@@ -69,10 +69,6 @@
 
 namespace lyx {
 
-using support::contains;
-using support::rsplit;
-using support::subst;
-
 Paragraph::Paragraph()
 	: begin_of_body_(0), pimpl_(new Paragraph::Pimpl(this))
 {
@@ -586,6 +582,31 @@
 }
 
 
+bool Paragraph::hasSameSpacing(Paragraph const & par) const
+{
+	return params().sameSpacing(par.params());
+}
+
+
+bool Paragraph::hasSameAlignment(Paragraph const & par) const
+{
+	return params().sameAlignment(par.params());
+}
+
+
+//HACK This is a total hack, as noted in neverIndent itself.
+//A fix requires the solution mentioned there: an InsetCell.
+bool Paragraph::needsCorrection(Buffer const & buf) const 
+{
+	InsetBase::Code ownersCode = ownerCode();
+	if (ownersCode == InsetBase::FLOAT_CODE || ownersCode == InsetBase::WRAP_CODE)
+		return true;
+	if (ownersCode != InsetBase::TEXT_CODE)
+		return false;
+	return static_cast<InsetText *>(inInset())->getText(0)->isMainText(buf);
+}
+
+
 depth_type Paragraph::getDepth() const
 {
 	return params().depth();
@@ -754,187 +775,13 @@
 	return inInset() && inInset()->forceDefaultParagraphs(0);
 }
 
-
-namespace {
-
-// paragraphs inside floats need different alignment tags to avoid
-// unwanted space
-
-bool noTrivlistCentering(InsetBase::Code code)
-{
-	return code == InsetBase::FLOAT_CODE || code == InsetBase::WRAP_CODE;
-}
-
-
-string correction(string const & orig)
-{
-	if (orig == "flushleft")
-		return "raggedright";
-	if (orig == "flushright")
-		return "raggedleft";
-	if (orig == "center")
-		return "centering";
-	return orig;
-}
-
-
-string const corrected_env(string const & suffix, string const & env,
-	InsetBase::Code code)
-{
-	string output = suffix + "{";
-	if (noTrivlistCentering(code))
-		output += correction(env);
-	else
-		output += env;
-	output += "}";
-	if (suffix == "\\begin")
-		output += "\n";
-	return output;
-}
-
-
-void adjust_row_column(string const & str, TexRow & texrow, int & column)
-{
-	if (!contains(str, "\n"))
-		column += str.size();
-	else {
-		string tmp;
-		texrow.newline();
-		column = rsplit(str, tmp, '\n').size();
-	}
-}
-
-} // namespace anon
-
-
-// This could go to ParagraphParameters if we want to
-int Paragraph::startTeXParParams(BufferParams const & bparams,
-                                 odocstream & os, TexRow & texrow, 
-				 bool moving_arg) const
-{
-	int column = 0;
-
-	if (params().noindent()) {
-		os << "\\noindent ";
-		column += 10;
-	}
-
-	switch (params().align()) {
-	case LYX_ALIGN_NONE:
-	case LYX_ALIGN_BLOCK:
-	case LYX_ALIGN_LAYOUT:
-	case LYX_ALIGN_SPECIAL:
-		break;
-	case LYX_ALIGN_LEFT:
-	case LYX_ALIGN_RIGHT:
-	case LYX_ALIGN_CENTER:
-		if (moving_arg) {
-			os << "\\protect";
-			column += 8;
-		}
-		break;
-	}
-
-	switch (params().align()) {
-	case LYX_ALIGN_NONE:
-	case LYX_ALIGN_BLOCK:
-	case LYX_ALIGN_LAYOUT:
-	case LYX_ALIGN_SPECIAL:
-		break;
-	case LYX_ALIGN_LEFT: {
-		string output;
-		if (getParLanguage(bparams)->babel() != "hebrew")
-			output = corrected_env("\\begin", "flushleft", ownerCode());
-		else
-			output = corrected_env("\\begin", "flushright", ownerCode());
-		os << from_ascii(output);
-		adjust_row_column(output, texrow, column);
-		break;
-	} case LYX_ALIGN_RIGHT: {
-		string output;
-		if (getParLanguage(bparams)->babel() != "hebrew")
-			output = corrected_env("\\begin", "flushright", ownerCode());
-		else
-			output = corrected_env("\\begin", "flushleft", ownerCode());
-		os << from_ascii(output);
-		adjust_row_column(output, texrow, column);
-		break;
-	} case LYX_ALIGN_CENTER: {
-		string output;
-		output = corrected_env("\\begin", "center", ownerCode());
-		os << from_ascii(output);
-		adjust_row_column(output, texrow, column);
-		break;
-	}
-	}
-
-	return column;
-}
-
-
-// This could go to ParagraphParameters if we want to
-int Paragraph::endTeXParParams(BufferParams const & bparams,  
-                               odocstream & os, TexRow & texrow,
-			       bool moving_arg) const
-{
-	int column = 0;
-
-	switch (params().align()) {
-	case LYX_ALIGN_NONE:
-	case LYX_ALIGN_BLOCK:
-	case LYX_ALIGN_LAYOUT:
-	case LYX_ALIGN_SPECIAL:
-		break;
-	case LYX_ALIGN_LEFT:
-	case LYX_ALIGN_RIGHT:
-	case LYX_ALIGN_CENTER:
-		if (moving_arg) {
-			os << "\\protect";
-			column = 8;
-		}
-		break;
-	}
-
-	switch (params().align()) {
-	case LYX_ALIGN_NONE:
-	case LYX_ALIGN_BLOCK:
-	case LYX_ALIGN_LAYOUT:
-	case LYX_ALIGN_SPECIAL:
-		break;
-	case LYX_ALIGN_LEFT: {
-		string output;
-		if (getParLanguage(bparams)->babel() != "hebrew")
-			output = corrected_env("\n\\par\\end", "flushleft", ownerCode());
-		else
-			output = corrected_env("\n\\par\\end", "flushright", ownerCode());
-		os << from_ascii(output);
-		adjust_row_column(output, texrow, column);
-		break;
-	} case LYX_ALIGN_RIGHT: {
-		string output;
-		if (getParLanguage(bparams)->babel() != "hebrew")
-			output = corrected_env("\n\\par\\end", "flushright", ownerCode());
-		else
-			output = corrected_env("\n\\par\\end", "flushleft", ownerCode());
-		os << from_ascii(output);
-		adjust_row_column(output, texrow, column);
-		break;
-	} case LYX_ALIGN_CENTER: {
-		string output;
-		output = corrected_env("\n\\par\\end", "center", ownerCode());
-		os << from_ascii(output);
-		adjust_row_column(output, texrow, column);
-		break;
-	}
-	}
-
-	return column;
-}
-
-
-// This one spits out the text of the paragraph
+// This one spits out the latex for the paragraph
+// Note that it does NOT end with a newline.
 bool Paragraph::simpleTeXOnePar(Buffer const & buf,
 				BufferParams const & bparams,
+				docstring const & beginParams, 
+				docstring const & endParams,
+				string const & everypar,
 				LyXFont const & outerfont,
 				odocstream & os, TexRow & texrow,
 				OutputParams const & runparams) const
@@ -945,19 +792,85 @@
 
 	LyXLayout_ptr style;
 
-	// well we have to check if we are in an inset with unlimited
-	// length (all in one row) if that is true then we don't allow
-	// any special options in the paragraph and also we don't allow
-	// any environment other than the default layout of the text class
-	// to be valid!
-	bool asdefault = forceDefaultParagraphs();
+	// Check whether the inset allows paragraph options.
+	bool const forceDefault = forceDefaultParagraphs();
 
-	if (asdefault) {
+	//FIXME This probably just ought to have been passed to us.
+	if (forceDefault) {
 		style = bparams.getLyXTextClass().defaultLayout();
 	} else {
 		style = layout();
 	}
 
+	//FIXME This was in the old code, but I don't see why we need
+	//to do this test. It doesn't have anything to do with the paragraph
+	//we're actually outputing.
+	if (!forceDefault) {
+		if (params().startOfAppendix()) {
+			os << "\\appendix\n";
+			texrow.newline();
+		}
+		
+		if (style->isCommand()) {
+			os << '\n';
+			texrow.newline();
+		}
+	} 
+
+	// Maybe we have to create an optional argument.
+	pos_type body_pos = beginOfBody();
+	bool const haveOptionalArgument = (body_pos > 0);
+	unsigned int column = 0;
+
+	//This might eventually be set from elsewhere---preferences, say.
+	//At present, of course, it will be optimized away.
+	bool const dontHackMovingArgs = false;
+	bool const specialOutputHandling = 
+		!dontHackMovingArgs && style->isCommand() && style->needprotect;
+	
+	switch (style->latextype) {
+	case LATEX_COMMAND:
+		/* 
+		If we are in a command with a moving argument, then the paragraph
+		parameters need to be output BEFORE the command itself, lest one run
+		into all kinds of problems.
+		*/
+		//FIXME @noskipsectrue solves the problem with section spacing and stuff
+		if (specialOutputHandling && !beginParams.empty()) {
+			os << beginParams << "\n";
+			texrow.newline();
+			//column = 0;
+		} // else it'll be output later
+		os << '\\' << from_ascii(style->latexname());
+
+		// Separate handling of optional argument inset.
+		if (style->optionalargs > 0) {
+			int ret = latexOptArgInsets(buf, *this, os, runparams,
+						    style->optionalargs);
+			while (ret > 0) {
+				texrow.newline();
+				--ret;
+			}
+		}
+		else
+			os << from_ascii(style->latexparam());
+		os << "{";
+		column += 1;
+		break;
+	case LATEX_ITEM_ENVIRONMENT:
+	case LATEX_LIST_ENVIRONMENT:
+		os << "\\item ";
+		column += 6;
+		break;
+	case LATEX_BIB_ENVIRONMENT:
+		// ignore this, the inset will write itself
+		//FIXME Should we or shouldn't we output info later?
+		//The old code would have output spacing, but not alignment.
+		break;
+	default:
+		break;
+	}
+	
 	// Current base font for all inherited font changes, without any
 	// change caused by an individual character, except for the language:
 	// It is set to the language of the first character.
@@ -973,11 +886,7 @@
 		&& runparams.flavor == OutputParams::LATEX
 		&& LaTeXFeatures::isAvailable("dvipost");
 
-	// Maybe we have to create a optional argument.
-	pos_type body_pos = beginOfBody();
-	unsigned int column = 0;
-
-	if (body_pos > 0) {
+	if (haveOptionalArgument) {
 		// the optional argument is kept in curly brackets in
 		// case it contains a ']'
 		os << "[{";
@@ -994,23 +903,12 @@
 
 	Change::Type runningChangeType = Change::UNCHANGED;
 
-	texrow.start(id(), 0);
-
-	// if the paragraph is empty, the loop will not be entered at all
-	if (empty()) {
-		if (style->isCommand()) {
-			os << '{';
-			++column;
-		}
-		if (!asdefault)
-			column += startTeXParParams(bparams, os, texrow,
-						    runparams.moving_arg);
-	}
-
+	//	texrow.start(id(), 0);
+	
 	for (pos_type i = 0; i < size(); ++i) {
 		// First char in paragraph or after label?
 		if (i == body_pos) {
-			if (body_pos > 0) {
+			if (haveOptionalArgument) {
 				if (open_font) {
 					column += running_font.latexWriteEndChanges(
 						os, basefont, basefont);
@@ -1024,17 +922,27 @@
 				runningChangeType = Change::UNCHANGED;
 
 				os << "}] ";
-				column +=3;
+				column += 3;
+			} // end if (haveOptionalArgument)
+			
+			//We now output the paragraph parameters, unless we've
+			//already done so.
+			if (!specialOutputHandling && !beginParams.empty()) {
+				os << beginParams << "\n";
+				texrow.newline();
+				column = 0;
 			}
-			if (style->isCommand()) {
-				os << '{';
-				++column;
+			//FIXME Inside or outside, if it's a moving argument?
+			//Probably outside, in which case this should go inside
+			//the previous test, and it would also need moving to the
+			//earlier output location.
+			//In fact, as things stand, this is always empty. Only in
+			//Andre's unfinished insetenv project is it used.
+			if (!everypar.empty()) {
+				os << from_utf8(everypar) << "\n";
+				texrow.newline();
+				column = 0;
 			}
-
-			if (!asdefault)
-				column += startTeXParParams(bparams, os, 
-							    texrow,
-							    runparams.moving_arg);
 		}
 
 		Change::Type changeType = pimpl_->lookupChange(i).type;
@@ -1046,7 +954,7 @@
 			continue;
 		}
 
-		++column;
+		++column; //this is for the character we're now outputting
 		
 		column += Changes::latexMarkChange(os, runningChangeType,
 			changeType, output);
@@ -1114,11 +1022,13 @@
 		rp.free_spacing = style->free_spacing;
 		rp.local_font = &font;
 		rp.intitle = style->intitle;
+
 		pimpl_->simpleTeXSpecialChars(buf, bparams, os,
 					texrow, rp, running_font,
 					basefont, outerfont, open_font,
 					runningChangeType, *style, i, column, c);
-	}
+	} //close of for loop
+	//Output of text of paragraph has now ended
 
 	// If we have an open font definition, we have to close it
 	if (open_font) {
@@ -1147,12 +1057,36 @@
 	// Needed if there is an optional argument but no contents.
 	if (body_pos > 0 && body_pos == size()) {
 		os << "}]~";
+		if (!specialOutputHandling && !beginParams.empty()) {
+			os << beginParams << "\n";
+			texrow.newline();
+			column = 0;
+		}
 		return_value = false;
 	}
-
-	if (!asdefault) {
-		column += endTeXParParams(bparams, os, texrow, 
-					  runparams.moving_arg);
+	
+	//We need to close the command if we were in one,
+	//and output the ending parameters at the right location.
+	if (style->isCommand()) {
+		if (specialOutputHandling) {
+			os << "}";
+			if (!endParams.empty()) {
+				os << "\n" << endParams;
+				texrow.newline();
+			}
+		} else {
+			if (!endParams.empty()) {
+				os << "\n" << endParams;
+				texrow.newline();
+			}
+			os << "}" ;
+		}
+	} 
+	else {
+		if (!endParams.empty()) {
+			os << "\n" << endParams;
+			texrow.newline();
+		}
 	}
 
 	LYXERR(Debug::LATEX) << "SimpleTeXOnePar...done " << this << endl;
Index: paragraph.h
===================================================================
--- paragraph.h	(revision 17918)
+++ paragraph.h	(working copy)
@@ -21,6 +21,7 @@
 #include "InsetList.h"
 #include "lyxlayout_ptr_fwd.h"
 #include "RowList_fwd.h"
+#include "support/RandomAccessList.h"
 
 #include "insets/insetbase.h" // only for InsetBase::Code
 
@@ -115,18 +116,11 @@
 	void validate(LaTeXFeatures &) const;
 
 	///
-	int startTeXParParams(BufferParams const &, odocstream &, TexRow &, 
-			      bool) const;
-
-	///
-	int endTeXParParams(BufferParams const &, odocstream &, TexRow &, 
-			    bool) const;
-
-
-	///
 	bool simpleTeXOnePar(Buffer const &, BufferParams const &,
-			     LyXFont const & outerfont, odocstream &,
-			     TexRow & texrow, OutputParams const &) const;
+           docstring const & beginParams, docstring const & endParams,
+           std::string const & everypar, 
+           LyXFont const &, odocstream &,
+           TexRow &, OutputParams const &) const;
 
 	/// Can we drop the standard paragraph wrapper?
 	bool emptyTag() const;
@@ -153,6 +147,12 @@
 
 	///
 	bool hasSameLayout(Paragraph const & par) const;
+	///
+	bool hasSameSpacing(Paragraph const & par) const;
+	///
+	bool hasSameAlignment(Paragraph const & par) const;
+	///
+	bool needsCorrection(Buffer const & buf) const;
 
 	///
 	void makeSameLayout(Paragraph const & par);
@@ -368,7 +368,6 @@
 	InsetList insetlist;
 
 private:
-
 	///
 	LyXLayout_ptr layout_;
 	/**
Index: Spacing.C
===================================================================
--- Spacing.C	(revision 17918)
+++ Spacing.C	(working copy)
@@ -93,20 +93,22 @@
 }
 
 
-string const Spacing::writeEnvirBegin() const
+string const Spacing::writeEnvirBegin(bool const protectCmd) const
 {
+	string const protection = protectCmd ? "\\protect" : "";
+	 
 	switch (space) {
 	case Default: break; // do nothing
 	case Single:
-		return "\\begin{singlespace}";
+		return protection + "\\begin{singlespace}";
 	case Onehalf:
-		return "\\begin{onehalfspace}";
+		return protection + "\\begin{onehalfspace}";
 	case Double:
-		return "\\begin{doublespace}";
+		return protection + "\\begin{doublespace}";
 	case Other:
 	{
 		ostringstream ost;
-		ost << "\\begin{spacing}{"
+		ost << protection << "\\begin{spacing}{"
 		    << getValueAsString() << '}';
 		return ost.str();
 	}
@@ -115,18 +117,20 @@
 }
 
 
-string const Spacing::writeEnvirEnd() const
+string const Spacing::writeEnvirEnd(bool const protectCmd) const
 {
+	string const protection = protectCmd ? "\\protect" : "";
+	 
 	switch (space) {
 	case Default: break; // do nothing
 	case Single:
-		return "\\end{singlespace}";
+		return protection + "\\end{singlespace}";
 	case Onehalf:
-		return "\\end{onehalfspace}";
+		return protection + "\\end{onehalfspace}";
 	case Double:
-		return "\\end{doublespace}";
+		return protection + "\\end{doublespace}";
 	case Other:
-		return "\\end{spacing}";
+		return protection + "\\end{spacing}";
 	}
 	return string();
 }
Index: Spacing.h
===================================================================
--- Spacing.h	(revision 17918)
+++ Spacing.h	(working copy)
@@ -61,9 +61,9 @@
 	///
 	void writeFile(std::ostream &, bool para = false) const;
 	///
-	std::string const writeEnvirBegin() const;
+	std::string const writeEnvirBegin(bool const protectCmd = false) const;
 	///
-	std::string const writeEnvirEnd() const;
+	std::string const writeEnvirEnd(bool const protectCmd = false) const;
 
 private:
 	///
Index: ParagraphParameters.C
===================================================================
--- ParagraphParameters.C	(revision 17918)
+++ ParagraphParameters.C	(working copy)
@@ -17,13 +17,15 @@
 #include "ParagraphParameters.h"
 
 #include "buffer.h"
+#include "debug.h"
 #include "gettext.h"
 #include "lyxlayout.h"
 #include "lyxlex.h"
 #include "lyxtext.h"
 #include "paragraph.h"
 #include "tex-strings.h"
-
+#include "insets/inset.h"
+#include "insets/insetbase.h"
 #include "support/lstrings.h"
 
 #include <sstream>
@@ -31,6 +33,9 @@
 namespace lyx {
 
 using support::rtrim;
+//For adjust_row_column
+//using support::contains;
+//using support::rsplit;
 
 using std::istringstream;
 using std::ostream;
@@ -38,6 +43,59 @@
 using std::string;
 
 
+namespace {
+
+// paragraphs inside floats and such need different alignment tags to avoid
+// unwanted space
+
+string correction(string const & orig)
+{
+	if (orig == "flushleft")
+		return "raggedright";
+	if (orig == "flushright")
+		return "raggedleft";
+	if (orig == "center")
+		return "centering";
+	return orig;
+}
+
+
+string const corrected_env(string const & prefix, string const & env,
+	bool needsCorrection = false)
+{
+	string output = prefix + "{";
+	if (needsCorrection)
+		output += correction(env);
+	else
+		output += env;
+	output += "}";
+	return output;
+}
+
+
+/* At the moment, this isn't needed, but it might be needed at some point.
+   I've generalized it to deal with multiple `\n's.
+void adjust_row_column(string const & str, TexRow & texrow, int & column)
+{
+	if (!contains(str, "\n")) {
+		contains += str.size();
+		return;
+}
+	string rightSide = str;
+	string leftSide;
+	while (contains(rightSide, "\n") {
+		string const tmp = rightSide;
+		rightSide = rsplit(tmp, leftSide, "\n");
+		texrow.newline();
+	}
+	column = whatsLeft.size();
+	return;
+}
+*/
+
+} // namespace anon
+
+
 static int findToken(char const * const str[], string const & search_token)
 {
 	return search_token == "default" ?
@@ -74,6 +132,18 @@
 }
 
 
+bool ParagraphParameters::sameSpacing(ParagraphParameters const & pp) const
+{
+	return spacing_ == pp.spacing_;
+}
+
+
+bool ParagraphParameters::sameAlignment(ParagraphParameters const & pp) const
+{
+	return align_ == pp.align_;
+}
+
+
 Spacing const & ParagraphParameters::spacing() const
 {
 	return spacing_;
@@ -314,4 +384,126 @@
 */
 
 
+string const ParagraphParameters::writeAlignBegin(
+	Language const * const & lang, bool const needsCorrection, 
+ 	bool const movingArg) const 
+{
+	string const protect = movingArg ? "\\protect" : "";
+	switch (align()) {
+		case LYX_ALIGN_NONE:
+		case LYX_ALIGN_BLOCK:
+		case LYX_ALIGN_LAYOUT:
+		case LYX_ALIGN_SPECIAL:
+			return "";
+		case LYX_ALIGN_LEFT: {
+			if (lang->babel() != "hebrew")
+				// NOTE NO_MOVING_ARG
+				// return protect + corrected_env(protect + "\\begin", "flushleft", needsCorrection);
+				// and similarly below
+				return corrected_env(protect + "\\begin", "flushleft", needsCorrection);
+			else
+				return corrected_env(protect + "\\begin", "flushright", needsCorrection);
+		} case LYX_ALIGN_RIGHT: {
+			if (lang->babel() != "hebrew")
+				return corrected_env(protect + "\\begin", "flushright", needsCorrection);
+			else
+				return corrected_env(protect + "\\begin", "flushleft", needsCorrection);
+		} case LYX_ALIGN_CENTER: {
+			return corrected_env(protect + "\\begin", "center", needsCorrection);
+		}
+	}
+	//should never get here
+	lyxerr << BOOST_CURRENT_FUNCTION << "Invalid alignment" << 
+		align() << std::endl;
+	return "";
+}
+
+
+string const ParagraphParameters::writeAlignEnd(
+	Language const * const & lang, bool const needsCorrection, 
+ 	bool const movingArg) const 
+{
+	string const protect = movingArg ? "\\protect" : ""; // or "\\par"??
+	switch (align()) {
+		case LYX_ALIGN_NONE:
+		case LYX_ALIGN_BLOCK:
+		case LYX_ALIGN_LAYOUT:
+		case LYX_ALIGN_SPECIAL:
+			return "";
+		case LYX_ALIGN_LEFT: {
+			if (lang->babel() != "hebrew")
+				return corrected_env(protect + "\\end", "flushleft", needsCorrection);
+			else
+				return corrected_env(protect + "\\end", "flushright", needsCorrection);
+		} case LYX_ALIGN_RIGHT: {
+			if (lang->babel() != "hebrew")
+				return corrected_env(protect + "\\end", "flushright", needsCorrection);
+			else
+				return corrected_env(protect + "\\end", "flushleft", needsCorrection);
+		} case LYX_ALIGN_CENTER: {
+			return corrected_env(protect + "\\end", "center", needsCorrection);
+		}
+	}
+	//should never get here
+	lyxerr << BOOST_CURRENT_FUNCTION << "Invalid alignment" << 
+		align() << std::endl;
+	return "";
+}
+
+
+//FIXME Can't we somehow avoid passing isFirst here?
+string ParagraphParameters::writeParamsBegin(
+	ParagraphList::const_iterator & pit, 
+	Language const * const & lang,
+	bool const isFirst, bool const protectFragile,
+	bool const needsCorrection) const
+{
+	if (pit->forceDefaultParagraphs()) return "";
+	
+	ostringstream output;
+	
+	//If the layout isn't default 
+	//and we're either in the first paragraph or
+	//the previous paragraph has the same alignment...
+	if (!spacing().isDefault()
+		&& (isFirst || !boost::prior(pit)->hasSameSpacing(*pit)))
+			output << spacing().writeEnvirBegin(protectFragile) << " ";
+
+	if (pit->params().noindent())
+		output << (protectFragile ? "\\protect" : "") << "\\noindent ";
+
+	if (align() != LYX_ALIGN_LAYOUT
+		&& align() != pit->layout()->align
+		&& (isFirst || !boost::prior(pit)->hasSameAlignment(*pit)))
+			output << 
+				writeAlignBegin(lang, needsCorrection, protectFragile) << 
+				" ";
+	
+	return output.str();
+}
+
+
+string ParagraphParameters::writeParamsEnd(
+	ParagraphList::const_iterator & pit, 
+	Language const * const & lang,
+	bool const isLast, bool const protectFragile,
+	bool const needsCorrection) const 
+{
+	if (pit->forceDefaultParagraphs()) return "";
+	
+	ostringstream output;
+
+	if (align() != LYX_ALIGN_LAYOUT
+		&& align() != pit->layout()->align
+		&& (isLast || !boost::next(pit)->hasSameAlignment(*pit)))
+			output << 
+				writeAlignEnd(lang, needsCorrection, protectFragile) << 
+				" ";
+	
+	if (!spacing().isDefault()
+		&& (isLast || !boost::next(pit)->hasSameSpacing(*pit)))
+			output << spacing().writeEnvirEnd(protectFragile) << " ";
+	return output.str();
+}
+
 } // namespace lyx
Index: ParagraphParameters.h
===================================================================
--- ParagraphParameters.h	(revision 17918)
+++ ParagraphParameters.h	(working copy)
@@ -14,8 +14,10 @@
 #ifndef PARAGRAPHPARAMETERS_H
 #define PARAGRAPHPARAMETERS_H
 
+#include "language.h"
 #include "layout.h"
 #include "lyxlength.h"
+#include "ParagraphList.h"
 #include "Spacing.h"
 
 #include "support/types.h"
@@ -44,6 +46,10 @@
 	///
 	bool sameLayout(ParagraphParameters const &) const;
 	///
+	bool sameSpacing(ParagraphParameters const &) const;
+	///
+	bool sameAlignment(ParagraphParameters const &) const;
+	///
 	Spacing const & spacing() const;
 	///
 	void spacing(Spacing const &);
@@ -85,10 +91,33 @@
 
 	/// write out the parameters to a stream
 	void write(std::ostream & os) const;
+	
+	/// Writes the opening LaTeX for spacing, alignment, and indentation
+	/// @return a string, with no newlines embedded
+	std::string writeParamsBegin(ParagraphList::const_iterator & pit, 
+		Language const * const & lang, bool const isFirst = false,
+		bool const protectFragile = false, bool const needsCorrection = false) 
+		const; 
+	/// Writes the closing LaTeX for spacing, alignment, and indentation
+	/// @return a string, with no newlines embedded
+	std::string writeParamsEnd(ParagraphList::const_iterator & pit, 
+		Language const * const & lang, bool const isLast = false,
+		bool const protectFragile = false, bool const needsCorrection = false) 
+		const; 
+	
 
 	//friend bool operator==(ParameterStruct const & ps1,
 	//ParameterStruct const & ps2);
 
+protected:
+	/// 
+	std::string const writeAlignBegin(Language const * const &, 
+		bool const, bool const movingArg = false) const;
+	///
+	std::string const writeAlignEnd(Language const * const &, 
+		bool const, bool const movingArg = false) const;
+
+	
 private:
 	///
 	Spacing spacing_;
Index: output_latex.C
===================================================================
--- output_latex.C	(revision 17918)
+++ output_latex.C	(working copy)
@@ -244,10 +244,20 @@
 		<< everypar << "'" << endl;
 	BufferParams const & bparams = buf.params();
 	LyXLayout_ptr style;
-
-	// In an inset with unlimited length (all in one row),
-	// force layout to default
-	if (!pit->forceDefaultParagraphs())
+	
+	texrow.start(pit->id(), 0);
+		
+	bool const forceDefault = pit->forceDefaultParagraphs();
+	ParagraphList::const_iterator const nextParIterator = boost::next(pit);
+	bool const isFirstPar = (pit == paragraphs.begin());
+	bool const isLastPar = (nextParIterator == paragraphs.end());
+	Paragraph const * const prevPar = isFirstPar ? 0 :
+		const_cast<Paragraph *>(& * boost::prior(pit));
+	//Paragraph const * const nextPar = isLastPar ? 0 :
+	//	const_cast<Paragraph *>(& * nextParIterator);
+	
+	//Some insets don't allow customization
+	if (!forceDefault)
 		style = pit->layout();
 	else
 		style = bparams.getLyXTextClass().defaultLayout();
@@ -257,18 +267,22 @@
 
 	Language const * const par_language = pit->getParLanguage(bparams);
 	Language const * const doc_language = bparams.language;
-	Language const * const prev_par_language =
-		(pit != paragraphs.begin())
-		? boost::prior(pit)->getParLanguage(bparams)
+	Language const * const prev_par_language = (!isFirstPar)
+		? prevPar->getParLanguage(bparams)
 		: doc_language;
 
+	//Change language of paragraph if necessary
 	if (par_language->babel() != prev_par_language->babel()
 	    // check if we already put language command in TeXEnvironment()
-	    && !(style->isEnvironment()
-		 && (pit == paragraphs.begin() ||
-		     (boost::prior(pit)->layout() != pit->layout() &&
-		      boost::prior(pit)->getDepth() <= pit->getDepth())
-		     || boost::prior(pit)->getDepth() < pit->getDepth())))
+			&& !(style->isEnvironment()
+			      && (isFirstPar 
+			         || (prevPar->layout() != pit->layout() &&
+		               prevPar->getDepth() <= pit->getDepth()
+		              )
+			         || prevPar->getDepth() < pit->getDepth()
+			         )
+			     )
+		 )
 	{
 		if (!lyxrc.language_command_end.empty() &&
 		    prev_par_language->babel() != doc_language->babel())
@@ -319,64 +333,40 @@
 		}
 	}
 
-	// In an inset with unlimited length (all in one row),
-	// don't allow any special options in the paragraph
-	if (!pit->forceDefaultParagraphs()) {
-		if (pit->params().startOfAppendix()) {
-			os << "\\appendix\n";
-			texrow.newline();
-		}
+	//FIXME It would be nice if these could just be calculated in
+	//simpleTexOnePar, but if that is to happen we would need to pass
+	//the ParagraphList::const_iterator, and I simply cannot manage to 
+	//make that work. Alternatively, we could pass isFirstPar and isLastPar,
+	//or we could somehow find this information ourselves.
+	//FIXME If we wanted to move the above there, as well, then we'd need
+	//to pass prevPar and nextPar, I think. It's possible these could be null
+	//if there is no such thing, and that would encode firstPar and lastPar.
+	
+	//The idea here is that this might eventually be set from somewhere else,
+	//e.g. from preferences. At present, of course, it will be optimized away.
+	bool const dontHackMovingArgs = false;
+	docstring const beginParams =
+		from_ascii(pit->params().writeParamsBegin(
+				pit, par_language, isFirstPar, 
+				dontHackMovingArgs && style->needprotect,
+				pit->needsCorrection(buf)
+		));
+	docstring const endParams =
+		from_ascii(pit->params().writeParamsEnd(
+			pit, par_language, isLastPar, 
+			dontHackMovingArgs && style->needprotect,
+			pit->needsCorrection(buf)
+		));
 
-		if (!pit->params().spacing().isDefault()
-			&& (pit == paragraphs.begin()
-			    || !boost::prior(pit)->hasSameLayout(*pit)))
-		{
-			os << from_ascii(pit->params().spacing().writeEnvirBegin())
-			    << '\n';
-			texrow.newline();
-		}
-
-		if (style->isCommand()) {
-			os << '\n';
-			texrow.newline();
-		}
-	}
-
-	switch (style->latextype) {
-	case LATEX_COMMAND:
-		os << '\\' << from_ascii(style->latexname());
-
-		// Separate handling of optional argument inset.
-		if (style->optionalargs > 0) {
-			int ret = latexOptArgInsets(buf, *pit, os, runparams,
-						    style->optionalargs);
-			while (ret > 0) {
-				texrow.newline();
-				--ret;
-			}
-		}
-		else
-			os << from_ascii(style->latexparam());
-		break;
-	case LATEX_ITEM_ENVIRONMENT:
-	case LATEX_LIST_ENVIRONMENT:
-		os << "\\item ";
-		break;
-	case LATEX_BIB_ENVIRONMENT:
-		// ignore this, the inset will write itself
-		break;
-	default:
-		break;
-	}
-
 	LyXFont const outerfont =
 		outerFont(std::distance(paragraphs.begin(), pit),
 			  paragraphs);
 
-	// FIXME UNICODE
-	os << from_utf8(everypar);
-	bool need_par = pit->simpleTeXOnePar(buf, bparams, outerfont,
-					     os, texrow, runparams);
+	//FIXME Probably should pass style here, as well.
+	pit->simpleTeXOnePar(buf, bparams, 
+                       beginParams, endParams, everypar, 
+                       outerfont,
+                       os, texrow, runparams);
 
 	// Make sure that \\par is done with the font of the last
 	// character if this has another size as the default.
@@ -385,73 +375,49 @@
 	// to this font. (Matthias)
 	//
 	// Is this really needed ? (Dekel)
-	// We do not need to use to change the font for the last paragraph
-	// or for a command.
 
 	LyXFont const font =
 		(pit->empty()
 		 ? pit->getLayoutFont(bparams, outerfont)
 		 : pit->getFont(bparams, pit->size() - 1, outerfont));
 
-	bool is_command = style->isCommand();
-
+	// We do not need to change the font for the last paragraph
+	// or for a command
 	if (style->resfont.size() != font.size()
-	    && boost::next(pit) != paragraphs.end()
-	    && !is_command) {
-		if (!need_par)
-			os << '{';
-		os << "\\" << from_ascii(font.latexSize()) << " \\par}";
-	} else if (need_par) {
-		os << "\\par}";
-	} else if (is_command)
-		os << '}';
-
+      && !isLastPar && !style->isCommand()) {
+		os << '{' << "\\" << from_ascii(font.latexSize()) << "}";
+	}
+	
 	bool pending_newline = false;
 	switch (style->latextype) {
 	case LATEX_ITEM_ENVIRONMENT:
 	case LATEX_LIST_ENVIRONMENT:
-		if (boost::next(pit) != paragraphs.end()
-		    && (pit->params().depth() < boost::next(pit)->params().depth()))
+		if (!isLastPar
+		    && (pit->params().depth() < nextParIterator->params().depth()))
 			pending_newline = true;
 		break;
 	case LATEX_ENVIRONMENT: {
 		// if its the last paragraph of the current environment
 		// skip it otherwise fall through
-		ParagraphList::const_iterator next = boost::next(pit);
+		
 
-		if (next != paragraphs.end()
-		    && (next->layout() != pit->layout()
-			|| next->params().depth() != pit->params().depth()))
+		if (nextParIterator != paragraphs.end()
+		    && (nextParIterator->layout() != pit->layout()
+			|| nextParIterator->params().depth() != pit->params().depth()))
 			break;
 	}
-
-		// fall through possible
+	// fall through possible
 	default:
 		// we don't need it for the last paragraph!!!
-		if (boost::next(pit) != paragraphs.end())
+		if (!isLastPar)
 			pending_newline = true;
 	}
 
-	if (!pit->forceDefaultParagraphs()) {
-		if (!pit->params().spacing().isDefault()
-			&& (boost::next(pit) == paragraphs.end()
-			    || !boost::next(pit)->hasSameLayout(*pit)))
-		{
-			if (pending_newline) {
-				os << '\n';
-				texrow.newline();
-			}
-			os << from_ascii(pit->params().spacing().writeEnvirEnd());
-			pending_newline = true;
-		}
-	}
-
-	if (boost::next(pit) == paragraphs.end()
+	// Since \selectlanguage writes the language to the aux file,
+	// we need to reset the language at the end of footnote or
+	// float.
+	if (isLastPar
 	    && par_language->babel() != doc_language->babel()) {
-		// Since \selectlanguage write the language to the aux file,
-		// we need to reset the language at the end of footnote or
-		// float.
-
 		if (pending_newline) {
 			os << '\n';
 			texrow.newline();
@@ -478,14 +444,12 @@
 	// we don't need it for the last paragraph!!!
 	// Note from JMarc: we will re-add a \n explicitely in
 	// TeXEnvironment, because it is needed in this case
-	if (boost::next(pit) != paragraphs.end()) {
-		os << '\n';
+	if (!isLastPar) {
+		os << "\n";
 		texrow.newline();
+		LYXERR(Debug::LATEX) << "TeXOnePar...done " << &*nextParIterator << endl;
 	}
 
-	if (boost::next(pit) != paragraphs.end())
-		LYXERR(Debug::LATEX) << "TeXOnePar...done " << &*boost::next(pit) << endl;
-
 	return ++pit;
 }
 

Reply via email to