diff --git a/src/Buffer.cpp b/src/Buffer.cpp index 3956896d39..2b2660e2c8 100644 --- a/src/Buffer.cpp +++ b/src/Buffer.cpp @@ -1932,6 +1932,10 @@ void Buffer::writeLaTeXSource(otexstream & os, // make the body. os << "\\begin{document}\n"; + // mark the start of a new paragraph by simulating a newline, + // so that os.afterParbreak() returns true at document start + os.lastChar('\n'); + // output the parent macros MacroSet::iterator it = parentMacros.begin(); MacroSet::iterator end = parentMacros.end(); diff --git a/src/Changes.cpp b/src/Changes.cpp index 88ecaf256d..88ebbbd72f 100644 --- a/src/Changes.cpp +++ b/src/Changes.cpp @@ -421,7 +421,7 @@ int Changes::latexMarkChange(otexstream & os, BufferParams const & bparams, // close \lyxadded or \lyxdeleted os << '}'; column++; - if (oldChange.type == Change::DELETED) + if (oldChange.type == Change::DELETED && !runparams.wasDisplayMath) --runparams.inulemcmd; } @@ -433,7 +433,8 @@ int Changes::latexMarkChange(otexstream & os, BufferParams const & bparams, docstring macro_beg; if (change.type == Change::DELETED) { macro_beg = from_ascii("\\lyxdeleted{"); - ++runparams.inulemcmd; + if (!runparams.inDisplayMath) + ++runparams.inulemcmd; } else if (change.type == Change::INSERTED) macro_beg = from_ascii("\\lyxadded{"); @@ -442,6 +443,17 @@ int Changes::latexMarkChange(otexstream & os, BufferParams const & bparams, bparams.authors().get(change.author).name(), chgTime, runparams); + // signature needed by \lyxsout to correctly strike out display math + if (change.type == Change::DELETED && runparams.inDisplayMath + && (!LaTeXFeatures::isAvailable("dvipost") + || (runparams.flavor != OutputParams::LATEX + && runparams.flavor != OutputParams::DVILUATEX))) { + if (os.afterParbreak()) + str += from_ascii("\\\\\\noindent\n"); + else + str += from_ascii("\\\\\\\\\n"); + } + os << str; column += str.size(); diff --git a/src/LaTeXFeatures.cpp b/src/LaTeXFeatures.cpp index 15d4370cab..4702db0e8b 100644 --- a/src/LaTeXFeatures.cpp +++ b/src/LaTeXFeatures.cpp @@ -191,12 +191,25 @@ static docstring const changetracking_dvipost_def = from_ascii( static docstring const changetracking_xcolor_ulem_def = from_ascii( "%% Change tracking with ulem\n" "\\DeclareRobustCommand{\\lyxadded}[3]{{\\color{lyxadded}{}#3}}\n" - "\\DeclareRobustCommand{\\lyxdeleted}[3]{{\\color{lyxdeleted}\\sout{#3}}}\n"); + "\\DeclareRobustCommand{\\lyxdeleted}[3]{{\\color{lyxdeleted}\\lyxsout{#3}}}\n" + "\\DeclareRobustCommand{\\lyxsout}[1]{\\ifx\\\\#1\\else\\sout{#1}\\fi}\n"); static docstring const changetracking_xcolor_ulem_hyperref_def = from_ascii( "%% Change tracking with ulem\n" "\\DeclareRobustCommand{\\lyxadded}[3]{{\\texorpdfstring{\\color{lyxadded}{}}{}#3}}\n" - "\\DeclareRobustCommand{\\lyxdeleted}[3]{{\\texorpdfstring{\\color{lyxdeleted}\\sout{#3}}{}}}\n"); + "\\DeclareRobustCommand{\\lyxdeleted}[3]{{\\texorpdfstring{\\color{lyxdeleted}\\lyxsout{#3}}{}}}\n" + "\\DeclareRobustCommand{\\lyxsout}[1]{\\ifx\\\\#1\\else\\sout{#1}\\fi}\n"); + +static docstring const changetracking_tikz_math_sout_def = from_ascii( + "%% Strike out display math with tikz\n" + "\\usepackage{tikz}\n" + "\\usetikzlibrary{calc}\n" + "\\newcommand{\\lyxmathsout}[1]{%\n" + " \\tikz[baseline=(math.base)]{\n" + " \\node[inner sep=0pt,outer sep=0pt](math){#1};\n" + " \\draw($(math.south west)+(2em,.5em)$)--($(math.north east)-(2em,.5em)$);\n" + " }\n" + "}\n"); static docstring const changetracking_none_def = from_ascii( "\\newcommand{\\lyxadded}[3]{#3}\n" @@ -388,7 +401,8 @@ static docstring const lyxstrikeout_style = from_ascii( LaTeXFeatures::LaTeXFeatures(Buffer const & b, BufferParams const & p, OutputParams const & r) - : buffer_(&b), params_(p), runparams_(r), in_float_(false) + : buffer_(&b), params_(p), runparams_(r), in_float_(false), + in_deleted_inset_(false) {} @@ -1367,6 +1381,9 @@ docstring const LaTeXFeatures::getMacros() const macros << changetracking_xcolor_ulem_def; } + if (mustProvide("ct-tikz-math-sout")) + macros << changetracking_tikz_math_sout_def; + if (mustProvide("ct-none")) macros << changetracking_none_def; diff --git a/src/LaTeXFeatures.h b/src/LaTeXFeatures.h index 9bf0f621da..754b445d00 100644 --- a/src/LaTeXFeatures.h +++ b/src/LaTeXFeatures.h @@ -156,6 +156,10 @@ public: bool inFloat() const { return in_float_; } /// are we in a float? void inFloat(bool const b) { in_float_ = b; } + /// are we in a deleted inset? + bool inDeletedInset() const { return in_deleted_inset_; } + /// are we in a deleted inset? + void inDeletedInset(bool const b) { in_deleted_inset_ = b; } /// Runparams that will be used for exporting this file. OutputParams const & runparams() const { return runparams_; } /// Resolve alternatives like "esint|amsmath|wasysym" @@ -209,6 +213,8 @@ private: /// bool in_float_; /// + bool in_deleted_inset_; + /// docstring htmltitle_; }; diff --git a/src/OutputParams.cpp b/src/OutputParams.cpp index 55768aec53..26e3dda787 100644 --- a/src/OutputParams.cpp +++ b/src/OutputParams.cpp @@ -23,7 +23,7 @@ OutputParams::OutputParams(Encoding const * enc) moving_arg(false), intitle(false), inulemcmd(0), local_font(0), master_language(0), encoding(enc), free_spacing(false), use_babel(false), use_polyglossia(false), use_indices(false), use_japanese(false), linelen(0), depth(0), - exportdata(new ExportData), + exportdata(new ExportData), inDisplayMath(false), wasDisplayMath(false), inComment(false), inTableCell(NO), inFloat(NONFLOAT), inIndexEntry(false), inIPA(false), inDeletedInset(0), changeOfDeletedInset(Change::UNCHANGED), diff --git a/src/OutputParams.h b/src/OutputParams.h index 16fe7c4a76..6356b9d890 100644 --- a/src/OutputParams.h +++ b/src/OutputParams.h @@ -184,6 +184,16 @@ public: */ shared_ptr exportdata; + /** Whether we are entering a display math inset. + * Needed to correctly strike out deleted math in change tracking. + */ + mutable bool inDisplayMath; + + /** Whether we are leaving a display math inset. + * Needed to correctly track nested ulem commands in change tracking. + */ + mutable bool wasDisplayMath; + /** Whether we are inside a comment inset. Insets that are including * external files like InsetGraphics, InsetInclude and InsetExternal * may only write the usual output and must not attempt to do diff --git a/src/Paragraph.cpp b/src/Paragraph.cpp index 1f8b18d7e9..7ac0a666cf 100644 --- a/src/Paragraph.cpp +++ b/src/Paragraph.cpp @@ -52,6 +52,8 @@ #include "insets/InsetLabel.h" #include "insets/InsetSpecialChar.h" +#include "mathed/InsetMathHull.h" + #include "support/debug.h" #include "support/docstring_list.h" #include "support/ExceptionMessage.h" @@ -1437,7 +1439,9 @@ void Paragraph::Private::validate(LaTeXFeatures & features) const InsetList::const_iterator iend = insetlist_.end(); for (; icit != iend; ++icit) { if (icit->inset) { + features.inDeletedInset(owner_->isDeleted(icit->pos)); icit->inset->validate(features); + features.inDeletedInset(false); if (layout_->needprotect && icit->inset->lyxCode() == FOOT_CODE) features.require("NeedLyXFootnoteCode"); @@ -2391,6 +2395,25 @@ void Paragraph::latex(BufferParams const & bparams, runparams); } + runparams.wasDisplayMath = runparams.inDisplayMath; + runparams.inDisplayMath = false; + bool deleted_display_math = false; + + // Check whether a display math inset follows + if (d->text_[i] == META_INSET + && i >= start_pos && (end_pos == -1 || i < end_pos)) { + InsetMath const * im = getInset(i)->asInsetMath(); + if (im && im->asHullInset() + && im->asHullInset()->outerDisplay()) { + runparams.inDisplayMath = true; + // runparams.inDeletedInset will be set by + // latexInset later, but we need this info + // before it is called. On the other hand, we + // cannot set it here because it is a counter. + deleted_display_math = isDeleted(i); + } + } + Change const & change = runparams.inDeletedInset ? runparams.changeOfDeletedInset : lookupChange(i); @@ -2402,7 +2425,6 @@ void Paragraph::latex(BufferParams const & bparams, } basefont = getLayoutFont(bparams, outerfont); running_font = basefont; - column += Changes::latexMarkChange(os, bparams, runningChange, change, runparams); runningChange = change; @@ -2464,6 +2486,19 @@ void Paragraph::latex(BufferParams const & bparams, char_type const c = d->text_[i]; + // A display math inset inside an ulem command will be output + // as a box of width \columnwidth, so we have to either disable + // indentation if the inset starts a paragraph, or start a new + // line to accommodate such box. This has to be done before + // writing any font changing commands. + if (runparams.inDisplayMath && !deleted_display_math + && runparams.inulemcmd) { + if (os.afterParbreak()) + os << "\\noindent"; + else + os << "\\\\\n"; + } + // Do we need to change font? if ((font != running_font || font.language() != running_font.language()) && @@ -2473,6 +2508,15 @@ void Paragraph::latex(BufferParams const & bparams, column += font.latexWriteStartChanges(ods, bparams, runparams, basefont, last_font); + // Check again for display math in ulem commands as a + // font change may also occur just before a math inset. + if (runparams.inDisplayMath && !deleted_display_math + && runparams.inulemcmd) { + if (os.afterParbreak()) + os << "\\noindent"; + else + os << "\\\\\n"; + } running_font = font; open_font = true; docstring fontchange = ods.str(); @@ -2524,12 +2568,12 @@ void Paragraph::latex(BufferParams const & bparams, basefont, outerfont, open_font, runningChange, style, i, column); } - } else { - if (i >= start_pos && (end_pos == -1 || i < end_pos)) { - try { - d->latexSpecialChar(os, bparams, rp, running_font, runningChange, - style, i, end_pos, column); - } catch (EncodingException & e) { + } else if (i >= start_pos && (end_pos == -1 || i < end_pos)) { + try { + d->latexSpecialChar(os, bparams, rp, + running_font, runningChange, + style, i, end_pos, column); + } catch (EncodingException & e) { if (runparams.dryrun) { os << "<" << _("LyX Warning: ") << _("uncodable character") << " '"; @@ -2543,11 +2587,15 @@ void Paragraph::latex(BufferParams const & bparams, } } } - } // Set the encoding to that returned from latexSpecialChar (see // comment for encoding member in OutputParams.h) runparams.encoding = rp.encoding; + + // Also carry on the info on a closed ulem command for insets + // such as Note that do not produce any output, so that no + // command is ever executed but its opening was recorded. + runparams.inulemcmd = rp.inulemcmd; } // If we have an open font definition, we have to close it diff --git a/src/mathed/InsetMathHull.cpp b/src/mathed/InsetMathHull.cpp index 349badbad3..cd069c3da5 100644 --- a/src/mathed/InsetMathHull.cpp +++ b/src/mathed/InsetMathHull.cpp @@ -118,6 +118,37 @@ namespace { } + // writes a preamble for underlined or struck out math display + void writeMathdisplayPreamble(WriteStream & os) + { + if (os.strikeoutMath()) { + if (os.ulemCmd() == WriteStream::UNDERLINE) + os << "\\raisebox{-\\belowdisplayshortskip}{" + "\\lyxmathsout{\\parbox[b]{\\columnwidth}{"; + else + os << "\\lyxmathsout{\\parbox{\\columnwidth}{"; + } else if (os.ulemCmd() == WriteStream::UNDERLINE) + os << "\\raisebox{-\\belowdisplayshortskip}{" + "\\parbox[b]{\\columnwidth}{"; + else if (os.ulemCmd() == WriteStream::STRIKEOUT) + os << "\\parbox{\\columnwidth}{"; + } + + + // writes a postamble for underlined or struck out math display + void writeMathdisplayPostamble(WriteStream & os) + { + if (os.strikeoutMath()) { + if (os.ulemCmd() == WriteStream::UNDERLINE) + os << "}"; + os << "}}\\\\\n"; + } else if (os.ulemCmd() == WriteStream::UNDERLINE) + os << "}}\\\\\n"; + else if (os.ulemCmd() == WriteStream::STRIKEOUT) + os << "}\\\\\n"; + } + + } // end anon namespace @@ -892,6 +923,29 @@ bool InsetMathHull::ams() const } +bool InsetMathHull::outerDisplay() const +{ + switch (type_) { + case hullEquation: + case hullEqnArray: + case hullAlign: + case hullFlAlign: + case hullGather: + case hullMultline: + return true; + case hullNone: + case hullSimple: + case hullAlignAt: + case hullXAlignAt: + case hullXXAlignAt: + case hullUnknown: + case hullRegexp: + break; + } + return false; +} + + Inset::DisplayType InsetMathHull::display() const { switch (type_) { @@ -957,6 +1011,9 @@ void InsetMathHull::validate(LaTeXFeatures & features) const + bgcol + string("}{\\ensuremath{\\mathtt{#1}}}}")); features.addPreambleSnippet( string("\\newcommand{\\endregexp}{}")); + } else if (outerDisplay() && features.inDeletedInset() + && !features.mustProvide("ct-dvipost")) { + features.require("ct-tikz-math-sout"); } // Validation is necessary only if not using AMS math. @@ -988,6 +1045,8 @@ void InsetMathHull::header_write(WriteStream & os) const break; case hullSimple: + if (os.ulemCmd()) + os << "\\mbox{"; os << '$'; os.startOuterRow(); if (cell(0).empty()) @@ -995,6 +1054,7 @@ void InsetMathHull::header_write(WriteStream & os) const break; case hullEquation: + writeMathdisplayPreamble(os); os << "\n"; os.startOuterRow(); if (n) @@ -1008,6 +1068,7 @@ void InsetMathHull::header_write(WriteStream & os) const case hullFlAlign: case hullGather: case hullMultline: + writeMathdisplayPreamble(os); os << "\n"; os.startOuterRow(); os << "\\begin{" << hullName(type_) << star(n) << "}\n"; @@ -1052,6 +1113,8 @@ void InsetMathHull::footer_write(WriteStream & os) const case hullSimple: os << '$'; + if (os.ulemCmd()) + os << "}"; break; case hullEquation: @@ -1061,15 +1124,22 @@ void InsetMathHull::footer_write(WriteStream & os) const os << "\\end{equation" << star(n) << "}\n"; else os << "\\]\n"; + writeMathdisplayPostamble(os); break; case hullEqnArray: case hullAlign: case hullFlAlign: - case hullAlignAt: - case hullXAlignAt: case hullGather: case hullMultline: + os << "\n"; + os.startOuterRow(); + os << "\\end{" << hullName(type_) << star(n) << "}\n"; + writeMathdisplayPostamble(os); + break; + + case hullAlignAt: + case hullXAlignAt: os << "\n"; os.startOuterRow(); os << "\\end{" << hullName(type_) << star(n) << "}\n"; diff --git a/src/mathed/InsetMathHull.h b/src/mathed/InsetMathHull.h index c12fcc7593..408130757e 100644 --- a/src/mathed/InsetMathHull.h +++ b/src/mathed/InsetMathHull.h @@ -86,6 +86,8 @@ public: /// bool ams() const; /// + bool outerDisplay() const; + /// void validate(LaTeXFeatures & features) const; /// identifies HullInset InsetMathHull const * asHullInset() const { return this; } diff --git a/src/mathed/InsetMathNest.cpp b/src/mathed/InsetMathNest.cpp index 493f529d1e..6f32364964 100644 --- a/src/mathed/InsetMathNest.cpp +++ b/src/mathed/InsetMathNest.cpp @@ -48,6 +48,7 @@ #include "Encoding.h" #include "FuncRequest.h" #include "FuncStatus.h" +#include "LaTeXFeatures.h" #include "LyX.h" #include "LyXRC.h" #include "OutputParams.h" @@ -406,6 +407,18 @@ void InsetMathNest::latex(otexstream & os, OutputParams const & runparams) const WriteStream wi(os, runparams.moving_arg, true, runparams.dryrun ? WriteStream::wsDryrun : WriteStream::wsDefault, runparams.encoding); + wi.strikeoutMath(runparams.inDeletedInset + && (!LaTeXFeatures::isAvailable("dvipost") + || (runparams.flavor != OutputParams::LATEX + && runparams.flavor != OutputParams::DVILUATEX))); + if (runparams.inulemcmd) { + wi.ulemCmd(WriteStream::UNDERLINE); + if (runparams.local_font) { + FontInfo f = runparams.local_font->fontInfo(); + if (f.strikeout() == FONT_ON) + wi.ulemCmd(WriteStream::STRIKEOUT); + } + } wi.canBreakLine(os.canBreakLine()); if (runparams.lastid != -1) { wi.pushRowEntry(os.texrow().textEntry(runparams.lastid, diff --git a/src/mathed/MathStream.cpp b/src/mathed/MathStream.cpp index ab2dcc7435..7ea6ab75f8 100644 --- a/src/mathed/MathStream.cpp +++ b/src/mathed/MathStream.cpp @@ -127,7 +127,7 @@ WriteStream::WriteStream(otexrowstream & os, bool fragile, bool latex, : os_(os), fragile_(fragile), firstitem_(false), latex_(latex), output_(output), pendingspace_(false), pendingbrace_(false), textmode_(false), locked_(0), ascii_(0), canbreakline_(true), - line_(0), encoding_(encoding) + mathsout_(false), ulemcmd_(NONE), line_(0), encoding_(encoding) {} diff --git a/src/mathed/MathStream.h b/src/mathed/MathStream.h index f9a20112c5..b2a7992f3d 100644 --- a/src/mathed/MathStream.h +++ b/src/mathed/MathStream.h @@ -40,6 +40,12 @@ public: wsPreview }; /// + enum UlemCmdType { + NONE, + UNDERLINE, + STRIKEOUT + }; + /// WriteStream(otexrowstream & os, bool fragile, bool latex, OutputType output, Encoding const * encoding = 0); /// @@ -66,6 +72,14 @@ public: void canBreakLine(bool breakline) { canbreakline_ = breakline; } /// tell whether we can write an immediately following newline char bool canBreakLine() const { return canbreakline_; } + /// record whether we have to take care for striking out display math + void strikeoutMath(bool mathsout) { mathsout_ = mathsout; } + /// tell whether we have to take care for striking out display math + bool strikeoutMath() const { return mathsout_; } + /// record which ulem command type we are inside + void ulemCmd(UlemCmdType ulemcmd) { ulemcmd_ = ulemcmd; } + /// tell which ulem command type we are inside + UlemCmdType ulemCmd() const { return ulemcmd_; } /// writes space if next thing is isalpha() void pendingSpace(bool how); /// writes space if next thing is isalpha() @@ -120,6 +134,10 @@ private: bool ascii_; /// are we allowed to output an immediately following newline? bool canbreakline_; + /// should we take care for striking out display math? + bool mathsout_; + /// what ulem command are we inside (none, underline, strikeout)? + UlemCmdType ulemcmd_; /// int line_; /// diff --git a/status.22x b/status.22x index bf526c837f..b9aed110db 100644 --- a/status.22x +++ b/status.22x @@ -73,6 +73,9 @@ What's new - Fix LaTeX output of fixed-width cells with decimal separator (bug 9568). +- Fix strike out of deleted display math with track-changes and pdf + output (bug 9678). + - Do not hardcode required packages for Note inset. - Make *-lyxformat-* backup files use .lyx~ extension.