From 5f6c681b76b7137107be20b52fb3200883a4faa9 Mon Sep 17 00:00:00 2001 From: Jean-Marc Lasgouttes Date: Sat, 15 Jul 2017 17:23:22 +0200 Subject: [PATCH 001/121] Handle properly top/bottom of inset with mac-like cursor movement The correct behavior is to go to position 0 going up from first row, and to end of row when going down on last row. The targetx value of the cursor is not updated, which makes cursor movement more natural. Fixes bug #10701. (cherry picked from commit 34285cc6830b061c18998bff8385092a311170a8) --- src/Text3.cpp | 12 +++++++++ status.23x | 68 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+) create mode 100644 status.23x diff --git a/src/Text3.cpp b/src/Text3.cpp index 36739a8e1e..adeb80b88f 100644 --- a/src/Text3.cpp +++ b/src/Text3.cpp @@ -860,6 +860,18 @@ void Text::dispatch(Cursor & cur, FuncRequest & cmd) cur.upDownInText(up, needsUpdate); needsUpdate |= cur.beforeDispatchCursor().inMathed(); } else { + pos_type newpos = up ? 0 : cur.lastpos(); + if (lyxrc.mac_like_cursor_movement && cur.pos() != newpos) { + needsUpdate |= cur.selHandle(select); + // we do not reset the targetx of the cursor + cur.pos() = newpos; + needsUpdate |= bv->checkDepm(cur, bv->cursor()); + cur.updateTextTargetOffset(); + if (needsUpdate) + cur.forceBufferUpdate(); + break; + } + // if the cursor cannot be moved up or down do not remove // the selection right now, but wait for the next dispatch. if (select) diff --git a/status.23x b/status.23x new file mode 100644 index 0000000000..30eff6cbc0 --- /dev/null +++ b/status.23x @@ -0,0 +1,68 @@ +-*- text -*- + +This file describes what has been done in the preparation of LyX 2.3.2. +All comments are welcome. + +We try to group things by topic and in decreasing order of importance. +Please feel free to re-arrange if that seems like a good idea. + + +What's new +========== + +** Updates: +*********** + +* DOCUMENT INPUT/OUTPUT + + + +* TEX2LYX IMPROVEMENTS + + + +* USER INTERFACE + +- Handle properly top/bottom of inset with mac-like cursor movement + (bug 10701). + +* DOCUMENTATION AND LOCALIZATION + + + +* BUILD/INSTALLATION + + +** Bug fixes: +************* + +* DOCUMENT INPUT/OUTPUT + + +* LYX2LYX + + +* USER INTERFACE + + + +* INTERNALS + + + +* DOCUMENTATION AND LOCALIZATION + + +* LYXHTML + + + +* TEX2LYX + + + +* ADVANCED FIND AND REPLACE + + +* BUILD/INSTALLATION + From 51e80361b2880a9f2e3b9d888891ffd9498713a6 Mon Sep 17 00:00:00 2001 From: Jean-Marc Lasgouttes Date: Wed, 29 Nov 2017 14:10:33 +0100 Subject: [PATCH 002/121] Better handling of multiple buffers in UndoGroupHelper It may happen that the buffers are visited in order buffer1, buffer2, buffer1. In this case, we want to have only one undo group in buffer1. The solution is to replace buffer_ with a set. A use case among others is InsetLabel::updateReferences. (cherry picked from commit cc7364dfc50c399e99158fd9efe2f3eb0e6f4570) --- src/Undo.cpp | 38 ++++++++++++++++++++++++-------------- src/Undo.h | 13 ++++--------- 2 files changed, 28 insertions(+), 23 deletions(-) diff --git a/src/Undo.cpp b/src/Undo.cpp index f7ee48205f..49f636cbb9 100644 --- a/src/Undo.cpp +++ b/src/Undo.cpp @@ -40,6 +40,7 @@ #include #include +#include using namespace std; using namespace lyx::support; @@ -645,22 +646,31 @@ void Undo::recordUndoFullBuffer(CursorData const & cur) /// UndoGroupHelper class stuff -/** FIXME: handle restarted groups - * It may happen that the buffers are visited in order buffer1, - * buffer2, buffer1. In this case, we want to have only one undo group - * in buffer1. One solution is to replace buffer_ with a set, - * but I am not sure yet how to do it. A use case is - * InsetLabel::updateReferences. - */ +class UndoGroupHelper::Impl { + friend class UndoGroupHelper; + set buffers_; +}; + + +UndoGroupHelper::UndoGroupHelper(Buffer * buf) : d(new UndoGroupHelper::Impl) +{ + resetBuffer(buf); +} + + +UndoGroupHelper::~UndoGroupHelper() +{ + for (Buffer * buf : d->buffers_) + buf->undo().endUndoGroup(); + delete d; +} + void UndoGroupHelper::resetBuffer(Buffer * buf) { - if (buf == buffer_) - return; - if (buffer_) - buffer_->undo().endUndoGroup(); - buffer_ = buf; - if (buffer_) - buffer_->undo().beginUndoGroup(); + if (buf && d->buffers_.count(buf) == 0) { + d->buffers_.insert(buf); + buf->undo().beginUndoGroup(); + } } diff --git a/src/Undo.h b/src/Undo.h index 70897bfa28..b1908a25b3 100644 --- a/src/Undo.h +++ b/src/Undo.h @@ -135,15 +135,9 @@ private: */ class UndoGroupHelper { public: - UndoGroupHelper(Buffer * buf = 0) : buffer_(0) - { - resetBuffer(buf); - } + UndoGroupHelper(Buffer * buf = 0); - ~UndoGroupHelper() - { - resetBuffer(0); - } + ~UndoGroupHelper(); /** Close the current undo group if necessary and create a new one * for buffer \c buf. @@ -151,7 +145,8 @@ public: void resetBuffer(Buffer * buf); private: - Buffer * buffer_; + class Impl; + Impl * const d; }; From 1dc134fb60806ee0d27371049392ab72223b6cd0 Mon Sep 17 00:00:00 2001 From: Jean-Marc Lasgouttes Date: Wed, 13 Dec 2017 11:10:49 +0100 Subject: [PATCH 003/121] Improve UndoGroupHelper and use it more Now the helper class contains logic that checks whether buffer are known before closing them. This avoids potential crashes. Use it in different places to siplify code. It is not clear at this point whether it should be used everywhere. Followup to bug #10847. (cherry picked from commit cd9e42dc3529980257d2b0fe6fd623fd2b99a1e6) --- src/Buffer.cpp | 4 ++-- src/Undo.cpp | 4 +++- src/frontends/qt4/GuiApplication.cpp | 15 ++++----------- src/frontends/qt4/GuiDocument.cpp | 7 ++----- src/insets/InsetGraphics.cpp | 4 ++-- src/insets/InsetLabel.cpp | 4 ++-- status.23x | 1 + 7 files changed, 16 insertions(+), 23 deletions(-) diff --git a/src/Buffer.cpp b/src/Buffer.cpp index ffe522e0f9..ca3c049b4d 100644 --- a/src/Buffer.cpp +++ b/src/Buffer.cpp @@ -2650,7 +2650,8 @@ void Buffer::dispatch(FuncRequest const & func, DispatchResult & dr) string const argument = to_utf8(func.argument()); // We'll set this back to false if need be. bool dispatched = true; - undo().beginUndoGroup(); + // This handles undo groups automagically + UndoGroupHelper ugh(this); switch (func.action()) { case LFUN_BUFFER_TOGGLE_READ_ONLY: @@ -2902,7 +2903,6 @@ void Buffer::dispatch(FuncRequest const & func, DispatchResult & dr) break; } dr.dispatched(dispatched); - undo().endUndoGroup(); } diff --git a/src/Undo.cpp b/src/Undo.cpp index 49f636cbb9..01394bc27f 100644 --- a/src/Undo.cpp +++ b/src/Undo.cpp @@ -18,6 +18,7 @@ #include "Undo.h" #include "Buffer.h" +#include "BufferList.h" #include "BufferParams.h" #include "buffer_funcs.h" #include "Cursor.h" @@ -661,7 +662,8 @@ UndoGroupHelper::UndoGroupHelper(Buffer * buf) : d(new UndoGroupHelper::Impl) UndoGroupHelper::~UndoGroupHelper() { for (Buffer * buf : d->buffers_) - buf->undo().endUndoGroup(); + if (theBufferList().isLoaded(buf) || theBufferList().isInternal(buf)) + buf->undo().endUndoGroup(); delete d; } diff --git a/src/frontends/qt4/GuiApplication.cpp b/src/frontends/qt4/GuiApplication.cpp index 35b639c9ac..0ce130eb69 100644 --- a/src/frontends/qt4/GuiApplication.cpp +++ b/src/frontends/qt4/GuiApplication.cpp @@ -1395,9 +1395,9 @@ DispatchResult const & GuiApplication::dispatch(FuncRequest const & cmd) if (current_view_ && current_view_->currentBufferView()) { current_view_->currentBufferView()->cursor().saveBeforeDispatchPosXY(); buffer = ¤t_view_->currentBufferView()->buffer(); - if (buffer) - buffer->undo().beginUndoGroup(); } + // This handles undo groups automagically + UndoGroupHelper ugh(buffer); DispatchResult dr; // redraw the screen at the end (first of the two drawing steps). @@ -1406,10 +1406,6 @@ DispatchResult const & GuiApplication::dispatch(FuncRequest const & cmd) dispatch(cmd, dr); updateCurrentView(cmd, dr); - // the buffer may have been closed by one action - if (theBufferList().isLoaded(buffer) || theBufferList().isInternal(buffer)) - buffer->undo().endUndoGroup(); - d->dispatch_result_ = dr; return d->dispatch_result_; } @@ -1873,8 +1869,8 @@ void GuiApplication::dispatch(FuncRequest const & cmd, DispatchResult & dr) // FIXME: this LFUN should also work without any view. Buffer * buffer = (current_view_ && current_view_->documentBufferView()) ? &(current_view_->documentBufferView()->buffer()) : 0; - if (buffer) - buffer->undo().beginUndoGroup(); + // This handles undo groups automagically + UndoGroupHelper ugh(buffer); while (!arg.empty()) { string first; arg = split(arg, first, ';'); @@ -1882,9 +1878,6 @@ void GuiApplication::dispatch(FuncRequest const & cmd, DispatchResult & dr) func.setOrigin(cmd.origin()); dispatch(func); } - // the buffer may have been closed by one action - if (theBufferList().isLoaded(buffer) || theBufferList().isInternal(buffer)) - buffer->undo().endUndoGroup(); break; } diff --git a/src/frontends/qt4/GuiDocument.cpp b/src/frontends/qt4/GuiDocument.cpp index 09203781f0..560883ec6a 100644 --- a/src/frontends/qt4/GuiDocument.cpp +++ b/src/frontends/qt4/GuiDocument.cpp @@ -4327,7 +4327,8 @@ void GuiDocument::dispatchParams() // We need a non-const buffer object. Buffer & buf = const_cast(bufferview())->buffer(); // There may be several undo records; group them (bug #8998) - buf.undo().beginUndoGroup(); + // This handles undo groups automagically + UndoGroupHelper ugh(&buf); // This must come first so that a language change is correctly noticed setLanguage(); @@ -4394,10 +4395,6 @@ void GuiDocument::dispatchParams() // If we used an LFUN, we would not need these two lines: BufferView * bv = const_cast(bufferview()); bv->processUpdateFlags(Update::Force | Update::FitCursor); - - // Don't forget to close the group. Note that it is important - // to check that there is no early return in the method. - buf.undo().endUndoGroup(); } diff --git a/src/insets/InsetGraphics.cpp b/src/insets/InsetGraphics.cpp index 94182a7326..a46d3fbc64 100644 --- a/src/insets/InsetGraphics.cpp +++ b/src/insets/InsetGraphics.cpp @@ -1150,7 +1150,8 @@ void unifyGraphicsGroups(Buffer & b, string const & argument) InsetGraphicsParams params; InsetGraphics::string2params(argument, b, params); - b.undo().beginUndoGroup(); + // This handles undo groups automagically + UndoGroupHelper ugh(&b); Inset & inset = b.inset(); InsetIterator it = inset_iterator_begin(inset); InsetIterator const end = inset_iterator_end(inset); @@ -1165,7 +1166,6 @@ void unifyGraphicsGroups(Buffer & b, string const & argument) } } } - b.undo().endUndoGroup(); } diff --git a/src/insets/InsetLabel.cpp b/src/insets/InsetLabel.cpp index 789a774ac6..7f3651f3a3 100644 --- a/src/insets/InsetLabel.cpp +++ b/src/insets/InsetLabel.cpp @@ -97,12 +97,12 @@ void InsetLabel::updateLabelAndRefs(docstring const & new_label, if (label == old_label) return; - buffer().undo().beginUndoGroup(); + // This handles undo groups automagically + UndoGroupHelper ugh(&buffer()); if (cursor) cursor->recordUndo(); setParam("name", label); updateReferences(old_label, label); - buffer().undo().endUndoGroup(); } diff --git a/status.23x b/status.23x index 30eff6cbc0..7f5727714b 100644 --- a/status.23x +++ b/status.23x @@ -44,6 +44,7 @@ What's new * USER INTERFACE +- Improve Undo for operations that act on several buffers (bug 10823). * INTERNALS From 2e1863b704fe5260dcf40c19c8679756c0f1a409 Mon Sep 17 00:00:00 2001 From: Jean-Marc Lasgouttes Date: Mon, 4 Dec 2017 10:44:49 +0100 Subject: [PATCH 004/121] Implement display of roots more faithfully This is a follow-up to 758de957. - unify the metrics and drawing of \sqrt and \root using helper functions mathed_root_metrics and mathed_draw_root. - compute the vertical spacing above the nucleus of the root following rule 11 of the TeXbook. In particular, it is different in inline and display style. - draw the root glyph without hard-coded pixel values. Make the line width depend on the zoom. more work is needed to implement properly rule 11: - Ideally, we should use sqrt glyphs from the math fonts. Note that then we would get rule thickness from there. - The positioning of the root MathData is arbitrary. It should follow the definition of \root...\of... in The Texbook in Apprendix B page 360. Fixes bug #10814. (cherry picked from commit 16af6e7c5067fff0873587af30833e0b8006c435) (cherry picked from commit 6cb6f78ae9050140c75af089350cd7cccc0b58e1) --- src/mathed/InsetMathRoot.cpp | 117 ++++++++++++++++++++++++----------- src/mathed/InsetMathRoot.h | 5 ++ src/mathed/InsetMathSqrt.cpp | 25 +------- src/mathed/MathSupport.cpp | 6 ++ src/mathed/MathSupport.h | 2 + status.23x | 2 + 6 files changed, 99 insertions(+), 58 deletions(-) diff --git a/src/mathed/InsetMathRoot.cpp b/src/mathed/InsetMathRoot.cpp index 8b86c5965b..348b4e9cab 100644 --- a/src/mathed/InsetMathRoot.cpp +++ b/src/mathed/InsetMathRoot.cpp @@ -13,7 +13,6 @@ #include "InsetMathRoot.h" -#include "MathData.h" #include "MathStream.h" #include "MathSupport.h" @@ -28,6 +27,7 @@ using namespace std; namespace lyx { +using namespace frontend; InsetMathRoot::InsetMathRoot(Buffer * buf) : InsetMathNest(buf, 2) @@ -40,56 +40,101 @@ Inset * InsetMathRoot::clone() const } -void InsetMathRoot::metrics(MetricsInfo & mi, Dimension & dim) const +void mathed_root_metrics(MetricsInfo & mi, MathData const & nucleus, + MathData const * root, Dimension & dim) { Changer dummy = mi.base.changeEnsureMath(); - Dimension dim0; - { + Dimension dimr; + if (root) { Changer script = mi.base.font.changeStyle(LM_ST_SCRIPTSCRIPT); - cell(0).metrics(mi, dim0); + root->metrics(mi, dimr); // make sure that the dim is high enough for any character Dimension fontDim; math_font_max_dim(mi.base.font, fontDim.asc, fontDim.des); - dim0 += fontDim; + dimr += fontDim; } - Dimension dim1; - cell(1).metrics(mi, dim1); + Dimension dimn; + nucleus.metrics(mi, dimn); // make sure that the dim is high enough for any character - Dimension fontDim; - math_font_max_dim(mi.base.font, fontDim.asc, fontDim.des); - dim1 += fontDim; + // Dimension fontDim; + // math_font_max_dim(mi.base.font, fontDim.asc, fontDim.des); + // dimn += fontDim; - dim.asc = max(dim0.ascent() + 5, dim1.ascent()) + 1; - dim.des = max(dim0.descent() - 5, dim1.descent()); - dim.wid = dim0.width() + dim1.width() + 4; + // Some room for the decoration + // The width of left decoration was 9 pixels with a 10em font + int const w = 9 * mathed_font_em(mi.base.font) / 10; + /* See rule 11 in Appendix G of Rhe TeXbook for the computation of the spacing + * above nucleus. + * FIXME more work is needed to implement properly rule 11. + * * Ideally, we should use sqrt glyphs from the math fonts. Note + that then we would get rule thickness from there. + * * The positioning of the root MathData is arbitrary. It should + * follow the definition of \root...\of... in The Texbook in + * Apprendix B page 360. + * + */ + int const t = mi.base.solidLineThickness(); + int const x_height = mathed_font_x_height(mi.base.font); + int const phi = (mi.base.font.style() == LM_ST_DISPLAY) ? x_height : t; + // first part is the spacing, second part is the line width + // itself, and last one is the spacing above. + int const space_above = (t + phi / 4) + t + t; + int const a = dimn.ascent(); + int const d = dimn.descent(); + // Not sure what the 1 stands for, it is needed to have some spacing at small sizes. + dim.asc = max(dimr.ascent() + (d - a) / 2, a + space_above) + 1; + dim.des = max(dimr.descent() - (d - a) / 2, d); + dim.wid = max(dimr.width() + 3 * w / 8, w) + dimn.width(); +} + + +void InsetMathRoot::metrics(MetricsInfo & mi, Dimension & dim) const +{ + mathed_root_metrics(mi, cell(1), &cell(0), dim); +} + + +void mathed_draw_root(PainterInfo & pi, int x, int y, MathData const & nucleus, + MathData const * root, Dimension const & dim) +{ + Changer dummy = pi.base.changeEnsureMath(); + // The width of left decoration was 9 pixels with a 10em font + int const w = 9 * mathed_font_em(pi.base.font) / 10; + // the height of the hook was 5 with a 10em font + int const h = 5 * mathed_font_em(pi.base.font) / 10; + int const a = dim.ascent(); + int const d = dim.descent(); + int const t = pi.base.solidLineThickness(); + Dimension const dimn = nucleus.dimension(*pi.base.bv); + // the width of the left part of the root + int const wl = dim.width() - dimn.width(); + // the "exponent" + if (root) { + Changer script = pi.base.font.changeStyle(LM_ST_SCRIPTSCRIPT); + Dimension const dimr = root->dimension(*pi.base.bv); + int const root_offset = wl - 3 * w / 8 - dimr.width(); + root->draw(pi, x + root_offset, y + (d - a)/2); + } + // the "base" + nucleus.draw(pi, x + wl, y); + int xp[4]; + int yp[4]; + pi.pain.line(x + dim.width(), y - a + 2 * t, + x + wl, y - a + 2 * t, pi.base.font.color(), + Painter::line_solid, t); + xp[0] = x + wl; yp[0] = y - a + 2 * t + 1; + xp[1] = x + wl - w / 2; yp[1] = y + d; + xp[2] = x + wl - w + h / 4; yp[2] = y + d - h; + xp[3] = x + wl - w; yp[3] = y + d - h + h / 4; + pi.pain.lines(xp, yp, 4, pi.base.font.color(), + Painter::fill_none, Painter::line_solid, t); } void InsetMathRoot::draw(PainterInfo & pi, int x, int y) const { - Changer dummy = pi.base.changeEnsureMath(); - Dimension const dim = dimension(*pi.base.bv); - int const a = dim.ascent(); - int const d = dim.descent(); - Dimension const & dim0 = cell(0).dimension(*pi.base.bv); - int const w = dim0.width(); - // the "exponent" - { - Changer script = pi.base.font.changeStyle(LM_ST_SCRIPTSCRIPT); - cell(0).draw(pi, x, y + (d - a)/2 - dim0.descent()); - } - // the "base" - cell(1).draw(pi, x + w + 4, y); - int xp[4]; - int yp[4]; - pi.pain.line(x + dim.width(), y - a + 1, - x + w + 4, y - a + 1, pi.base.font.color()); - xp[0] = x + w + 4; yp[0] = y - a + 1; - xp[1] = x + w; yp[1] = y + d; - xp[2] = x + w - 2; yp[2] = y + (d - a)/2 + 2; - xp[3] = x + w - 5; yp[3] = y + (d - a)/2 + 4; - pi.pain.lines(xp, yp, 4, pi.base.font.color()); + mathed_draw_root(pi, x, y, cell(1), &cell(0), dimension(*pi.base.bv)); } diff --git a/src/mathed/InsetMathRoot.h b/src/mathed/InsetMathRoot.h index 18bacbbf18..923e9a5f61 100644 --- a/src/mathed/InsetMathRoot.h +++ b/src/mathed/InsetMathRoot.h @@ -54,6 +54,11 @@ private: virtual Inset * clone() const; }; +void mathed_root_metrics(MetricsInfo & mi, MathData const & nucleus, + MathData const * root, Dimension & dim); + +void mathed_draw_root(PainterInfo & pi, int x, int y, MathData const & nucleus, + MathData const * root, Dimension const & dim); } // namespace lyx diff --git a/src/mathed/InsetMathSqrt.cpp b/src/mathed/InsetMathSqrt.cpp index a7385cc708..7416c332f1 100644 --- a/src/mathed/InsetMathSqrt.cpp +++ b/src/mathed/InsetMathSqrt.cpp @@ -12,6 +12,7 @@ #include "InsetMathSqrt.h" +#include "InsetMathRoot.h" #include "MathData.h" #include "MathStream.h" #include "MathSupport.h" @@ -38,33 +39,13 @@ Inset * InsetMathSqrt::clone() const void InsetMathSqrt::metrics(MetricsInfo & mi, Dimension & dim) const { - Changer dummy = mi.base.changeEnsureMath(); - cell(0).metrics(mi, dim); - // make sure that the dim is high enough for any character - Dimension fontDim; - math_font_max_dim(mi.base.font, fontDim.asc, fontDim.des); - dim += fontDim; - // Some room for the decoration - dim.asc += 1; - dim.wid += 7; + mathed_root_metrics(mi, cell(0), nullptr, dim); } void InsetMathSqrt::draw(PainterInfo & pi, int x, int y) const { - Changer dummy = pi.base.changeEnsureMath(); - cell(0).draw(pi, x + 9, y); - Dimension const dim = dimension(*pi.base.bv); - int const a = dim.ascent(); - int const d = dim.descent(); - int xp[3]; - int yp[3]; - pi.pain.line(x + dim.width(), y - a + 1, - x + 7, y - a + 1, pi.base.font.color()); - xp[0] = x + 7; yp[0] = y - a + 1; - xp[1] = x + 4; yp[1] = y + d - 1; - xp[2] = x; yp[2] = y + (d - a)/2; - pi.pain.lines(xp, yp, 3, pi.base.font.color()); + mathed_draw_root(pi, x, y, cell(0), nullptr, dimension(*pi.base.bv)); } diff --git a/src/mathed/MathSupport.cpp b/src/mathed/MathSupport.cpp index bb6a21c74d..57eca6ee31 100644 --- a/src/mathed/MathSupport.cpp +++ b/src/mathed/MathSupport.cpp @@ -513,6 +513,12 @@ int mathed_font_em(FontInfo const & font) return theFontMetrics(font).em(); } + +int mathed_font_x_height(FontInfo const & font) +{ + return theFontMetrics(font).ascent('x'); +} + /* The math units. Quoting TeX by Topic, p.205: * * Spacing around mathematical objects is measured in mu units. A mu diff --git a/src/mathed/MathSupport.h b/src/mathed/MathSupport.h index 3e5f67d5cf..d9301453dd 100644 --- a/src/mathed/MathSupport.h +++ b/src/mathed/MathSupport.h @@ -32,6 +32,8 @@ class LaTeXFeatures; int mathed_font_em(FontInfo const &); +int mathed_font_x_height(FontInfo const & font); + int mathed_mu(FontInfo const & font, double mu); int mathed_thinmuskip(FontInfo const & font); diff --git a/status.23x b/status.23x index 7f5727714b..d1e5abf8ea 100644 --- a/status.23x +++ b/status.23x @@ -46,6 +46,8 @@ What's new - Improve Undo for operations that act on several buffers (bug 10823). +- Improve rendering of square roots in math editor (bug 10814). + * INTERNALS From 08f6354bc9c4d4b2630b4e6f10fdf82d4de6959a Mon Sep 17 00:00:00 2001 From: Pavel Sanda Date: Fri, 2 Feb 2018 23:42:56 +0100 Subject: [PATCH 005/121] Add LFUN_DOC_ANONYMIZE, quick fix for #7259. Backport from master. --- src/BufferView.cpp | 9 +++++++++ src/FuncCode.h | 3 +++ src/LyXAction.cpp | 10 ++++++++++ 3 files changed, 22 insertions(+) diff --git a/src/BufferView.cpp b/src/BufferView.cpp index e141f34c7e..2d4e06dfeb 100644 --- a/src/BufferView.cpp +++ b/src/BufferView.cpp @@ -1112,6 +1112,7 @@ bool BufferView::getStatus(FuncRequest const & cmd, FuncStatus & flag) case LFUN_WORD_FIND_FORWARD: case LFUN_WORD_FIND_BACKWARD: case LFUN_WORD_REPLACE: + case LFUN_DOC_ANONYMIZE: case LFUN_MARK_OFF: case LFUN_MARK_ON: case LFUN_MARK_TOGGLE: @@ -1575,6 +1576,14 @@ void BufferView::dispatch(FuncRequest const & cmd, DispatchResult & dr) break; } + case LFUN_DOC_ANONYMIZE: { + for(char c = '0'; c <='Z'; c++) { + odocstringstream ss; + ss << "a\n" << c << "\n0 0 1 1 0"; + lyx::dispatch(FuncRequest(LFUN_WORD_REPLACE, ss.str())); + } + } + case LFUN_WORD_FINDADV: { FindAndReplaceOptions opt; istringstream iss(to_utf8(cmd.argument())); diff --git a/src/FuncCode.h b/src/FuncCode.h index 92d5e35268..b8ca134325 100644 --- a/src/FuncCode.h +++ b/src/FuncCode.h @@ -474,6 +474,9 @@ enum FuncCode LFUN_TOOLBAR_MOVABLE, // daniel, 20160712 LFUN_FONT_CROSSOUT, // uwestoehr 20170404 LFUN_DEVEL_MODE_TOGGLE, // lasgouttes 20170723 + //370 + LFUN_EXPORT_CANCEL, // rgh, 20171227 + LFUN_DOC_ANONYMIZE, // sanda, 20180201 LFUN_LASTACTION // end of the table }; diff --git a/src/LyXAction.cpp b/src/LyXAction.cpp index 7cd103b1c4..2a07aaa03a 100644 --- a/src/LyXAction.cpp +++ b/src/LyXAction.cpp @@ -4209,6 +4209,16 @@ void LyXAction::init() */ { LFUN_WORD_REPLACE, "word-replace", Noop, Edit }, +/*! + * \var lyx::FuncCode lyx::LFUN_DOC_ANONYMIZE + * \li Action: For debug purposes only. Convert all [a-zA-Z0-1] characters to + single character. Useful when submitting docs to list or bugzilla. + * \li Syntax: doc-anonymize + * \li Origin: sanda, Feb 1 2018 + * \endvar + */ + { LFUN_DOC_ANONYMIZE, "doc-anonymize", Noop, Edit }, + /*! * \var lyx::FuncCode lyx::LFUN_WORD_RIGHT * \li Action: Moves the cursor to the next beginning of a word "on the right". From 624a6ed91d1daac775e2773cc8b6471cc89567ea Mon Sep 17 00:00:00 2001 From: Pavel Sanda Date: Sat, 3 Feb 2018 22:05:49 +0100 Subject: [PATCH 006/121] LFUN_DOC_ANONYMIZE -> LFUN_BUFFER_ANONYMIZE per JMarc's suggestion. --- src/BufferView.cpp | 4 ++-- src/FuncCode.h | 2 +- src/LyXAction.cpp | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/BufferView.cpp b/src/BufferView.cpp index 2d4e06dfeb..bf7c1ea165 100644 --- a/src/BufferView.cpp +++ b/src/BufferView.cpp @@ -1112,7 +1112,7 @@ bool BufferView::getStatus(FuncRequest const & cmd, FuncStatus & flag) case LFUN_WORD_FIND_FORWARD: case LFUN_WORD_FIND_BACKWARD: case LFUN_WORD_REPLACE: - case LFUN_DOC_ANONYMIZE: + case LFUN_BUFFER_ANONYMIZE: case LFUN_MARK_OFF: case LFUN_MARK_ON: case LFUN_MARK_TOGGLE: @@ -1576,7 +1576,7 @@ void BufferView::dispatch(FuncRequest const & cmd, DispatchResult & dr) break; } - case LFUN_DOC_ANONYMIZE: { + case LFUN_BUFFER_ANONYMIZE: { for(char c = '0'; c <='Z'; c++) { odocstringstream ss; ss << "a\n" << c << "\n0 0 1 1 0"; diff --git a/src/FuncCode.h b/src/FuncCode.h index b8ca134325..4a5983147d 100644 --- a/src/FuncCode.h +++ b/src/FuncCode.h @@ -476,7 +476,7 @@ enum FuncCode LFUN_DEVEL_MODE_TOGGLE, // lasgouttes 20170723 //370 LFUN_EXPORT_CANCEL, // rgh, 20171227 - LFUN_DOC_ANONYMIZE, // sanda, 20180201 + LFUN_BUFFER_ANONYMIZE, // sanda, 20180201 LFUN_LASTACTION // end of the table }; diff --git a/src/LyXAction.cpp b/src/LyXAction.cpp index 2a07aaa03a..dae9b53894 100644 --- a/src/LyXAction.cpp +++ b/src/LyXAction.cpp @@ -4210,14 +4210,14 @@ void LyXAction::init() { LFUN_WORD_REPLACE, "word-replace", Noop, Edit }, /*! - * \var lyx::FuncCode lyx::LFUN_DOC_ANONYMIZE + * \var lyx::FuncCode lyx::LFUN_BUFFER_ANONYMIZE * \li Action: For debug purposes only. Convert all [a-zA-Z0-1] characters to single character. Useful when submitting docs to list or bugzilla. * \li Syntax: doc-anonymize * \li Origin: sanda, Feb 1 2018 * \endvar */ - { LFUN_DOC_ANONYMIZE, "doc-anonymize", Noop, Edit }, + { LFUN_BUFFER_ANONYMIZE, "buffer-anonymize", Noop, Edit }, /*! * \var lyx::FuncCode lyx::LFUN_WORD_RIGHT From 9966f098ea07d1568f8650a1fc3e43a838f2fe82 Mon Sep 17 00:00:00 2001 From: Pavel Sanda Date: Sat, 3 Feb 2018 22:43:00 +0100 Subject: [PATCH 007/121] forgotten glitch --- src/LyXAction.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/LyXAction.cpp b/src/LyXAction.cpp index dae9b53894..33d5100a82 100644 --- a/src/LyXAction.cpp +++ b/src/LyXAction.cpp @@ -4213,7 +4213,7 @@ void LyXAction::init() * \var lyx::FuncCode lyx::LFUN_BUFFER_ANONYMIZE * \li Action: For debug purposes only. Convert all [a-zA-Z0-1] characters to single character. Useful when submitting docs to list or bugzilla. - * \li Syntax: doc-anonymize + * \li Syntax: buffer-anonymize * \li Origin: sanda, Feb 1 2018 * \endvar */ From abdadcceb9368f8b2485dd1f812bf3405674dddc Mon Sep 17 00:00:00 2001 From: Pavel Sanda Date: Thu, 15 Feb 2018 11:56:34 +0100 Subject: [PATCH 008/121] * status.23x --- status.23x | 2 ++ 1 file changed, 2 insertions(+) diff --git a/status.23x b/status.23x index d1e5abf8ea..16ce90b5f8 100644 --- a/status.23x +++ b/status.23x @@ -15,6 +15,8 @@ What's new * DOCUMENT INPUT/OUTPUT +- it possible to anonymize document's content for bug submissions + via buffer-anonymize lfun (bug 7259). * TEX2LYX IMPROVEMENTS From 9a1728c70a0e171111864168d5f3ac9cae1ca2b8 Mon Sep 17 00:00:00 2001 From: Jean-Marc Lasgouttes Date: Thu, 15 Feb 2018 12:07:33 +0100 Subject: [PATCH 009/121] Implement buffer-anonymize more efficiently The work is done now in Paragraph::anonymize(). Move the handling of the lfun to Buffer class. Document the new feature in release notes. (cherry picked from commit 1dba36c7cec6aeec2576e7a99e2967e867076a01) --- lib/RELEASE-NOTES | 4 ++++ src/Buffer.cpp | 18 ++++++++++++++---- src/BufferView.cpp | 9 --------- src/Paragraph.cpp | 9 +++++++++ src/Paragraph.h | 4 ++++ 5 files changed, 31 insertions(+), 13 deletions(-) diff --git a/lib/RELEASE-NOTES b/lib/RELEASE-NOTES index 59325c3bd2..a48968b24d 100644 --- a/lib/RELEASE-NOTES +++ b/lib/RELEASE-NOTES @@ -111,6 +111,10 @@ opened in editable mode. This state used to be hardcoded at compile time. +* buffer-anonymize (2.3.2) + Replace all text n the document by streams of `a'. This is useful + for sharing private documents in a bug report. + * font-crossout Cross out characters. diff --git a/src/Buffer.cpp b/src/Buffer.cpp index ca3c049b4d..1ae48acc8a 100644 --- a/src/Buffer.cpp +++ b/src/Buffer.cpp @@ -2612,15 +2612,16 @@ bool Buffer::getStatus(FuncRequest const & cmd, FuncStatus & flag) flag.setOnOff(params().output_changes); break; - case LFUN_BUFFER_TOGGLE_COMPRESSION: { + case LFUN_BUFFER_TOGGLE_COMPRESSION: flag.setOnOff(params().compressed); break; - } - case LFUN_BUFFER_TOGGLE_OUTPUT_SYNC: { + case LFUN_BUFFER_TOGGLE_OUTPUT_SYNC: flag.setOnOff(params().output_sync); break; - } + + case LFUN_BUFFER_ANONYMIZE: + break; default: return false; @@ -2898,6 +2899,15 @@ void Buffer::dispatch(FuncRequest const & func, DispatchResult & dr) params().output_sync = !params().output_sync; break; + case LFUN_BUFFER_ANONYMIZE: { + undo().recordUndoFullBuffer(CursorData()); + CursorData cur(doc_iterator_begin(this)); + for ( ; cur ; cur.forwardPar()) + cur.paragraph().anonymize(); + dr.forceBufferUpdate(); + break; + } + default: dispatched = false; break; diff --git a/src/BufferView.cpp b/src/BufferView.cpp index bf7c1ea165..e141f34c7e 100644 --- a/src/BufferView.cpp +++ b/src/BufferView.cpp @@ -1112,7 +1112,6 @@ bool BufferView::getStatus(FuncRequest const & cmd, FuncStatus & flag) case LFUN_WORD_FIND_FORWARD: case LFUN_WORD_FIND_BACKWARD: case LFUN_WORD_REPLACE: - case LFUN_BUFFER_ANONYMIZE: case LFUN_MARK_OFF: case LFUN_MARK_ON: case LFUN_MARK_TOGGLE: @@ -1576,14 +1575,6 @@ void BufferView::dispatch(FuncRequest const & cmd, DispatchResult & dr) break; } - case LFUN_BUFFER_ANONYMIZE: { - for(char c = '0'; c <='Z'; c++) { - odocstringstream ss; - ss << "a\n" << c << "\n0 0 1 1 0"; - lyx::dispatch(FuncRequest(LFUN_WORD_REPLACE, ss.str())); - } - } - case LFUN_WORD_FINDADV: { FindAndReplaceOptions opt; istringstream iss(to_utf8(cmd.argument())); diff --git a/src/Paragraph.cpp b/src/Paragraph.cpp index 5c5a728027..c905856e9c 100644 --- a/src/Paragraph.cpp +++ b/src/Paragraph.cpp @@ -4176,6 +4176,15 @@ SpellChecker::Result Paragraph::spellCheck(pos_type & from, pos_type & to, } +void Paragraph::anonymize() +{ + // This is a very crude anonymization for now + for (char_type & c : d->text_) + if (isLetterChar(c) || isNumber(c)) + c = 'a'; +} + + void Paragraph::Private::markMisspelledWords( pos_type const & first, pos_type const & last, SpellChecker::Result result, diff --git a/src/Paragraph.h b/src/Paragraph.h index d462f4c413..0c6c48090f 100644 --- a/src/Paragraph.h +++ b/src/Paragraph.h @@ -505,6 +505,10 @@ public: /// presently used only in the XHTML output routines. std::string magicLabel() const; + /// anonymizes the paragraph contents (but not the paragraphs + /// contained inside it. Does not handle undo. + void anonymize(); + private: /// Expand the counters for the labelstring of \c layout docstring expandParagraphLabel(Layout const &, BufferParams const &, From d222e0f48e17eb838d8320f30f82b4c96b3e496e Mon Sep 17 00:00:00 2001 From: Jean-Marc Lasgouttes Date: Sun, 16 Jul 2017 01:25:03 +0200 Subject: [PATCH 010/121] three-stage drawing: add a nodraw stage Normally the two stages of drawing are 1/ compute metrics of insets/rows/paragraphs/mathrow... 2/ draw the elements and cache their positions Now the three stages are 1/ metrics 2/ nodraw: do not draw the elements, but cache their position 3/ draw the elements (and store again their position; it does not seems to hurt performance). Revive the NullPainter: this replaces the setDrawingEnabled mechanism with a painter that does nothing. The advantage is that updatePosCache (renamed from setPosCache) does not need anymore to be invoked from the frontend. updatePosCache (the nodraw stage) is called at the end of BufferView::updateMetrics. --- src/BufferView.cpp | 27 +++++-- src/BufferView.h | 5 +- src/RowPainter.cpp | 2 +- src/TextMetrics.cpp | 18 ++--- src/frontends/Makefile.am | 1 + src/frontends/NullPainter.h | 109 ++++++++++++++++++++++++++ src/frontends/Painter.h | 11 +-- src/frontends/qt4/GuiPainter.cpp | 26 +----- src/frontends/qt4/GuiPainter.h | 3 + src/frontends/qt4/GuiWorkArea.cpp | 14 ++-- src/mathed/InsetMathMacroTemplate.cpp | 18 ++--- 11 files changed, 160 insertions(+), 74 deletions(-) create mode 100644 src/frontends/NullPainter.h diff --git a/src/BufferView.cpp b/src/BufferView.cpp index e141f34c7e..94e448d1e9 100644 --- a/src/BufferView.cpp +++ b/src/BufferView.cpp @@ -70,6 +70,7 @@ #include "frontends/Application.h" #include "frontends/Delegates.h" #include "frontends/FontMetrics.h" +#include "frontends/NullPainter.h" #include "frontends/Painter.h" #include "frontends/Selection.h" @@ -2732,6 +2733,9 @@ void BufferView::updateMetrics() d->update_strategy_ = FullScreenUpdate; + // Now update the positions of insets in the cache. + updatePosCache(); + if (lyxerr.debugging(Debug::WORKAREA)) { LYXERR(Debug::WORKAREA, "BufferView::updateMetrics"); d->coord_cache_.dump(); @@ -2739,6 +2743,15 @@ void BufferView::updateMetrics() } +void BufferView::updatePosCache() +{ + // this is the "nodraw" drawing stage: only set the positions of the + // insets in metrics cache. + frontend::NullPainter np; + draw(np); +} + + void BufferView::insertLyXFile(FileName const & fname) { LASSERT(d->cursor_.inTexted(), return); @@ -2984,12 +2997,11 @@ void BufferView::checkCursorScrollOffset(PainterInfo & pi) * at this point. */ // Force the recomputation of inset positions - bool const drawing = pi.pain.isDrawingEnabled(); - pi.pain.setDrawingEnabled(false); + frontend::NullPainter np; + PainterInfo(this, np); // No need to care about vertical position. RowPainter rp(pi, buffer().text(), row, -d->horiz_scroll_offset_, 0); rp.paintText(); - pi.pain.setDrawingEnabled(drawing); } // Current x position of the cursor in pixels @@ -3053,12 +3065,13 @@ void BufferView::draw(frontend::Painter & pain) switch (d->update_strategy_) { case NoScreenUpdate: - // If no screen painting is actually needed, only some the different - // coordinates of insets and paragraphs needs to be updated. + // no screen painting is actually needed. In nodraw stage + // however, the different coordinates of insets and paragraphs + // needs to be updated. LYXERR(Debug::PAINTING, "Strategy: NoScreenUpdate"); pi.full_repaint = true; - pi.pain.setDrawingEnabled(false); - tm.draw(pi, 0, y); + if (pain.isNull()) + tm.draw(pi, 0, y); break; case SingleParUpdate: diff --git a/src/BufferView.h b/src/BufferView.h index 588e9d0665..40af7c63b2 100644 --- a/src/BufferView.h +++ b/src/BufferView.h @@ -283,6 +283,10 @@ public: /// update the internal \c ViewMetricsInfo. void updateMetrics(); + // this is the "nodraw" drawing stage: only set the positions of the + // insets in metrics cache. + void updatePosCache(); + /// TextMetrics const & textMetrics(Text const * t) const; TextMetrics & textMetrics(Text const * t); @@ -303,7 +307,6 @@ public: /// get the position and height of the cursor void cursorPosAndHeight(Point & p, int & h) const; - /// void draw(frontend::Painter & pain); diff --git a/src/RowPainter.cpp b/src/RowPainter.cpp index 1f89b252b9..c4b9034fb4 100644 --- a/src/RowPainter.cpp +++ b/src/RowPainter.cpp @@ -576,7 +576,7 @@ void RowPainter::paintText() paintStringAndSel(e); // Paint the spelling marks if enabled. - if (lyxrc.spellcheck_continuously && pi_.do_spellcheck && pi_.pain.isDrawingEnabled()) + if (lyxrc.spellcheck_continuously && pi_.do_spellcheck && !pi_.pain.isNull()) paintMisspelledMark(e); break; diff --git a/src/TextMetrics.cpp b/src/TextMetrics.cpp index 4768157bda..360d83b296 100644 --- a/src/TextMetrics.cpp +++ b/src/TextMetrics.cpp @@ -1797,8 +1797,8 @@ void TextMetrics::drawParagraph(PainterInfo & pi, pit_type const pit, int const return; size_t const nrows = pm.rows().size(); - // Use fast lane when drawing is disabled. - if (!pi.pain.isDrawingEnabled()) { + // Use fast lane in nodraw stage. + if (pi.pain.isNull()) { for (size_t i = 0; i != nrows; ++i) { Row const & row = pm.rows()[i]; @@ -1850,17 +1850,11 @@ void TextMetrics::drawParagraph(PainterInfo & pi, pit_type const pit, int const if (i) y += row.ascent(); - RowPainter rp(pi, *text_, row, row_x, y); - // It is not needed to draw on screen if we are not inside. bool const inside = (y + row.descent() >= 0 && y - row.ascent() < ww); - pi.pain.setDrawingEnabled(inside); if (!inside) { - // Paint only the insets to set inset cache correctly - // FIXME: remove paintOnlyInsets when we know that positions - // have already been set. - rp.paintOnlyInsets(); + // Inset positions have already been set in nodraw stage. y += row.descent(); continue; } @@ -1889,6 +1883,8 @@ void TextMetrics::drawParagraph(PainterInfo & pi, pit_type const pit, int const text_->getPar(pit).spellCheck(); } + RowPainter rp(pi, *text_, row, row_x, y); + // Don't paint the row if a full repaint has not been requested // and if it has not changed. if (!pi.full_repaint && !row_has_changed) { @@ -1919,7 +1915,7 @@ void TextMetrics::drawParagraph(PainterInfo & pi, pit_type const pit, int const << " row_selection=" << row.selection() << " full_repaint=" << pi.full_repaint << " row_has_changed=" << row_has_changed - << " drawingEnabled=" << pi.pain.isDrawingEnabled()); + << " null painter=" << pi.pain.isNull()); } // Backup full_repaint status and force full repaint @@ -1947,8 +1943,6 @@ void TextMetrics::drawParagraph(PainterInfo & pi, pit_type const pit, int const // Restore full_repaint status. pi.full_repaint = tmp; } - // Re-enable screen drawing for future use of the painter. - pi.pain.setDrawingEnabled(true); //LYXERR(Debug::PAINTING, "."); } diff --git a/src/frontends/Makefile.am b/src/frontends/Makefile.am index 862613a67f..22b7508a7a 100644 --- a/src/frontends/Makefile.am +++ b/src/frontends/Makefile.am @@ -17,6 +17,7 @@ liblyxfrontends_a_SOURCES = \ Delegates.h \ KeyModifier.h \ KeySymbol.h \ + NullPainter.h \ Painter.h \ Clipboard.h \ Selection.h \ diff --git a/src/frontends/NullPainter.h b/src/frontends/NullPainter.h new file mode 100644 index 0000000000..19ac8b66a2 --- /dev/null +++ b/src/frontends/NullPainter.h @@ -0,0 +1,109 @@ +// -*- C++ -*- +/** + * \file NullPainter.h + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author unknown + * \author John Levon + * \author Jean-Marc Lasgouttes + * + * Full author contact details are available in file CREDITS. + */ + +#ifndef NULLPAINTER_H +#define NULLPAINTER_H + +#include "Painter.h" + +namespace lyx { + +namespace frontend { + +/** + * NullPainter - A painter instance that does nothing + */ +class NullPainter : public Painter { +public: + NullPainter() : Painter(1) {} + + ~NullPainter() {} + + /// draw a line from point to point + void line(int, int, int, int, Color, + line_style = line_solid, int = thin_line) {} + + /// + void lines(int const *, int const *, int, Color, + fill_style = fill_none, line_style = line_solid, + int = thin_line) {} + + /// + void path(int const *, int const *, int const *, int const *, + int const *, int const *, int, Color, + fill_style = fill_none, line_style = line_solid, int = thin_line) {} + + /// draw a rectangle + void rectangle(int, int, int, int, Color, + line_style = line_solid, int = thin_line) {} + + /// draw a filled rectangle + void fillRectangle(int, int, int, int, Color) {} + + /// draw an arc + void arc(int, int, unsigned int, unsigned int, int, int, Color) {} + + /// draw a pixel + void point(int, int, Color) {} + + /// draw an image from the image cache + void image(int, int, int, int, graphics::Image const &) {} + + /// draw a string + void text(int, int, docstring const &, FontInfo const &) {} + + /// draw a char + void text(int, int, char_type, FontInfo const &) {} + + /// draw a string + void text(int, int, docstring const &, Font const &, double, double) {} + + /// + void text(int, int, docstring const &, Font const &, + Color, size_type, size_type, double, double) {} + + /// This painter does not paint + bool isNull() const { return true; } + + /// draw the underbar, strikeout, xout, uuline and uwave font attributes + void textDecoration(FontInfo const &, int, int, int) {} + + /** + * Draw a string and enclose it inside a rectangle. If + * back color is specified, the background is cleared with + * the given color. If frame is specified, a thin frame is drawn + * around the text with the given color. + */ + void rectText(int, int, docstring const &, + FontInfo const &, Color, Color) {} + + /// draw a string and enclose it inside a button frame + void buttonText(int, int, docstring const &, + FontInfo const &, Color, Color, int) {} + + /// draw a character of a preedit string for cjk support. + int preeditText(int, int, char_type, FontInfo const &, + preedit_style) { return 0; } + + /// start monochrome painting mode, i.e. map every color into [min,max] + void enterMonochromeMode(Color const &, Color const &) {} + /// leave monochrome painting mode + void leaveMonochromeMode() {} + /// draws a wavy line that can be used for underlining. + void wavyHorizontalLine(int, int, int, ColorCode) {} +}; + +} // namespace frontend +} // namespace lyx + +#endif // NULLPAINTER_H diff --git a/src/frontends/Painter.h b/src/frontends/Painter.h index d03ebf40e8..17253b2f44 100644 --- a/src/frontends/Painter.h +++ b/src/frontends/Painter.h @@ -49,7 +49,7 @@ namespace frontend { */ class Painter { public: - Painter(double pixel_ratio) : drawing_enabled_(true), pixel_ratio_(pixel_ratio) {} + Painter(double pixel_ratio) : pixel_ratio_(pixel_ratio) {} static const int thin_line; @@ -147,11 +147,8 @@ public: Color other, size_type from, size_type to, double wordspacing, double textwidth) = 0; - void setDrawingEnabled(bool drawing_enabled) - { drawing_enabled_ = drawing_enabled; } - - /// Indicate wether real screen drawing shall be done or not. - bool isDrawingEnabled() const { return drawing_enabled_; } + // Returns true if the painter does not actually paint. + virtual bool isNull() const = 0; double pixelRatio() const { return pixel_ratio_; } @@ -183,8 +180,6 @@ public: /// draws a wavy line that can be used for underlining. virtual void wavyHorizontalLine(int x, int y, int width, ColorCode col) = 0; private: - /// - bool drawing_enabled_; /// Ratio between physical pixels and device-independent pixels double pixel_ratio_; }; diff --git a/src/frontends/qt4/GuiPainter.cpp b/src/frontends/qt4/GuiPainter.cpp index e832f23e99..bff8f9dc30 100644 --- a/src/frontends/qt4/GuiPainter.cpp +++ b/src/frontends/qt4/GuiPainter.cpp @@ -171,9 +171,6 @@ void GuiPainter::leaveMonochromeMode() void GuiPainter::point(int x, int y, Color col) { - if (!isDrawingEnabled()) - return; - setQPainterPen(computeColor(col)); drawPoint(x, y); } @@ -184,9 +181,6 @@ void GuiPainter::line(int x1, int y1, int x2, int y2, line_style ls, int lw) { - if (!isDrawingEnabled()) - return; - setQPainterPen(computeColor(col), ls, lw); bool const do_antialiasing = renderHints() & TextAntialiasing && x1 != x2 && y1 != y2 && ls != line_solid_aliased; @@ -202,9 +196,6 @@ void GuiPainter::lines(int const * xp, int const * yp, int np, line_style ls, int lw) { - if (!isDrawingEnabled()) - return; - // double the size if needed // FIXME THREAD static QVector points(32); @@ -247,9 +238,6 @@ void GuiPainter::path(int const * xp, int const * yp, line_style ls, int lw) { - if (!isDrawingEnabled()) - return; - QPainterPath bpath; // This is the starting point, so its control points are meaningless bpath.moveTo(xp[0], yp[0]); @@ -278,9 +266,6 @@ void GuiPainter::rectangle(int x, int y, int w, int h, line_style ls, int lw) { - if (!isDrawingEnabled()) - return; - setQPainterPen(computeColor(col), ls, lw); drawRect(x, y, w, h); } @@ -288,9 +273,6 @@ void GuiPainter::rectangle(int x, int y, int w, int h, void GuiPainter::fillRectangle(int x, int y, int w, int h, Color col) { - if (!isDrawingEnabled()) - return; - fillRect(x, y, w, h, guiApp->colorCache().get(col)); } @@ -298,9 +280,6 @@ void GuiPainter::fillRectangle(int x, int y, int w, int h, Color col) void GuiPainter::arc(int x, int y, unsigned int w, unsigned int h, int a1, int a2, Color col) { - if (!isDrawingEnabled()) - return; - // LyX usings 1/64ths degree, Qt usings 1/16th setQPainterPen(computeColor(col)); bool const do_antialiasing = renderHints() & TextAntialiasing; @@ -317,9 +296,6 @@ void GuiPainter::image(int x, int y, int w, int h, graphics::Image const & i) fillRectangle(x, y, w, h, Color_graphicsbg); - if (!isDrawingEnabled()) - return; - QImage const image = qlimage.image(); QRectF const drect = QRectF(x, y, w, h); QRectF const srect = QRectF(0, 0, image.width(), image.height()); @@ -391,7 +367,7 @@ void GuiPainter::text(int x, int y, docstring const & s, double const wordspacing, double const tw) { //LYXERR0("text: x=" << x << ", s=" << s); - if (s.empty() || !isDrawingEnabled()) + if (s.empty()) return; /* Caution: The following ucs4 to QString conversions work for symbol fonts diff --git a/src/frontends/qt4/GuiPainter.h b/src/frontends/qt4/GuiPainter.h index 9657ed9770..7513965ea6 100644 --- a/src/frontends/qt4/GuiPainter.h +++ b/src/frontends/qt4/GuiPainter.h @@ -37,6 +37,9 @@ public: GuiPainter(QPaintDevice *, double pixel_ratio); virtual ~GuiPainter(); + /// This painter paints + virtual bool isNull() const { return false; } + /// draw a line from point to point virtual void line( int x1, int y1, diff --git a/src/frontends/qt4/GuiWorkArea.cpp b/src/frontends/qt4/GuiWorkArea.cpp index 8bf5242b33..ea6423ac85 100644 --- a/src/frontends/qt4/GuiWorkArea.cpp +++ b/src/frontends/qt4/GuiWorkArea.cpp @@ -16,6 +16,11 @@ #include "ColorCache.h" #include "FontLoader.h" +#include "GuiApplication.h" +#include "GuiCompleter.h" +#include "GuiKeySymbol.h" +#include "GuiPainter.h" +#include "GuiView.h" #include "Menus.h" #include "Buffer.h" @@ -26,11 +31,6 @@ #include "Cursor.h" #include "Font.h" #include "FuncRequest.h" -#include "GuiApplication.h" -#include "GuiCompleter.h" -#include "GuiKeySymbol.h" -#include "GuiPainter.h" -#include "GuiView.h" #include "KeySymbol.h" #include "Language.h" #include "LyX.h" @@ -1289,9 +1289,8 @@ void GuiWorkArea::inputMethodEvent(QInputMethodEvent * e) return; } - GuiPainter pain(d->screen_, pixelRatio()); d->buffer_view_->updateMetrics(); - d->buffer_view_->draw(pain); + d->updateScreen(); // FIXME: shall we use real_current_font here? (see #10478) FontInfo font = d->buffer_view_->cursor().getFont().fontInfo(); FontMetrics const & fm = theFontMetrics(font); @@ -1383,6 +1382,7 @@ void GuiWorkArea::inputMethodEvent(QInputMethodEvent * e) ps = Painter::preedit_cursor; // draw one character and update cur_x. + GuiPainter pain(d->screen_, pixelRatio()); cur_x += pain.preeditText(cur_x, cur_y, typed_char, font, ps); } diff --git a/src/mathed/InsetMathMacroTemplate.cpp b/src/mathed/InsetMathMacroTemplate.cpp index 17fc2d04a2..a2fc064c00 100644 --- a/src/mathed/InsetMathMacroTemplate.cpp +++ b/src/mathed/InsetMathMacroTemplate.cpp @@ -231,25 +231,17 @@ void InsetDisplayLabelBox::metrics(MetricsInfo & mi, Dimension & dim) const { InsetLabelBox::metrics(mi, dim); if (!parent_.editing(mi.base.bv) - && parent_.cell(parent_.displayIdx()).empty()) { - dim.wid = 0; - dim.asc = 0; - dim.des = 0; - } + && parent_.cell(parent_.displayIdx()).empty()) + dim.clear(); } void InsetDisplayLabelBox::draw(PainterInfo & pi, int x, int y) const { if (parent_.editing(pi.base.bv) - || !parent_.cell(parent_.displayIdx()).empty()) { - InsetLabelBox::draw(pi, x, y); - } else { - bool enabled = pi.pain.isDrawingEnabled(); - pi.pain.setDrawingEnabled(false); - InsetLabelBox::draw(pi, x, y); - pi.pain.setDrawingEnabled(enabled); - } + || !parent_.cell(parent_.displayIdx()).empty() + || pi.pain.isNull()) + InsetLabelBox::draw(pi, x, y); } From 7b8b3e38a1b9ff4d733266a4f3fe0f8fb041da01 Mon Sep 17 00:00:00 2001 From: Jean-Marc Lasgouttes Date: Fri, 8 Sep 2017 16:55:11 +0200 Subject: [PATCH 011/121] Do the actual drawing in the paint event Historically, because of two-stage drawing, LyX has been painting on a Pixmap, and this pixmap is copied to screen at paint event time. Now that we have three-stage drawing, it is possible to delay the painting to actual paint event and avoid the intermediate Pixmap. Known bug: the cursor is never erased. --- src/frontends/qt4/GuiWorkArea.cpp | 55 ++++++++----------------- src/frontends/qt4/GuiWorkArea_Private.h | 29 ------------- 2 files changed, 17 insertions(+), 67 deletions(-) diff --git a/src/frontends/qt4/GuiWorkArea.cpp b/src/frontends/qt4/GuiWorkArea.cpp index ea6423ac85..8ce598583e 100644 --- a/src/frontends/qt4/GuiWorkArea.cpp +++ b/src/frontends/qt4/GuiWorkArea.cpp @@ -246,7 +246,7 @@ SyntheticMouseEvent::SyntheticMouseEvent() GuiWorkArea::Private::Private(GuiWorkArea * parent) -: p(parent), screen_(0), buffer_view_(0), lyx_view_(0), +: p(parent), buffer_view_(0), lyx_view_(0), cursor_visible_(false), cursor_(0), need_resize_(false), schedule_redraw_(false), preedit_lines_(1), pixel_ratio_(1.0), @@ -299,7 +299,6 @@ void GuiWorkArea::init() d->cursor_timeout_.setInterval(500); } - d->resetScreen(); // With Qt4.5 a mouse event will happen before the first paint event // so make sure that the buffer view has an up to date metrics. d->buffer_view_->resize(viewport()->width(), viewport()->height()); @@ -313,10 +312,11 @@ void GuiWorkArea::init() setFrameStyle(QFrame::NoFrame); updateWindowTitle(); - viewport()->setAutoFillBackground(false); + //viewport()->setAutoFillBackground(false); // We don't need double-buffering nor SystemBackground on // the viewport because we have our own backing pixmap. - viewport()->setAttribute(Qt::WA_NoSystemBackground); + //viewport()->setAttribute(Qt::WA_NoSystemBackground); + viewport()->setAttribute(Qt::WA_OpaquePaintEvent); setFocusPolicy(Qt::StrongFocus); @@ -344,7 +344,6 @@ GuiWorkArea::~GuiWorkArea() try { d->buffer_view_->buffer().workAreaManager().remove(this); } catch(...) {} - delete d->screen_; delete d->buffer_view_; delete d->cursor_; // Completer has a QObject parent and is thus automatically destroyed. @@ -491,8 +490,7 @@ void GuiWorkArea::redraw(bool update_metrics) } LYXERR(Debug::WORKAREA, "WorkArea::redraw screen"); - d->updateScreen(); - update(0, 0, viewport()->width(), viewport()->height()); + viewport()->update(); /// \warning: scrollbar updating *must* be done after the BufferView is drawn /// because \c BufferView::updateScrollbar() is called in \c BufferView::draw(). @@ -591,7 +589,7 @@ void GuiWorkArea::Private::resizeBufferView() buffer_view_->resize(p->viewport()->width(), p->viewport()->height()); if (cursor_in_view) buffer_view_->scrollToCursor(); - updateScreen(); + p->viewport()->update(); // Update scrollbars which might have changed due different // BufferView dimension. This is especially important when the @@ -1176,20 +1174,12 @@ void GuiWorkArea::resizeEvent(QResizeEvent * ev) } -void GuiWorkArea::Private::update(int x, int y, int w, int h) -{ - p->viewport()->update(x, y, w, h); -} - - void GuiWorkArea::paintEvent(QPaintEvent * ev) { - QRectF const rc = ev->rect(); // LYXERR(Debug::PAINTING, "paintEvent begin: x: " << rc.x() // << " y: " << rc.y() << " w: " << rc.width() << " h: " << rc.height()); if (d->needResize()) { - d->resetScreen(); d->resizeBufferView(); if (d->cursor_visible_) { d->hideCursor(); @@ -1197,29 +1187,14 @@ void GuiWorkArea::paintEvent(QPaintEvent * ev) } } - QPainter pain(viewport()); - double const pr = pixelRatio(); - QRectF const rcs = QRectF(rc.x() * pr, rc.y() * pr, rc.width() * pr, rc.height() * pr); + GuiPainter pain(viewport(), pixelRatio()); + d->buffer_view_->draw(pain); - if (lyxrc.use_qimage) { - QImage const & image = static_cast(*d->screen_); - pain.drawImage(rc, image, rcs); - } else { - QPixmap const & pixmap = static_cast(*d->screen_); - pain.drawPixmap(rc, pixmap, rcs); - } d->cursor_->draw(pain); ev->accept(); } -void GuiWorkArea::Private::updateScreen() -{ - GuiPainter pain(screen_, p->pixelRatio()); - buffer_view_->draw(pain); -} - - void GuiWorkArea::Private::showCursor(int x, int y, int h, bool l_shape, bool rtl, bool completable) { @@ -1229,9 +1204,8 @@ void GuiWorkArea::Private::showCursor(int x, int y, int h, // We can't use redraw() here because this would trigger a infinite // recursive loop with showCursor(). buffer_view_->resize(p->viewport()->width(), p->viewport()->height()); - updateScreen(); + p->viewport()->update(); updateScrollbar(); - p->viewport()->update(QRect(0, 0, p->viewport()->width(), p->viewport()->height())); schedule_redraw_ = false; // Show the cursor immediately after the update. hideCursor(); @@ -1255,6 +1229,10 @@ void GuiWorkArea::Private::removeCursor() void GuiWorkArea::inputMethodEvent(QInputMethodEvent * e) { +//FIXME Broken Feature !! +// I do not think that we are supposed to paint inside this event. Shall we +// just let TextMetrics::breakRow add this to the relevant Row object? +#if 0 QString const & commit_string = e->commitString(); docstring const & preedit_string = qstring_to_ucs4(e->preeditString()); @@ -1290,7 +1268,7 @@ void GuiWorkArea::inputMethodEvent(QInputMethodEvent * e) } d->buffer_view_->updateMetrics(); - d->updateScreen(); + viewport()->update(); // FIXME: shall we use real_current_font here? (see #10478) FontInfo font = d->buffer_view_->cursor().getFont().fontInfo(); FontMetrics const & fm = theFontMetrics(font); @@ -1299,7 +1277,7 @@ void GuiWorkArea::inputMethodEvent(QInputMethodEvent * e) int cur_y = d->cursor_->rect().bottom(); // redraw area of preedit string. - update(0, cur_y - height, viewport()->width(), + viewport()->update(0, cur_y - height, viewport()->width(), (height + 1) * d->preedit_lines_); if (preedit_string.empty()) { @@ -1387,8 +1365,9 @@ void GuiWorkArea::inputMethodEvent(QInputMethodEvent * e) } // update the preedit string screen area. - update(0, cur_y - d->preedit_lines_*height, viewport()->width(), + viewport()->update(0, cur_y - d->preedit_lines_*height, viewport()->width(), (height + 1) * d->preedit_lines_); +#endif // Don't forget to accept the event! e->accept(); diff --git a/src/frontends/qt4/GuiWorkArea_Private.h b/src/frontends/qt4/GuiWorkArea_Private.h index 76b05c0d36..42597172b1 100644 --- a/src/frontends/qt4/GuiWorkArea_Private.h +++ b/src/frontends/qt4/GuiWorkArea_Private.h @@ -92,10 +92,6 @@ struct GuiWorkArea::Private { Private(GuiWorkArea *); - /// update the passed area. - void update(int x, int y, int w, int h); - /// - void updateScreen(); /// void resizeBufferView(); @@ -123,34 +119,9 @@ struct GuiWorkArea::Private return need_resize_ || p->pixelRatio() != pixel_ratio_; } - void resetScreen() - { - delete screen_; - pixel_ratio_ = p->pixelRatio(); - if (lyxrc.use_qimage) { - QImage *x = - new QImage(static_cast(pixel_ratio_ * p->viewport()->width()), - static_cast(pixel_ratio_ * p->viewport()->height()), - QImage::Format_ARGB32_Premultiplied); -#if QT_VERSION >= 0x050000 - x->setDevicePixelRatio(pixel_ratio_); -#endif - screen_ = x; - } else { - QPixmap *x = - new QPixmap(static_cast(pixel_ratio_ * p->viewport()->width()), - static_cast(pixel_ratio_ * p->viewport()->height())); -#if QT_VERSION >= 0x050000 - x->setDevicePixelRatio(pixel_ratio_); -#endif - screen_ = x; - } - } /// GuiWorkArea * p; /// - QPaintDevice * screen_; - /// BufferView * buffer_view_; /// GuiView * lyx_view_; From ef1d50207088bc40cd0fbbd27229df9e8400e932 Mon Sep 17 00:00:00 2001 From: Jean-Marc Lasgouttes Date: Thu, 20 Jul 2017 23:31:05 +0200 Subject: [PATCH 012/121] Fix caret painting The trick is to remember in BufferView what has been done at the previous draw, so that the row that contained the caret can be repainted if needed. To this end, add an argument paint_caret to BufferView, although painting the caret is not the job of the BufferView (at this point). BufferView::needRepaint will act as an interface with TextMetrics::drawParagraph to know whether the painting of a given row should be forced. Currently everything is done at the top row level, so that, if the caret is in a large table, the whole table will have to be repainted. It is not clear yet that this is necessary. --- src/BufferView.cpp | 54 ++++++++++++++++++++++++++++--- src/BufferView.h | 6 +++- src/MetricsInfo.h | 2 +- src/TextMetrics.cpp | 3 +- src/frontends/qt4/GuiWorkArea.cpp | 5 +-- 5 files changed, 60 insertions(+), 10 deletions(-) diff --git a/src/BufferView.cpp b/src/BufferView.cpp index 94e448d1e9..3c6adfcd74 100644 --- a/src/BufferView.cpp +++ b/src/BufferView.cpp @@ -235,7 +235,7 @@ struct BufferView::Private last_inset_(0), clickable_inset_(false), mouse_position_cache_(), bookmark_edit_position_(-1), gui_(0), - horiz_scroll_offset_(0) + horiz_scroll_offset_(0), repaint_caret_row_(false) { xsel_cache_.set = false; } @@ -312,6 +312,12 @@ struct BufferView::Private /// a slice pointing to the start of the row where cursor was /// at previous draw event CursorSlice last_row_slice_; + + /// a slice pointing to where the cursor has been drawn after the current + /// draw() call. + CursorSlice caret_slice_; + /// indicates whether the caret slice needs to be repainted in this draw() run. + bool repaint_caret_row_; }; @@ -2748,7 +2754,7 @@ void BufferView::updatePosCache() // this is the "nodraw" drawing stage: only set the positions of the // insets in metrics cache. frontend::NullPainter np; - draw(np); + draw(np, false); } @@ -2959,6 +2965,23 @@ void BufferView::setCurrentRowSlice(CursorSlice const & rowSlice) } +namespace { + +bool sliceInRow(CursorSlice const & cs, Text const * text, Row const & row) +{ + return !cs.empty() && cs.text() == text && cs.pit() == row.pit() + && row.pos() <= cs.pos() && cs.pos() <= row.endpos(); +} + +} + + +bool BufferView::needRepaint(Text const * text, Row const & row) const +{ + return d->repaint_caret_row_ && sliceInRow(d->caret_slice_, text, row); +} + + void BufferView::checkCursorScrollOffset(PainterInfo & pi) { CursorSlice rowSlice = d->cursor_.bottom(); @@ -3047,7 +3070,7 @@ void BufferView::checkCursorScrollOffset(PainterInfo & pi) } -void BufferView::draw(frontend::Painter & pain) +void BufferView::draw(frontend::Painter & pain, bool paint_caret) { if (height_ == 0 || width_ == 0) return; @@ -3058,6 +3081,16 @@ void BufferView::draw(frontend::Painter & pain) int const y = tm.first().second->position(); PainterInfo pi(this, pain); + CursorSlice const & bottomSlice = d->cursor_.bottom(); + /** A repaint of the previous cursor row is needed if + * 1/ the caret will be painted and is is not the same than the + * already painted one; + * 2/ the caret will not be painted, but there is already one on + * screen. + */ + d->repaint_caret_row_ = (paint_caret && bottomSlice != d->caret_slice_) + || (! paint_caret && !d->caret_slice_.empty()); + // Check whether the row where the cursor lives needs to be scrolled. // Update the drawing strategy if needed. checkCursorScrollOffset(pi); @@ -3069,9 +3102,14 @@ void BufferView::draw(frontend::Painter & pain) // however, the different coordinates of insets and paragraphs // needs to be updated. LYXERR(Debug::PAINTING, "Strategy: NoScreenUpdate"); - pi.full_repaint = true; - if (pain.isNull()) + pi.full_repaint = false; + if (pain.isNull()) { + pi.full_repaint = true; tm.draw(pi, 0, y); + } else if (d->repaint_caret_row_) { + pi.full_repaint = false; + tm.draw(pi, 0, y); + } break; case SingleParUpdate: @@ -3134,6 +3172,12 @@ void BufferView::draw(frontend::Painter & pain) } LYXERR(Debug::PAINTING, "Found new anchor pit = " << d->anchor_pit_ << " anchor ypos = " << d->anchor_ypos_); + + // Remember what has just been done for the next draw() step + if (paint_caret) + d->caret_slice_ = bottomSlice; + else + d->caret_slice_ = CursorSlice(); } diff --git a/src/BufferView.h b/src/BufferView.h index 40af7c63b2..eed408dae7 100644 --- a/src/BufferView.h +++ b/src/BufferView.h @@ -46,6 +46,7 @@ class PainterInfo; class ParIterator; class ParagraphMetrics; class Point; +class Row; class TexRow; class Text; class TextMetrics; @@ -132,6 +133,9 @@ public: /// Only to be called with good y coordinates (after a bv::metrics) bool needsFitCursor() const; + /// returns true if this row needs to be repainted (to erase caret) + bool needRepaint(Text const * text, Row const & row) const; + // Returns the amount of horizontal scrolling applied to the // top-level row where the cursor lies int horizScrollOffset() const; @@ -308,7 +312,7 @@ public: void cursorPosAndHeight(Point & p, int & h) const; /// - void draw(frontend::Painter & pain); + void draw(frontend::Painter & pain, bool paint_caret); /// get this view's keyboard map handler. Intl & getIntl(); diff --git a/src/MetricsInfo.h b/src/MetricsInfo.h index 2a18cf8cff..ff0b1c6989 100644 --- a/src/MetricsInfo.h +++ b/src/MetricsInfo.h @@ -130,7 +130,7 @@ public: bool selected; /// Whether the spell checker is enabled for the parent bool do_spellcheck; - /// + /// True when it can be assumed that the screen has been cleared bool full_repaint; /// Current background color ColorCode background_color; diff --git a/src/TextMetrics.cpp b/src/TextMetrics.cpp index 360d83b296..52717400d5 100644 --- a/src/TextMetrics.cpp +++ b/src/TextMetrics.cpp @@ -1876,7 +1876,8 @@ void TextMetrics::drawParagraph(PainterInfo & pi, pit_type const pit, int const // Row signature; has row changed since last paint? row.setCrc(pm.computeRowSignature(row, *bv_)); bool row_has_changed = row.changed() - || bv_->hadHorizScrollOffset(text_, pit, row.pos()); + || bv_->hadHorizScrollOffset(text_, pit, row.pos()) + || bv_->needRepaint(text_, row); // Take this opportunity to spellcheck the row contents. if (row_has_changed && pi.do_spellcheck && lyxrc.spellcheck_continuously) { diff --git a/src/frontends/qt4/GuiWorkArea.cpp b/src/frontends/qt4/GuiWorkArea.cpp index 8ce598583e..9a9e155f2d 100644 --- a/src/frontends/qt4/GuiWorkArea.cpp +++ b/src/frontends/qt4/GuiWorkArea.cpp @@ -1188,9 +1188,10 @@ void GuiWorkArea::paintEvent(QPaintEvent * ev) } GuiPainter pain(viewport(), pixelRatio()); - d->buffer_view_->draw(pain); + d->buffer_view_->draw(pain, d->cursor_visible_); - d->cursor_->draw(pain); + if (d->cursor_visible_) + d->cursor_->draw(pain); ev->accept(); } From 418bf09879dfad860e298f0f3b16d765bb1262d5 Mon Sep 17 00:00:00 2001 From: Jean-Marc Lasgouttes Date: Sat, 22 Jul 2017 01:19:45 +0200 Subject: [PATCH 013/121] Cleanup and simplify WorkArea code Rename cursor to caret to in order to avoid ambiguity. The caret is now the blinking thing only. Remove unused header contents, and some not so useful methods. No intended change of behavior. --- src/frontends/qt4/FindAndReplace.cpp | 4 +- src/frontends/qt4/GuiApplication.cpp | 11 +- src/frontends/qt4/GuiView.cpp | 8 +- src/frontends/qt4/GuiView.h | 2 +- src/frontends/qt4/GuiWorkArea.cpp | 292 ++++++++++-------------- src/frontends/qt4/GuiWorkArea.h | 12 +- src/frontends/qt4/GuiWorkArea_Private.h | 46 ++-- 7 files changed, 152 insertions(+), 223 deletions(-) diff --git a/src/frontends/qt4/FindAndReplace.cpp b/src/frontends/qt4/FindAndReplace.cpp index 4411074de7..607f1653aa 100644 --- a/src/frontends/qt4/FindAndReplace.cpp +++ b/src/frontends/qt4/FindAndReplace.cpp @@ -65,8 +65,8 @@ FindAndReplaceWidget::FindAndReplaceWidget(GuiView & view) replace_work_area_->setFrameStyle(QFrame::StyledPanel); // We don't want two cursors blinking. - find_work_area_->stopBlinkingCursor(); - replace_work_area_->stopBlinkingCursor(); + find_work_area_->stopBlinkingCaret(); + replace_work_area_->stopBlinkingCaret(); } diff --git a/src/frontends/qt4/GuiApplication.cpp b/src/frontends/qt4/GuiApplication.cpp index 0ce130eb69..ee379ffb56 100644 --- a/src/frontends/qt4/GuiApplication.cpp +++ b/src/frontends/qt4/GuiApplication.cpp @@ -122,7 +122,6 @@ #include #include #include -#undef CursorShape #undef None #elif defined(QPA_XCB) #include @@ -1435,7 +1434,7 @@ void GuiApplication::updateCurrentView(FuncRequest const & cmd, DispatchResult & theSelection().haveSelection(bv->cursor().selection()); // update gui - current_view_->restartCursor(); + current_view_->restartCaret(); } if (dr.needMessageUpdate()) { // Some messages may already be translated, so we cannot use _() @@ -2151,7 +2150,7 @@ void GuiApplication::processKeySym(KeySymbol const & keysym, KeyModifier state) if (!keysym.isOK()) LYXERR(Debug::KEY, "Empty kbd action (probably composing)"); if (current_view_) - current_view_->restartCursor(); + current_view_->restartCaret(); return; } @@ -2211,7 +2210,7 @@ void GuiApplication::processKeySym(KeySymbol const & keysym, KeyModifier state) if (!isPrintable(encoded_last_key)) { LYXERR(Debug::KEY, "Non-printable character! Omitting."); if (current_view_) - current_view_->restartCursor(); + current_view_->restartCaret(); return; } // The following modifier check is not needed on Mac. @@ -2233,7 +2232,7 @@ void GuiApplication::processKeySym(KeySymbol const & keysym, KeyModifier state) { if (current_view_) { current_view_->message(_("Unknown function.")); - current_view_->restartCursor(); + current_view_->restartCaret(); } return; } @@ -2248,7 +2247,7 @@ void GuiApplication::processKeySym(KeySymbol const & keysym, KeyModifier state) LYXERR(Debug::KEY, "Unknown Action and not isText() -- giving up"); if (current_view_) { current_view_->message(_("Unknown function.")); - current_view_->restartCursor(); + current_view_->restartCaret(); } return; } diff --git a/src/frontends/qt4/GuiView.cpp b/src/frontends/qt4/GuiView.cpp index c587460297..a7d669a774 100644 --- a/src/frontends/qt4/GuiView.cpp +++ b/src/frontends/qt4/GuiView.cpp @@ -4354,13 +4354,13 @@ Buffer const * GuiView::updateInset(Inset const * inset) } -void GuiView::restartCursor() +void GuiView::restartCaret() { /* When we move around, or type, it's nice to be able to see - * the cursor immediately after the keypress. + * the caret immediately after the keypress. */ if (d.current_work_area_) - d.current_work_area_->startBlinkingCursor(); + d.current_work_area_->startBlinkingCaret(); // Take this occasion to update the other GUI elements. updateDialogs(); @@ -4429,7 +4429,7 @@ void GuiView::resetDialogs() // Now update controls with current buffer. guiApp->setCurrentView(this); restoreLayout(); - restartCursor(); + restartCaret(); } diff --git a/src/frontends/qt4/GuiView.h b/src/frontends/qt4/GuiView.h index ecf4e446c6..68f1734a94 100644 --- a/src/frontends/qt4/GuiView.h +++ b/src/frontends/qt4/GuiView.h @@ -116,7 +116,7 @@ public: /// \return true if the \c FuncRequest has been dispatched. void dispatch(FuncRequest const & cmd, DispatchResult & dr); - void restartCursor(); + void restartCaret(); /// Update the completion popup and the inline completion state. /// If \c start is true, then a new completion might be started. /// If \c keep is true, an active completion will be kept active diff --git a/src/frontends/qt4/GuiWorkArea.cpp b/src/frontends/qt4/GuiWorkArea.cpp index 9a9e155f2d..6773412cb0 100644 --- a/src/frontends/qt4/GuiWorkArea.cpp +++ b/src/frontends/qt4/GuiWorkArea.cpp @@ -22,6 +22,7 @@ #include "GuiPainter.h" #include "GuiView.h" #include "Menus.h" +#include "qt_helpers.h" #include "Buffer.h" #include "BufferList.h" @@ -36,7 +37,6 @@ #include "LyX.h" #include "LyXRC.h" #include "LyXVC.h" -#include "qt_helpers.h" #include "Text.h" #include "TextMetrics.h" #include "version.h" @@ -46,7 +46,6 @@ #include "support/convert.h" #include "support/debug.h" -#include "support/gettext.h" #include "support/lassert.h" #include "support/TempFile.h" @@ -68,7 +67,6 @@ #include #include #include -#include #include #include #include @@ -77,8 +75,6 @@ #include #include -#include "support/bind.h" - #include #include @@ -130,17 +126,15 @@ mouse_button::state q_motion_state(Qt::MouseButtons state) namespace frontend { -class CursorWidget { +class CaretWidget { public: - CursorWidget() : rtl_(false), l_shape_(false), completable_(false), - show_(false), x_(0), cursor_width_(0) - { - recomputeWidth(); - } + CaretWidget() : rtl_(false), l_shape_(false), completable_(false), + x_(0), caret_width_(0) + {} void draw(QPainter & painter) { - if (!show_ || !rect_.isValid()) + if (!rect_.isValid()) return; int y = rect_.top(); @@ -149,7 +143,7 @@ public: int bot = rect_.bottom(); // draw vertical line - painter.fillRect(x_, y, cursor_width_, rect_.height(), color_); + painter.fillRect(x_, y, caret_width_, rect_.height(), color_); // draw RTL/LTR indication painter.setPen(color_); @@ -157,7 +151,7 @@ public: if (rtl_) painter.drawLine(x_, bot, x_ - l, bot); else - painter.drawLine(x_, bot, x_ + cursor_width_ + r, bot); + painter.drawLine(x_, bot, x_ + caret_width_ + r, bot); } // draw completion triangle @@ -168,8 +162,8 @@ public: painter.drawLine(x_ - 1, m - d, x_ - 1 - d, m); painter.drawLine(x_ - 1, m + d, x_ - 1 - d, m); } else { - painter.drawLine(x_ + cursor_width_, m - d, x_ + cursor_width_ + d, m); - painter.drawLine(x_ + cursor_width_, m + d, x_ + cursor_width_ + d, m); + painter.drawLine(x_ + caret_width_, m - d, x_ + caret_width_ + d, m); + painter.drawLine(x_ + caret_width_, m + d, x_ + caret_width_ + d, m); } } } @@ -203,17 +197,12 @@ public: r = max(r, TabIndicatorWidth); } - // compute overall rectangle - rect_ = QRect(x - l, y, cursor_width_ + r + l, h); - } - - void show(bool set_show = true) { show_ = set_show; } - void hide() { show_ = false; } - int cursorWidth() const { return cursor_width_; } - void recomputeWidth() { - cursor_width_ = lyxrc.cursor_width + caret_width_ = lyxrc.cursor_width ? lyxrc.cursor_width : 1 + int((lyxrc.currentZoom + 50) / 200.0); + + // compute overall rectangle + rect_ = QRect(x - l, y, caret_width_ + r + l, h); } QRect const & rect() { return rect_; } @@ -226,15 +215,13 @@ private: /// triangle to show that a completion is available bool completable_; /// - bool show_; - /// QColor color_; /// rectangle, possibly with l_shape and completion triangle QRect rect_; /// x position (were the vertical line is drawn) int x_; - - int cursor_width_; + /// the width of the vertical blinking bar + int caret_width_; }; @@ -247,12 +234,34 @@ SyntheticMouseEvent::SyntheticMouseEvent() GuiWorkArea::Private::Private(GuiWorkArea * parent) : p(parent), buffer_view_(0), lyx_view_(0), - cursor_visible_(false), cursor_(0), + caret_(0), caret_visible_(false), need_resize_(false), schedule_redraw_(false), preedit_lines_(1), pixel_ratio_(1.0), completer_(new GuiCompleter(p, p)), dialog_mode_(false), shell_escape_(false), read_only_(false), clean_(true), externally_modified_(false) { + int const time = QApplication::cursorFlashTime() / 2; + if (time > 0) { + caret_timeout_.setInterval(time); + caret_timeout_.start(); + } else { + // let's initialize this just to be safe + caret_timeout_.setInterval(500); + } +} + + +GuiWorkArea::Private::~Private() +{ + // If something is wrong with the buffer, we can ignore it safely + try { + buffer_view_->buffer().workAreaManager().remove(p); + } catch(...) {} + delete buffer_view_; + delete caret_; + // Completer has a QObject parent and is thus automatically destroyed. + // See #4758. + // delete completer_; } @@ -287,23 +296,18 @@ double GuiWorkArea::pixelRatio() const void GuiWorkArea::init() { // Setup the signals - connect(&d->cursor_timeout_, SIGNAL(timeout()), - this, SLOT(toggleCursor())); + connect(&d->caret_timeout_, SIGNAL(timeout()), + this, SLOT(toggleCaret())); - int const time = QApplication::cursorFlashTime() / 2; - if (time > 0) { - d->cursor_timeout_.setInterval(time); - d->cursor_timeout_.start(); - } else { - // let's initialize this just to be safe - d->cursor_timeout_.setInterval(500); - } + // This connection is closed at the same time as this is destroyed. + d->synthetic_mouse_event_.timeout.timeout.connect([this](){ + generateSyntheticMouseEvent(); + }); // With Qt4.5 a mouse event will happen before the first paint event // so make sure that the buffer view has an up to date metrics. d->buffer_view_->resize(viewport()->width(), viewport()->height()); - d->cursor_ = new frontend::CursorWidget(); - d->cursor_->hide(); + d->caret_ = new frontend::CaretWidget(); setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); setAcceptDrops(true); @@ -312,63 +316,33 @@ void GuiWorkArea::init() setFrameStyle(QFrame::NoFrame); updateWindowTitle(); - //viewport()->setAutoFillBackground(false); - // We don't need double-buffering nor SystemBackground on - // the viewport because we have our own backing pixmap. - //viewport()->setAttribute(Qt::WA_NoSystemBackground); + d->updateCursorShape(); + + // we paint our own background viewport()->setAttribute(Qt::WA_OpaquePaintEvent); setFocusPolicy(Qt::StrongFocus); - d->setCursorShape(Qt::IBeamCursor); - - // This connection is closed at the same time as this is destroyed. - d->synthetic_mouse_event_.timeout.timeout.connect([this](){ - generateSyntheticMouseEvent(); - }); - LYXERR(Debug::GUI, "viewport width: " << viewport()->width() << " viewport height: " << viewport()->height()); // Enables input methods for asian languages. // Must be set when creating custom text editing widgets. setAttribute(Qt::WA_InputMethodEnabled, true); - - d->dialog_mode_ = false; } GuiWorkArea::~GuiWorkArea() { - // If something is wrong with the buffer, we can ignore it safely - try { - d->buffer_view_->buffer().workAreaManager().remove(this); - } catch(...) {} - delete d->buffer_view_; - delete d->cursor_; - // Completer has a QObject parent and is thus automatically destroyed. - // See #4758. - // delete completer_; delete d; } -Qt::CursorShape GuiWorkArea::cursorShape() const -{ - return viewport()->cursor().shape(); -} - - -void GuiWorkArea::Private::setCursorShape(Qt::CursorShape shape) -{ - p->viewport()->setCursor(shape); -} - - void GuiWorkArea::Private::updateCursorShape() { - setCursorShape(buffer_view_->clickableInset() - ? Qt::PointingHandCursor : Qt::IBeamCursor); + bool const clickable = buffer_view_ && buffer_view_->clickableInset(); + p->viewport()->setCursor(clickable ? Qt::PointingHandCursor + : Qt::IBeamCursor); } @@ -435,14 +409,14 @@ BufferView const & GuiWorkArea::bufferView() const } -void GuiWorkArea::stopBlinkingCursor() +void GuiWorkArea::stopBlinkingCaret() { - d->cursor_timeout_.stop(); - d->hideCursor(); + d->caret_timeout_.stop(); + d->hideCaret(); } -void GuiWorkArea::startBlinkingCursor() +void GuiWorkArea::startBlinkingCaret() { // do not show the cursor if the view is busy if (view().busy()) @@ -455,14 +429,23 @@ void GuiWorkArea::startBlinkingCursor() if (!d->buffer_view_->cursorInView(p, h)) return; - d->showCursor(); + d->showCaret(); //we're not supposed to cache this value. int const time = QApplication::cursorFlashTime() / 2; if (time <= 0) return; - d->cursor_timeout_.setInterval(time); - d->cursor_timeout_.start(); + d->caret_timeout_.setInterval(time); + d->caret_timeout_.start(); +} + + +void GuiWorkArea::toggleCaret() +{ + if (d->caret_visible_) + d->hideCaret(); + else + d->showCaret(); } @@ -484,9 +467,9 @@ void GuiWorkArea::redraw(bool update_metrics) // update cursor position, because otherwise it has to wait until // the blinking interval is over - if (d->cursor_visible_) { - d->hideCursor(); - d->showCursor(); + if (d->caret_visible_) { + d->hideCaret(); + d->showCaret(); } LYXERR(Debug::WORKAREA, "WorkArea::redraw screen"); @@ -524,9 +507,9 @@ void GuiWorkArea::processKeySym(KeySymbol const & key, KeyModifier mod) } // In order to avoid bad surprise in the middle of an operation, - // we better stop the blinking cursor... - // the cursor gets restarted in GuiView::restartCursor() - stopBlinkingCursor(); + // we better stop the blinking caret... + // the cursor gets restarted in GuiView::restartCaret() + stopBlinkingCaret(); guiApp->processKeySym(key, mod); } @@ -546,7 +529,7 @@ void GuiWorkArea::Private::dispatch(FuncRequest const & cmd) // In order to avoid bad surprise in the middle of an operation, we better stop // the blinking cursor. if (notJustMovingTheMouse) - p->stopBlinkingCursor(); + p->stopBlinkingCaret(); buffer_view_->mouseEventDispatch(cmd); @@ -567,7 +550,7 @@ void GuiWorkArea::Private::dispatch(FuncRequest const & cmd) lyx_view_->clearMessage(); // Show the cursor immediately after any operation - p->startBlinkingCursor(); + p->startBlinkingCaret(); } updateCursorShape(); @@ -578,16 +561,16 @@ void GuiWorkArea::Private::resizeBufferView() { // WARNING: Please don't put any code that will trigger a repaint here! // We are already inside a paint event. - p->stopBlinkingCursor(); + p->stopBlinkingCaret(); // Warn our container (GuiView). p->busy(true); Point point; int h = 0; buffer_view_->cursorPosAndHeight(point, h); - bool const cursor_in_view = buffer_view_->cursorInView(point, h); + bool const caret_in_view = buffer_view_->cursorInView(point, h); buffer_view_->resize(p->viewport()->width(), p->viewport()->height()); - if (cursor_in_view) + if (caret_in_view) buffer_view_->scrollToCursor(); p->viewport()->update(); @@ -603,19 +586,19 @@ void GuiWorkArea::Private::resizeBufferView() // We might be resizing even if the focus is on another widget so we only // restart the cursor if we have the focus. if (p->hasFocus()) - QTimer::singleShot(50, p, SLOT(startBlinkingCursor())); + QTimer::singleShot(50, p, SLOT(startBlinkingCaret())); } -void GuiWorkArea::Private::showCursor() +void GuiWorkArea::Private::showCaret() { - if (cursor_visible_) + if (caret_visible_) return; - Point p; + Point point; int h = 0; - buffer_view_->cursorPosAndHeight(p, h); - if (!buffer_view_->cursorInView(p, h)) + buffer_view_->cursorPosAndHeight(point, h); + if (!buffer_view_->cursorInView(point, h)) return; // RTL or not RTL @@ -638,34 +621,39 @@ void GuiWorkArea::Private::showCursor() && completer_->completionAvailable() && !completer_->popupVisible() && !completer_->inlineVisible(); - cursor_visible_ = true; - cursor_->recomputeWidth(); + caret_visible_ = true; //int cur_x = buffer_view_->getPos(cur).x_; // We may have decided to slide the cursor row so that cursor // is visible. - p.x_ -= buffer_view_->horizScrollOffset(); + point.x_ -= buffer_view_->horizScrollOffset(); - showCursor(p.x_, p.y_, h, l_shape, isrtl, completable); + caret_->update(point.x_, point.y_, h, l_shape, isrtl, completable); + + if (schedule_redraw_) { + // This happens when a graphic conversion is finished. As we don't know + // the size of the new graphics, it's better the update everything. + // We can't use redraw() here because this would trigger a infinite + // recursive loop with showCaret(). + buffer_view_->resize(p->viewport()->width(), p->viewport()->height()); + p->viewport()->update(); + updateScrollbar(); + schedule_redraw_ = false; + return; + } + + p->viewport()->update(caret_->rect()); } -void GuiWorkArea::Private::hideCursor() +void GuiWorkArea::Private::hideCaret() { - if (!cursor_visible_) + if (!caret_visible_) return; - cursor_visible_ = false; - removeCursor(); -} - - -void GuiWorkArea::toggleCursor() -{ - if (d->cursor_visible_) - d->hideCursor(); - else - d->showCursor(); + caret_visible_ = false; + //if (!qApp->focusWidget()) + p->viewport()->update(caret_->rect()); } @@ -688,7 +676,7 @@ void GuiWorkArea::Private::updateScrollbar() void GuiWorkArea::scrollTo(int value) { - stopBlinkingCursor(); + stopBlinkingCaret(); d->buffer_view_->scrollDocView(value, true); if (lyxrc.cursor_follows_scrollbar) { @@ -697,7 +685,7 @@ void GuiWorkArea::scrollTo(int value) d->lyx_view_->updateLayoutList(); } // Show the cursor immediately after any operation. - startBlinkingCursor(); + startBlinkingCaret(); // FIXME QT5 #ifdef Q_WS_X11 QApplication::syncX(); @@ -803,7 +791,7 @@ void GuiWorkArea::focusInEvent(QFocusEvent * e) d->lyx_view_->currentWorkArea()->bufferView().buffer().updateBuffer(); } - startBlinkingCursor(); + startBlinkingCaret(); QAbstractScrollArea::focusInEvent(e); } @@ -811,7 +799,7 @@ void GuiWorkArea::focusInEvent(QFocusEvent * e) void GuiWorkArea::focusOutEvent(QFocusEvent * e) { LYXERR(Debug::DEBUG, "GuiWorkArea::focusOutEvent(): " << this << endl); - stopBlinkingCursor(); + stopBlinkingCaret(); QAbstractScrollArea::focusOutEvent(e); } @@ -1181,53 +1169,21 @@ void GuiWorkArea::paintEvent(QPaintEvent * ev) if (d->needResize()) { d->resizeBufferView(); - if (d->cursor_visible_) { - d->hideCursor(); - d->showCursor(); + if (d->caret_visible_) { + d->hideCaret(); + d->showCaret(); } } GuiPainter pain(viewport(), pixelRatio()); - d->buffer_view_->draw(pain, d->cursor_visible_); + d->buffer_view_->draw(pain, d->caret_visible_); - if (d->cursor_visible_) - d->cursor_->draw(pain); + if (d->caret_visible_) + d->caret_->draw(pain); ev->accept(); } -void GuiWorkArea::Private::showCursor(int x, int y, int h, - bool l_shape, bool rtl, bool completable) -{ - if (schedule_redraw_) { - // This happens when a graphic conversion is finished. As we don't know - // the size of the new graphics, it's better the update everything. - // We can't use redraw() here because this would trigger a infinite - // recursive loop with showCursor(). - buffer_view_->resize(p->viewport()->width(), p->viewport()->height()); - p->viewport()->update(); - updateScrollbar(); - schedule_redraw_ = false; - // Show the cursor immediately after the update. - hideCursor(); - p->toggleCursor(); - return; - } - - cursor_->update(x, y, h, l_shape, rtl, completable); - cursor_->show(); - p->viewport()->update(cursor_->rect()); -} - - -void GuiWorkArea::Private::removeCursor() -{ - cursor_->hide(); - //if (!qApp->focusWidget()) - p->viewport()->update(cursor_->rect()); -} - - void GuiWorkArea::inputMethodEvent(QInputMethodEvent * e) { //FIXME Broken Feature !! @@ -1254,9 +1210,9 @@ void GuiWorkArea::inputMethodEvent(QInputMethodEvent * e) // Hide the cursor during the kana-kanji transformation. if (preedit_string.empty()) - startBlinkingCursor(); + startBlinkingCaret(); else - stopBlinkingCursor(); + stopBlinkingCaret(); // last_width : for checking if last preedit string was/wasn't empty. // FIXME THREAD && FIXME @@ -1274,8 +1230,8 @@ void GuiWorkArea::inputMethodEvent(QInputMethodEvent * e) FontInfo font = d->buffer_view_->cursor().getFont().fontInfo(); FontMetrics const & fm = theFontMetrics(font); int height = fm.maxHeight(); - int cur_x = d->cursor_->rect().left(); - int cur_y = d->cursor_->rect().bottom(); + int cur_x = d->caret_->rect().left(); + int cur_y = d->caret_->rect().bottom(); // redraw area of preedit string. viewport()->update(0, cur_y - height, viewport()->width(), @@ -1295,7 +1251,7 @@ void GuiWorkArea::inputMethodEvent(QInputMethodEvent * e) // get attributes of input method cursor. // cursor_pos : cursor position in preedit string. size_t cursor_pos = 0; - bool cursor_is_visible = false; + bool caret_is_visible = false; for (int i = 0; i != att.size(); ++i) { if (att.at(i).type == QInputMethodEvent::Cursor) { cursor_pos = att.at(i).start; @@ -1382,7 +1338,7 @@ QVariant GuiWorkArea::inputMethodQuery(Qt::InputMethodQuery query) const // this is the CJK-specific composition window position and // the context menu position when the menu key is pressed. case Qt::ImMicroFocus: - cur_r = d->cursor_->rect(); + cur_r = d->caret_->rect(); if (d->preedit_lines_ != 1) cur_r.moveLeft(10); cur_r.moveBottom(cur_r.bottom() @@ -1509,7 +1465,7 @@ QSize EmbeddedWorkArea::sizeHint () const void EmbeddedWorkArea::disable() { - stopBlinkingCursor(); + stopBlinkingCaret(); if (view().currentWorkArea() != this) return; // No problem if currentMainWorkArea() is 0 (setCurrentWorkArea() diff --git a/src/frontends/qt4/GuiWorkArea.h b/src/frontends/qt4/GuiWorkArea.h index 34b5d3aa4d..596b975c04 100644 --- a/src/frontends/qt4/GuiWorkArea.h +++ b/src/frontends/qt4/GuiWorkArea.h @@ -27,10 +27,6 @@ class QDropEvent; class QToolButton; class QWidget; -#ifdef CursorShape -#undef CursorShape -#endif - namespace lyx { class Buffer; @@ -81,8 +77,6 @@ public: /// GuiCompleter & completer(); - Qt::CursorShape cursorShape() const; - /// Return the GuiView this workArea belongs to GuiView const & view() const; GuiView & view(); @@ -95,9 +89,9 @@ public Q_SLOTS: /// This needs to be public because it is accessed externally by GuiView. void processKeySym(KeySymbol const & key, KeyModifier mod); /// - void stopBlinkingCursor(); + void stopBlinkingCaret(); /// - void startBlinkingCursor(); + void startBlinkingCaret(); Q_SIGNALS: /// @@ -119,7 +113,7 @@ private Q_SLOTS: /// timer to limit triple clicks void doubleClickTimeout(); /// toggle the cursor's visibility - void toggleCursor(); + void toggleCaret(); /// close this work area. /// Slot for Buffer::closing signal. void close(); diff --git a/src/frontends/qt4/GuiWorkArea_Private.h b/src/frontends/qt4/GuiWorkArea_Private.h index 42597172b1..cae768a689 100644 --- a/src/frontends/qt4/GuiWorkArea_Private.h +++ b/src/frontends/qt4/GuiWorkArea_Private.h @@ -13,30 +13,13 @@ #define WORKAREA_PRIVATE_H #include "FuncRequest.h" -#include "LyXRC.h" #include "support/FileName.h" #include "support/Timeout.h" #include -#include -#include #include -class QContextMenuEvent; -class QDragEnterEvent; -class QDropEvent; -class QKeyEvent; -class QPaintEvent; -class QResizeEvent; -class QToolButton; -class QWheelEvent; -class QWidget; - -#ifdef CursorShape -#undef CursorShape -#endif - namespace lyx { class Buffer; @@ -86,34 +69,30 @@ public: /** * Implementation of the work area (buffer view GUI) */ -class CursorWidget; +class CaretWidget; struct GuiWorkArea::Private { + /// Private(GuiWorkArea *); + /// + ~Private(); + /// void resizeBufferView(); - /// paint the cursor and store the background - void showCursor(int x, int y, int h, - bool l_shape, bool rtl, bool completable); - - /// hide the cursor - void removeCursor(); /// void dispatch(FuncRequest const & cmd0); /// hide the visible cursor, if it is visible - void hideCursor(); + void hideCaret(); /// show the cursor if it is not visible - void showCursor(); + void showCaret(); /// Set the range and value of the scrollbar and connect to its valueChanged /// signal. void updateScrollbar(); /// Change the cursor when the mouse hovers over a clickable inset void updateCursorShape(); - /// - void setCursorShape(Qt::CursorShape shape); bool needResize() const { return need_resize_ || p->pixelRatio() != pixel_ratio_; @@ -125,18 +104,19 @@ struct GuiWorkArea::Private BufferView * buffer_view_; /// GuiView * lyx_view_; - /// is the cursor currently displayed - bool cursor_visible_; /// - QTimer cursor_timeout_; + CaretWidget * caret_; + /// is the cursor currently displayed + bool caret_visible_; + /// + QTimer caret_timeout_; + /// SyntheticMouseEvent synthetic_mouse_event_; /// DoubleClick dc_event_; - /// - CursorWidget * cursor_; /// bool need_resize_; /// From 9ef52806f8ff80bf1325368f07ba07a83172f7da Mon Sep 17 00:00:00 2001 From: Jean-Marc Lasgouttes Date: Sun, 23 Jul 2017 00:56:27 +0200 Subject: [PATCH 014/121] Make input methods support great again This unbreaks input methods by splitting the part of the code that does the actual drawing to a separate paintPreeditText() method which is called from paintEvent(). The proper solution would have been to introduce the preedit string in the Row object, like is done for completion, but this is too complex to do at this point. The only change in behavior is that now the commit string is inserted in one fell swoop, intead of emulating a number of key events. --- src/frontends/qt4/GuiWorkArea.cpp | 194 ++++++++++++------------ src/frontends/qt4/GuiWorkArea_Private.h | 11 +- 2 files changed, 103 insertions(+), 102 deletions(-) diff --git a/src/frontends/qt4/GuiWorkArea.cpp b/src/frontends/qt4/GuiWorkArea.cpp index 6773412cb0..c7f62c4db5 100644 --- a/src/frontends/qt4/GuiWorkArea.cpp +++ b/src/frontends/qt4/GuiWorkArea.cpp @@ -39,6 +39,7 @@ #include "LyXVC.h" #include "Text.h" #include "TextMetrics.h" +#include "Undo.h" #include "version.h" #include "graphics/GraphicsImage.h" @@ -1162,105 +1163,31 @@ void GuiWorkArea::resizeEvent(QResizeEvent * ev) } -void GuiWorkArea::paintEvent(QPaintEvent * ev) +void GuiWorkArea::Private::paintPreeditText(GuiPainter & pain) { - // LYXERR(Debug::PAINTING, "paintEvent begin: x: " << rc.x() - // << " y: " << rc.y() << " w: " << rc.width() << " h: " << rc.height()); - - if (d->needResize()) { - d->resizeBufferView(); - if (d->caret_visible_) { - d->hideCaret(); - d->showCaret(); - } - } - - GuiPainter pain(viewport(), pixelRatio()); - d->buffer_view_->draw(pain, d->caret_visible_); - - if (d->caret_visible_) - d->caret_->draw(pain); - ev->accept(); -} - - -void GuiWorkArea::inputMethodEvent(QInputMethodEvent * e) -{ -//FIXME Broken Feature !! -// I do not think that we are supposed to paint inside this event. Shall we -// just let TextMetrics::breakRow add this to the relevant Row object? -#if 0 - QString const & commit_string = e->commitString(); - docstring const & preedit_string - = qstring_to_ucs4(e->preeditString()); - - if (!commit_string.isEmpty()) { - - LYXERR(Debug::KEY, "preeditString: " << e->preeditString() - << " commitString: " << e->commitString()); - - int key = 0; - - // FIXME Iwami 04/01/07: we should take care also of UTF16 surrogates here. - for (int i = 0; i != commit_string.size(); ++i) { - QKeyEvent ev(QEvent::KeyPress, key, Qt::NoModifier, commit_string[i]); - keyPressEvent(&ev); - } - } - - // Hide the cursor during the kana-kanji transformation. - if (preedit_string.empty()) - startBlinkingCaret(); - else - stopBlinkingCaret(); - - // last_width : for checking if last preedit string was/wasn't empty. - // FIXME THREAD && FIXME - // We could have more than one work area, right? - static bool last_width = false; - if (!last_width && preedit_string.empty()) { - // if last_width is last length of preedit string. - e->accept(); + if (preedit_string_.empty()) return; - } - d->buffer_view_->updateMetrics(); - viewport()->update(); // FIXME: shall we use real_current_font here? (see #10478) - FontInfo font = d->buffer_view_->cursor().getFont().fontInfo(); + FontInfo const font = buffer_view_->cursor().getFont().fontInfo(); FontMetrics const & fm = theFontMetrics(font); - int height = fm.maxHeight(); - int cur_x = d->caret_->rect().left(); - int cur_y = d->caret_->rect().bottom(); - - // redraw area of preedit string. - viewport()->update(0, cur_y - height, viewport()->width(), - (height + 1) * d->preedit_lines_); - - if (preedit_string.empty()) { - last_width = false; - d->preedit_lines_ = 1; - e->accept(); - return; - } - last_width = true; - - // att : stores an IM attribute. - QList const & att = e->attributes(); + int const height = fm.maxHeight(); + int cur_x = caret_->rect().left(); + int cur_y = caret_->rect().bottom(); // get attributes of input method cursor. // cursor_pos : cursor position in preedit string. size_t cursor_pos = 0; - bool caret_is_visible = false; - for (int i = 0; i != att.size(); ++i) { - if (att.at(i).type == QInputMethodEvent::Cursor) { - cursor_pos = att.at(i).start; - cursor_is_visible = att.at(i).length != 0; + bool cursor_is_visible = false; + for (auto const & attr : preedit_attr_) { + if (attr.type == QInputMethodEvent::Cursor) { + cursor_pos = attr.start; + cursor_is_visible = attr.length != 0; break; } } - size_t preedit_length = preedit_string.length(); + size_t const preedit_length = preedit_string_.length(); // get position of selection in input method. // FIXME: isn't there a way to do this simplier? @@ -1269,12 +1196,12 @@ void GuiWorkArea::inputMethodEvent(QInputMethodEvent * e) // rLength : selected string length in IM. size_t rLength = 0; if (cursor_pos < preedit_length) { - for (int i = 0; i != att.size(); ++i) { - if (att.at(i).type == QInputMethodEvent::TextFormat) { - if (att.at(i).start <= int(cursor_pos) - && int(cursor_pos) < att.at(i).start + att.at(i).length) { - rStart = att.at(i).start; - rLength = att.at(i).length; + for (auto const & attr : preedit_attr_) { + if (attr.type == QInputMethodEvent::TextFormat) { + if (attr.start <= int(cursor_pos) + && int(cursor_pos) < attr.start + attr.length) { + rStart = attr.start; + rLength = attr.length; if (!cursor_is_visible) cursor_pos += rLength; break; @@ -1287,20 +1214,20 @@ void GuiWorkArea::inputMethodEvent(QInputMethodEvent * e) rLength = 0; } - int const right_margin = d->buffer_view_->rightMargin(); + int const right_margin = buffer_view_->rightMargin(); Painter::preedit_style ps; // Most often there would be only one line: - d->preedit_lines_ = 1; + preedit_lines_ = 1; for (size_t pos = 0; pos != preedit_length; ++pos) { - char_type const typed_char = preedit_string[pos]; + char_type const typed_char = preedit_string_[pos]; // reset preedit string style ps = Painter::preedit_default; // if we reached the right extremity of the screen, go to next line. - if (cur_x + fm.width(typed_char) > viewport()->width() - right_margin) { + if (cur_x + fm.width(typed_char) > p->viewport()->width() - right_margin) { cur_x = right_margin; cur_y += height + 1; - ++d->preedit_lines_; + ++preedit_lines_; } // preedit strings are displayed with dashed underline // and partial strings are displayed white on black indicating @@ -1317,14 +1244,79 @@ void GuiWorkArea::inputMethodEvent(QInputMethodEvent * e) ps = Painter::preedit_cursor; // draw one character and update cur_x. - GuiPainter pain(d->screen_, pixelRatio()); cur_x += pain.preeditText(cur_x, cur_y, typed_char, font, ps); } +} - // update the preedit string screen area. - viewport()->update(0, cur_y - d->preedit_lines_*height, viewport()->width(), + +void GuiWorkArea::paintEvent(QPaintEvent * ev) +{ + // LYXERR(Debug::PAINTING, "paintEvent begin: x: " << rc.x() + // << " y: " << rc.y() << " w: " << rc.width() << " h: " << rc.height()); + + if (d->needResize()) { + d->resizeBufferView(); + if (d->caret_visible_) { + d->hideCaret(); + d->showCaret(); + } + } + + GuiPainter pain(viewport(), pixelRatio()); + d->buffer_view_->draw(pain, d->caret_visible_); + + // The preedit text, if needed + d->paintPreeditText(pain); + + // and the caret + if (d->caret_visible_) + d->caret_->draw(pain); + ev->accept(); +} + + +void GuiWorkArea::inputMethodEvent(QInputMethodEvent * e) +{ + LYXERR(Debug::KEY, "preeditString: " << e->preeditString() + << " commitString: " << e->commitString()); + + // insert the processed text in the document (handles undo) + if (!e->commitString().isEmpty()) { + d->buffer_view_->cursor().beginUndoGroup(); + d->buffer_view_->cursor().insert(qstring_to_ucs4(e->commitString())); + d->buffer_view_->updateMetrics(); + d->buffer_view_->cursor().endUndoGroup(); + viewport()->update(); + } + + // Hide the cursor during the test transformation. + if (e->preeditString().isEmpty()) + startBlinkingCaret(); + else + stopBlinkingCaret(); + + if (d->preedit_string_.empty() && e->preeditString().isEmpty()) { + // Nothing to do + e->accept(); + return; + } + + // The preedit text and its attributes will be used in paintPreeditText + d->preedit_string_ = qstring_to_ucs4(e->preeditString()); + d->preedit_attr_ = e->attributes(); + + + // redraw area of preedit string. + int height = d->caret_->rect().height(); + int cur_y = d->caret_->rect().bottom(); + viewport()->update(0, cur_y - height, viewport()->width(), (height + 1) * d->preedit_lines_); -#endif + + if (d->preedit_string_.empty()) { + d->preedit_lines_ = 1; + e->accept(); + return; + } // Don't forget to accept the event! e->accept(); diff --git a/src/frontends/qt4/GuiWorkArea_Private.h b/src/frontends/qt4/GuiWorkArea_Private.h index cae768a689..7198c569fe 100644 --- a/src/frontends/qt4/GuiWorkArea_Private.h +++ b/src/frontends/qt4/GuiWorkArea_Private.h @@ -27,6 +27,7 @@ class Buffer; namespace frontend { class GuiCompleter; +class GuiPainter; class GuiView; class GuiWorkArea; @@ -94,6 +95,8 @@ struct GuiWorkArea::Private /// Change the cursor when the mouse hovers over a clickable inset void updateCursorShape(); + void paintPreeditText(GuiPainter & pain); + bool needResize() const { return need_resize_ || p->pixelRatio() != pixel_ratio_; } @@ -121,8 +124,14 @@ struct GuiWorkArea::Private bool need_resize_; /// bool schedule_redraw_; - /// + + /// the current preedit text of the input method + docstring preedit_string_; + /// Number of lines used by preedit text int preedit_lines_; + /// the attributes of the preedit text + QList preedit_attr_; + /// Ratio between physical pixels and device-independent pixels /// We save the last used value to detect changes of the /// current pixel_ratio of the viewport. From 8bb7ce4e4a25622b91208e18702fbd52c59bf16f Mon Sep 17 00:00:00 2001 From: Jean-Marc Lasgouttes Date: Sun, 23 Jul 2017 12:39:26 +0200 Subject: [PATCH 015/121] Update the painting process documentation --- development/PAINTING_ANALYSIS | 44 +++++++++++------------------------ 1 file changed, 14 insertions(+), 30 deletions(-) diff --git a/development/PAINTING_ANALYSIS b/development/PAINTING_ANALYSIS index e53b4b23df..9d625934bb 100644 --- a/development/PAINTING_ANALYSIS +++ b/development/PAINTING_ANALYSIS @@ -67,31 +67,11 @@ drawing from metrics. Other changes are only clean-ups. ** When a paragraph ends with a newline, compute correctly the height of the extra row. -** Rewrite TextMetrics::editXY, checkInsetHit using row information (getPosNearX)? - - The helper version should return a Row::Element instead of an InsetTable. - -** Set inset position during metrics phase - -In order to do that, a no-paint drawing will be initiated after every -redoParagraph. This code path will need to be made as fast as possible. - -Effect: avoid depending on actual drawing having taken place. In turn, -it will allow to do drawing on paint events, like any reasonable -application would do. - ** Cleanup after complete metrics Then the following can be done: + remove hack in InsetMathNest::drawSelection - + remove painting when not inside in drawParagraph + remove Cursor::inCoordCache? -** Paint directly to screen - -Instead of using an intermediary pixmap. I have no idea of how -difficult it will prove. -One benefit will be that subpixel aliasing will work again (#9972) - ** Merging bv::updateMetrics and tm::metrics While the full metrics computation tries hard to limit the number of @@ -107,19 +87,19 @@ necessary to break the whole contents to know the width of the cell. * Description of current drawing mechanism -** Two stage drawing +** Three-stage drawing -There are two parts to drawing the work area: +There are three parts to drawing the work area: + the metrics phase computes the size of insets and breaks the paragraphs into rows. It stores the dimension of insets (both normal and math) in bv::coordCache. - + the drawing phase draws the contents and caches the inset - positions. Since the caching of positions is useful in itself, - there is a provision for drawing "without" drawing when the only - thing we want is to cache inset positions - (Painter::setDrawingEnabled). + + the nodraw drawing phase paints the screen (see below) with a null + painter. The only useful effect is to store the inset positions. + + + an update() signal is sent. This in turn will trigger a paint + event, and the actual screen painting will happen then. The machinery is controlled via bv::processUpdateFlags. This method is called at the end of bv::mouseEventDispatch and in @@ -145,7 +125,7 @@ update flag is Update::None. ** Metrics computation This is triggered by bv::updateMetrics, which calls tm::redoParagraph for -all visible paragraphs. Paragraphs above or below the screen (needed +all visible paragraphs. Some Paragraphs above or below the screen (needed for page up/down) and computed as needed. tm::redoParagraph will call Inset::metrics for each inset. In the case @@ -155,8 +135,9 @@ all the paragraphs of the inset. ** Drawing the work area. -This is done in bv::draw. This method is triggered mainly by -Buffer::changed, which draws all the work areas that show the given buffer. +This is done in bv::draw. This method is triggered by a paint event, +mainly called through Buffer::changed, which draws all the work areas +that show the given buffer. Note that, When Buffer::changed is called outside of bv::processUpdateFlags, it is not clear whether the update strategy @@ -186,3 +167,6 @@ The action depends on the update strategy: + SingleParUpdate: only tries to repaint current paragraph in a way that is not yet very clear to me. + +BufferView::draw can also be called with a null painter from +BufferView::updateMetrics(). From 410605385f1f40d3381fc7236dfb468d100d94f8 Mon Sep 17 00:00:00 2001 From: Jean-Marc Lasgouttes Date: Sun, 23 Jul 2017 15:50:35 +0200 Subject: [PATCH 016/121] Remove workaround that is not necessary anymore. This code was necessary to handle cases where the insets positions were not yet in cache. This cannot happen anymore thanks to the nodraw stage. --- development/PAINTING_ANALYSIS | 5 ----- src/BufferView.cpp | 32 ++------------------------------ src/BufferView.h | 3 +-- src/Cursor.cpp | 13 ------------- src/Cursor.h | 2 -- 5 files changed, 3 insertions(+), 52 deletions(-) diff --git a/development/PAINTING_ANALYSIS b/development/PAINTING_ANALYSIS index 9d625934bb..f734edb3b0 100644 --- a/development/PAINTING_ANALYSIS +++ b/development/PAINTING_ANALYSIS @@ -67,11 +67,6 @@ drawing from metrics. Other changes are only clean-ups. ** When a paragraph ends with a newline, compute correctly the height of the extra row. -** Cleanup after complete metrics - Then the following can be done: - + remove hack in InsetMathNest::drawSelection - + remove Cursor::inCoordCache? - ** Merging bv::updateMetrics and tm::metrics While the full metrics computation tries hard to limit the number of diff --git a/src/BufferView.cpp b/src/BufferView.cpp index 3c6adfcd74..68ba3d7475 100644 --- a/src/BufferView.cpp +++ b/src/BufferView.cpp @@ -2982,7 +2982,7 @@ bool BufferView::needRepaint(Text const * text, Row const & row) const } -void BufferView::checkCursorScrollOffset(PainterInfo & pi) +void BufferView::checkCursorScrollOffset() { CursorSlice rowSlice = d->cursor_.bottom(); TextMetrics const & tm = textMetrics(rowSlice.text()); @@ -2999,34 +2999,6 @@ void BufferView::checkCursorScrollOffset(PainterInfo & pi) // Set the row on which the cursor lives. setCurrentRowSlice(rowSlice); - // If insets referred to by cursor are not all in the cache, the positions - // need to be recomputed. - if (!d->cursor_.inCoordCache()) { - /** FIXME: the code below adds an extraneous computation of - * inset positions, and can therefore be bad for performance - * (think for example about a very large tabular inset. - * Redawing the row where it is means redrawing the whole - * screen). - * - * The bug that this fixes is the following: assume that there - * is a very large math inset. Upon entering the inset, when - * pressing `End', the row is not scrolled and the cursor is - * not visible. The extra row computation makes sure that the - * inset positions are correctly computed and set in the - * cache. This would not happen if we did not have two-stage - * drawing. - * - * A proper fix would be to always have proper inset positions - * at this point. - */ - // Force the recomputation of inset positions - frontend::NullPainter np; - PainterInfo(this, np); - // No need to care about vertical position. - RowPainter rp(pi, buffer().text(), row, -d->horiz_scroll_offset_, 0); - rp.paintText(); - } - // Current x position of the cursor in pixels int cur_x = getPos(d->cursor_).x_; @@ -3093,7 +3065,7 @@ void BufferView::draw(frontend::Painter & pain, bool paint_caret) // Check whether the row where the cursor lives needs to be scrolled. // Update the drawing strategy if needed. - checkCursorScrollOffset(pi); + checkCursorScrollOffset(); switch (d->update_strategy_) { diff --git a/src/BufferView.h b/src/BufferView.h index eed408dae7..1c155685a5 100644 --- a/src/BufferView.h +++ b/src/BufferView.h @@ -42,7 +42,6 @@ class FuncStatus; class Intl; class Inset; class Length; -class PainterInfo; class ParIterator; class ParagraphMetrics; class Point; @@ -374,7 +373,7 @@ private: // Check whether the row where the cursor lives needs to be scrolled. // Update the drawing strategy if needed. - void checkCursorScrollOffset(PainterInfo & pi); + void checkCursorScrollOffset(); /// The minimal size of the document that is visible. Used /// when it is allowed to scroll below the document. diff --git a/src/Cursor.cpp b/src/Cursor.cpp index 2e8060509d..11ee5ea535 100644 --- a/src/Cursor.cpp +++ b/src/Cursor.cpp @@ -453,19 +453,6 @@ int Cursor::currentMode() } -bool Cursor::inCoordCache() const -{ - // the root inset is not in cache, but we do not need it. - if (depth() == 1) - return true; - CoordCache::Insets const & icache = bv_->coordCache().getInsets(); - for (size_t i = 1 ; i < depth() ; ++i) - if (!icache.has(&(*this)[i].inset())) - return false; - return true; -} - - void Cursor::getPos(int & x, int & y) const { Point p = bv().getPos(*this); diff --git a/src/Cursor.h b/src/Cursor.h index 8a8c71996d..5fb52638b7 100644 --- a/src/Cursor.h +++ b/src/Cursor.h @@ -215,8 +215,6 @@ public: /// are we entering a macro name? bool & macromode() { return macromode_; } - /// returns true when all insets in cursor stack are in cache - bool inCoordCache() const; /// returns x,y position void getPos(int & x, int & y) const; /// return logical positions between which the cursor is situated From 94b1d04f2c379291748365a296f2b6378d617f4a Mon Sep 17 00:00:00 2001 From: Jean-Marc Lasgouttes Date: Thu, 24 Aug 2017 17:37:56 +0200 Subject: [PATCH 017/121] Rename more instances of "cursor" to "caret" Thanks to Pavel for the hint. --- src/BufferView.cpp | 2 +- src/BufferView.h | 4 ++-- src/frontends/qt4/GuiWorkArea.cpp | 31 +++++++++++++------------ src/frontends/qt4/GuiWorkArea.h | 2 +- src/frontends/qt4/GuiWorkArea_Private.h | 6 ++--- 5 files changed, 23 insertions(+), 22 deletions(-) diff --git a/src/BufferView.cpp b/src/BufferView.cpp index 68ba3d7475..96c7dfe55f 100644 --- a/src/BufferView.cpp +++ b/src/BufferView.cpp @@ -2892,7 +2892,7 @@ bool BufferView::paragraphVisible(DocIterator const & dit) const } -void BufferView::cursorPosAndHeight(Point & p, int & h) const +void BufferView::caretPosAndHeight(Point & p, int & h) const { Cursor const & cur = cursor(); Font const font = cur.real_current_font; diff --git a/src/BufferView.h b/src/BufferView.h index 1c155685a5..a5222599f2 100644 --- a/src/BufferView.h +++ b/src/BufferView.h @@ -307,8 +307,8 @@ public: bool paragraphVisible(DocIterator const & dit) const; /// is the cursor currently visible in the view bool cursorInView(Point const & p, int h) const; - /// get the position and height of the cursor - void cursorPosAndHeight(Point & p, int & h) const; + /// get the position and height of the caret + void caretPosAndHeight(Point & p, int & h) const; /// void draw(frontend::Painter & pain, bool paint_caret); diff --git a/src/frontends/qt4/GuiWorkArea.cpp b/src/frontends/qt4/GuiWorkArea.cpp index c7f62c4db5..70dcf3b32c 100644 --- a/src/frontends/qt4/GuiWorkArea.cpp +++ b/src/frontends/qt4/GuiWorkArea.cpp @@ -198,6 +198,7 @@ public: r = max(r, TabIndicatorWidth); } + //FIXME: LyXRC::cursor_width should be caret_width caret_width_ = lyxrc.cursor_width ? lyxrc.cursor_width : 1 + int((lyxrc.currentZoom + 50) / 200.0); @@ -209,7 +210,7 @@ public: QRect const & rect() { return rect_; } private: - /// cursor is in RTL or LTR text + /// caret is in RTL or LTR text bool rtl_; /// indication for RTL or LTR bool l_shape_; @@ -425,7 +426,7 @@ void GuiWorkArea::startBlinkingCaret() Point p; int h = 0; - d->buffer_view_->cursorPosAndHeight(p, h); + d->buffer_view_->caretPosAndHeight(p, h); // Don't start blinking if the cursor isn't on screen. if (!d->buffer_view_->cursorInView(p, h)) return; @@ -466,7 +467,7 @@ void GuiWorkArea::redraw(bool update_metrics) d->buffer_view_->cursor().fixIfBroken(); } - // update cursor position, because otherwise it has to wait until + // update caret position, because otherwise it has to wait until // the blinking interval is over if (d->caret_visible_) { d->hideCaret(); @@ -509,7 +510,7 @@ void GuiWorkArea::processKeySym(KeySymbol const & key, KeyModifier mod) // In order to avoid bad surprise in the middle of an operation, // we better stop the blinking caret... - // the cursor gets restarted in GuiView::restartCaret() + // the caret gets restarted in GuiView::restartCaret() stopBlinkingCaret(); guiApp->processKeySym(key, mod); } @@ -528,7 +529,7 @@ void GuiWorkArea::Private::dispatch(FuncRequest const & cmd) cmd.action() != LFUN_MOUSE_MOTION || cmd.button() != mouse_button::none; // In order to avoid bad surprise in the middle of an operation, we better stop - // the blinking cursor. + // the blinking caret. if (notJustMovingTheMouse) p->stopBlinkingCaret(); @@ -550,7 +551,7 @@ void GuiWorkArea::Private::dispatch(FuncRequest const & cmd) // FIXME: let GuiView take care of those. lyx_view_->clearMessage(); - // Show the cursor immediately after any operation + // Show the caret immediately after any operation p->startBlinkingCaret(); } @@ -568,7 +569,7 @@ void GuiWorkArea::Private::resizeBufferView() Point point; int h = 0; - buffer_view_->cursorPosAndHeight(point, h); + buffer_view_->caretPosAndHeight(point, h); bool const caret_in_view = buffer_view_->cursorInView(point, h); buffer_view_->resize(p->viewport()->width(), p->viewport()->height()); if (caret_in_view) @@ -583,9 +584,9 @@ void GuiWorkArea::Private::resizeBufferView() need_resize_ = false; p->busy(false); - // Eventually, restart the cursor after the resize event. + // Eventually, restart the caret after the resize event. // We might be resizing even if the focus is on another widget so we only - // restart the cursor if we have the focus. + // restart the caret if we have the focus. if (p->hasFocus()) QTimer::singleShot(50, p, SLOT(startBlinkingCaret())); } @@ -598,7 +599,7 @@ void GuiWorkArea::Private::showCaret() Point point; int h = 0; - buffer_view_->cursorPosAndHeight(point, h); + buffer_view_->caretPosAndHeight(point, h); if (!buffer_view_->cursorInView(point, h)) return; @@ -616,7 +617,7 @@ void GuiWorkArea::Private::showCaret() if (realfont.language() == latex_language) l_shape = false; - // show cursor on screen + // show caret on screen Cursor & cur = buffer_view_->cursor(); bool completable = cur.inset().showCompletionCursor() && completer_->completionAvailable() @@ -625,7 +626,7 @@ void GuiWorkArea::Private::showCaret() caret_visible_ = true; //int cur_x = buffer_view_->getPos(cur).x_; - // We may have decided to slide the cursor row so that cursor + // We may have decided to slide the cursor row so that caret // is visible. point.x_ -= buffer_view_->horizScrollOffset(); @@ -685,7 +686,7 @@ void GuiWorkArea::scrollTo(int value) // FIXME: let GuiView take care of those. d->lyx_view_->updateLayoutList(); } - // Show the cursor immediately after any operation. + // Show the caret immediately after any operation. startBlinkingCaret(); // FIXME QT5 #ifdef Q_WS_X11 @@ -1289,7 +1290,7 @@ void GuiWorkArea::inputMethodEvent(QInputMethodEvent * e) viewport()->update(); } - // Hide the cursor during the test transformation. + // Hide the caret during the test transformation. if (e->preeditString().isEmpty()) startBlinkingCaret(); else @@ -1335,7 +1336,7 @@ QVariant GuiWorkArea::inputMethodQuery(Qt::InputMethodQuery query) const cur_r.moveLeft(10); cur_r.moveBottom(cur_r.bottom() + cur_r.height() * (d->preedit_lines_ - 1)); - // return lower right of cursor in LyX. + // return lower right of caret in LyX. return cur_r; default: return QWidget::inputMethodQuery(query); diff --git a/src/frontends/qt4/GuiWorkArea.h b/src/frontends/qt4/GuiWorkArea.h index 596b975c04..63a9c8364e 100644 --- a/src/frontends/qt4/GuiWorkArea.h +++ b/src/frontends/qt4/GuiWorkArea.h @@ -112,7 +112,7 @@ private Q_SLOTS: void scrollTo(int value); /// timer to limit triple clicks void doubleClickTimeout(); - /// toggle the cursor's visibility + /// toggle the caret's visibility void toggleCaret(); /// close this work area. /// Slot for Buffer::closing signal. diff --git a/src/frontends/qt4/GuiWorkArea_Private.h b/src/frontends/qt4/GuiWorkArea_Private.h index 7198c569fe..199ce253d6 100644 --- a/src/frontends/qt4/GuiWorkArea_Private.h +++ b/src/frontends/qt4/GuiWorkArea_Private.h @@ -85,9 +85,9 @@ struct GuiWorkArea::Private /// void dispatch(FuncRequest const & cmd0); - /// hide the visible cursor, if it is visible + /// hide the visible caret, if it is visible void hideCaret(); - /// show the cursor if it is not visible + /// show the caret if it is not visible void showCaret(); /// Set the range and value of the scrollbar and connect to its valueChanged /// signal. @@ -110,7 +110,7 @@ struct GuiWorkArea::Private /// CaretWidget * caret_; - /// is the cursor currently displayed + /// is the caret currently displayed bool caret_visible_; /// QTimer caret_timeout_; From 9bb41f09436ad23fb881dd87e2caf3628b03403f Mon Sep 17 00:00:00 2001 From: Jean-Marc Lasgouttes Date: Wed, 30 Aug 2017 18:05:16 +0200 Subject: [PATCH 018/121] Update insets position in cache in more cases This patch makes sure that, every time a ParagraphMetrics has its position set, the inset positions for the insets held by this paragraph are remembered too. This is complementary to BufferView::updatePosCache, but I do not have hard evidence that this is required other than to increase robustness. It may help in some cases when scrolling the document (scrollbar, cursor up/down, page up/down). --- src/BufferView.cpp | 4 ++++ src/TextMetrics.cpp | 11 +++++++++++ src/TextMetrics.h | 5 +++++ 3 files changed, 20 insertions(+) diff --git a/src/BufferView.cpp b/src/BufferView.cpp index 96c7dfe55f..58e4f8640f 100644 --- a/src/BufferView.cpp +++ b/src/BufferView.cpp @@ -2645,6 +2645,7 @@ bool BufferView::singleParUpdate() // the singlePar optimisation. return false; + tm.updatePosCache(bottom_pit); d->update_strategy_ = SingleParUpdate; LYXERR(Debug::PAINTING, "\ny1: " << pm.position() - pm.ascent() @@ -2698,6 +2699,7 @@ void BufferView::updateMetrics() } } anchor_pm.setPosition(d->anchor_ypos_); + tm.updatePosCache(d->anchor_pit_); LYXERR(Debug::PAINTING, "metrics: " << " anchor pit = " << d->anchor_pit_ @@ -2713,6 +2715,7 @@ void BufferView::updateMetrics() y1 -= pm.descent(); // Save the paragraph position in the cache. pm.setPosition(y1); + tm.updatePosCache(pit1); y1 -= pm.ascent(); } @@ -2726,6 +2729,7 @@ void BufferView::updateMetrics() y2 += pm.ascent(); // Save the paragraph position in the cache. pm.setPosition(y2); + tm.updatePosCache(pit2); y2 += pm.descent(); } diff --git a/src/TextMetrics.cpp b/src/TextMetrics.cpp index 52717400d5..5eb85bf118 100644 --- a/src/TextMetrics.cpp +++ b/src/TextMetrics.cpp @@ -43,6 +43,7 @@ #include "frontends/FontMetrics.h" #include "frontends/Painter.h" +#include "frontends/NullPainter.h" #include "support/debug.h" #include "support/lassert.h" @@ -198,6 +199,14 @@ bool TextMetrics::metrics(MetricsInfo & mi, Dimension & dim, int min_width) } +void TextMetrics::updatePosCache(pit_type pit) const +{ + frontend::NullPainter np; + PainterInfo pi(bv_, np); + drawParagraph(pi, pit, origin_.x_, par_metrics_[pit].position()); +} + + int TextMetrics::rightMargin(ParagraphMetrics const & pm) const { return text_->isMainText() ? pm.rightMargin(*bv_) : 0; @@ -1214,6 +1223,7 @@ void TextMetrics::newParMetricsDown() redoParagraph(pit); par_metrics_[pit].setPosition(last.second.position() + last.second.descent() + par_metrics_[pit].ascent()); + updatePosCache(pit); } @@ -1228,6 +1238,7 @@ void TextMetrics::newParMetricsUp() redoParagraph(pit); par_metrics_[pit].setPosition(first.second.position() - first.second.ascent() - par_metrics_[pit].descent()); + updatePosCache(pit); } // y is screen coordinate diff --git a/src/TextMetrics.h b/src/TextMetrics.h index 3000b218bf..ae99490955 100644 --- a/src/TextMetrics.h +++ b/src/TextMetrics.h @@ -62,6 +62,11 @@ public: /// void newParMetricsUp(); + /// The "nodraw" drawing stage for one single paragraph: set the + /// positions of the insets contained this paragraph in metrics + /// cache. Related to BufferView::updatePosCache. + void updatePosCache(pit_type pit) const; + /// Gets the fully instantiated font at a given position in a paragraph /// Basically the same routine as Paragraph::getFont() in Paragraph.cpp. /// The difference is that this one is used for displaying, and thus we From a1579c583acb22a7f5dae80a9bfe7707774f49a4 Mon Sep 17 00:00:00 2001 From: Jean-Marc Lasgouttes Date: Thu, 14 Sep 2017 15:50:30 +0200 Subject: [PATCH 019/121] Compute metrics when graphics is updated Remove the old schedule_redraw_ mechanism that was only useful because of our synchronous drawing code. Now that actual painting is scheduled instead of forced, it becomes pointless. Rename WorkArea::redraw(bool) to scheduleRedraw(bool), to show that the drawing is not done right away. In GuiView::updateInset, call scheduleRedraw(true), so that metrics are correctly computed (this was the whole point of the exercise). (cherry picked from commit a31d3dc67dce9655bee9f1b0a2bc2188d7d97453) --- src/frontends/WorkArea.h | 4 ++-- src/frontends/WorkAreaManager.cpp | 2 +- src/frontends/qt4/GuiView.cpp | 2 +- src/frontends/qt4/GuiWorkArea.cpp | 24 +++--------------------- src/frontends/qt4/GuiWorkArea.h | 4 +--- src/frontends/qt4/GuiWorkArea_Private.h | 2 -- 6 files changed, 8 insertions(+), 30 deletions(-) diff --git a/src/frontends/WorkArea.h b/src/frontends/WorkArea.h index 8e459ca375..c21555913e 100644 --- a/src/frontends/WorkArea.h +++ b/src/frontends/WorkArea.h @@ -36,8 +36,8 @@ public: /// virtual ~WorkArea() {} - /// redraw the screen, without using existing pixmap - virtual void redraw(bool update_metrics) = 0; + /// Update metrics if needed and schedule a paint event + virtual void scheduleRedraw(bool update_metrics) = 0; /// close this work area. /// Slot for Buffer::closing signal. diff --git a/src/frontends/WorkAreaManager.cpp b/src/frontends/WorkAreaManager.cpp index b98163cecc..c79f08bef7 100644 --- a/src/frontends/WorkAreaManager.cpp +++ b/src/frontends/WorkAreaManager.cpp @@ -35,7 +35,7 @@ void WorkAreaManager::remove(WorkArea * wa) void WorkAreaManager::redrawAll(bool update_metrics) { for (WorkArea * wa : work_areas_) - wa->redraw(update_metrics); + wa->scheduleRedraw(update_metrics); } diff --git a/src/frontends/qt4/GuiView.cpp b/src/frontends/qt4/GuiView.cpp index a7d669a774..785abfdd9b 100644 --- a/src/frontends/qt4/GuiView.cpp +++ b/src/frontends/qt4/GuiView.cpp @@ -4348,7 +4348,7 @@ Buffer const * GuiView::updateInset(Inset const * inset) continue; Buffer const * buffer = &(wa->bufferView().buffer()); if (inset_buffer == buffer) - wa->scheduleRedraw(); + wa->scheduleRedraw(true); } return inset_buffer; } diff --git a/src/frontends/qt4/GuiWorkArea.cpp b/src/frontends/qt4/GuiWorkArea.cpp index 70dcf3b32c..6520c3aa7c 100644 --- a/src/frontends/qt4/GuiWorkArea.cpp +++ b/src/frontends/qt4/GuiWorkArea.cpp @@ -237,7 +237,7 @@ SyntheticMouseEvent::SyntheticMouseEvent() GuiWorkArea::Private::Private(GuiWorkArea * parent) : p(parent), buffer_view_(0), lyx_view_(0), caret_(0), caret_visible_(false), - need_resize_(false), schedule_redraw_(false), preedit_lines_(1), + need_resize_(false), preedit_lines_(1), pixel_ratio_(1.0), completer_(new GuiCompleter(p, p)), dialog_mode_(false), shell_escape_(false), read_only_(false), clean_(true), externally_modified_(false) @@ -451,7 +451,7 @@ void GuiWorkArea::toggleCaret() } -void GuiWorkArea::redraw(bool update_metrics) +void GuiWorkArea::scheduleRedraw(bool update_metrics) { if (!isVisible()) // No need to redraw in this case. @@ -632,18 +632,6 @@ void GuiWorkArea::Private::showCaret() caret_->update(point.x_, point.y_, h, l_shape, isrtl, completable); - if (schedule_redraw_) { - // This happens when a graphic conversion is finished. As we don't know - // the size of the new graphics, it's better the update everything. - // We can't use redraw() here because this would trigger a infinite - // recursive loop with showCaret(). - buffer_view_->resize(p->viewport()->width(), p->viewport()->height()); - p->viewport()->update(); - updateScrollbar(); - schedule_redraw_ = false; - return; - } - p->viewport()->update(caret_->rect()); } @@ -1370,12 +1358,6 @@ bool GuiWorkArea::isFullScreen() const } -void GuiWorkArea::scheduleRedraw() -{ - d->schedule_redraw_ = true; -} - - bool GuiWorkArea::inDialogMode() const { return d->dialog_mode_; @@ -1788,7 +1770,7 @@ void TabWorkArea::on_currentTabChanged(int i) GuiWorkArea * wa = workArea(i); LASSERT(wa, return); wa->setUpdatesEnabled(true); - wa->redraw(true); + wa->scheduleRedraw(true); wa->setFocus(); /// currentWorkAreaChanged(wa); diff --git a/src/frontends/qt4/GuiWorkArea.h b/src/frontends/qt4/GuiWorkArea.h index 63a9c8364e..39d2054217 100644 --- a/src/frontends/qt4/GuiWorkArea.h +++ b/src/frontends/qt4/GuiWorkArea.h @@ -60,13 +60,11 @@ public: /// is GuiView in fullscreen mode? bool isFullScreen() const; /// - void scheduleRedraw(); - /// BufferView & bufferView(); /// BufferView const & bufferView() const; /// - void redraw(bool update_metrics); + void scheduleRedraw(bool update_metrics); /// return true if the key is part of a shortcut bool queryKeySym(KeySymbol const & key, KeyModifier mod) const; diff --git a/src/frontends/qt4/GuiWorkArea_Private.h b/src/frontends/qt4/GuiWorkArea_Private.h index 199ce253d6..8be28694cd 100644 --- a/src/frontends/qt4/GuiWorkArea_Private.h +++ b/src/frontends/qt4/GuiWorkArea_Private.h @@ -122,8 +122,6 @@ struct GuiWorkArea::Private /// bool need_resize_; - /// - bool schedule_redraw_; /// the current preedit text of the input method docstring preedit_string_; From c43b6a9ecf7d78a2187384e776d439698633f01f Mon Sep 17 00:00:00 2001 From: Jean-Marc Lasgouttes Date: Mon, 18 Sep 2017 10:58:07 +0200 Subject: [PATCH 020/121] Remember correctly pixel ratio used for painting This avoids endless resize issues on HiDPI systems (e.g. Retina Mac). Rename pixel_ratio_ to last_pixel_ratio_ to emphasize that this is a cached value. Inline needResize method to make the logic clearer in paintEvent. (cherry picked from commit 6532e5104dfad5416817d89a5f91e53c30cdd523) --- src/frontends/qt4/GuiWorkArea.cpp | 6 ++++-- src/frontends/qt4/GuiWorkArea_Private.h | 6 +----- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/frontends/qt4/GuiWorkArea.cpp b/src/frontends/qt4/GuiWorkArea.cpp index 6520c3aa7c..f4380da5e8 100644 --- a/src/frontends/qt4/GuiWorkArea.cpp +++ b/src/frontends/qt4/GuiWorkArea.cpp @@ -238,7 +238,7 @@ GuiWorkArea::Private::Private(GuiWorkArea * parent) : p(parent), buffer_view_(0), lyx_view_(0), caret_(0), caret_visible_(false), need_resize_(false), preedit_lines_(1), - pixel_ratio_(1.0), + last_pixel_ratio_(1.0), completer_(new GuiCompleter(p, p)), dialog_mode_(false), shell_escape_(false), read_only_(false), clean_(true), externally_modified_(false) { @@ -1243,7 +1243,7 @@ void GuiWorkArea::paintEvent(QPaintEvent * ev) // LYXERR(Debug::PAINTING, "paintEvent begin: x: " << rc.x() // << " y: " << rc.y() << " w: " << rc.width() << " h: " << rc.height()); - if (d->needResize()) { + if (d->need_resize_ || pixelRatio() != d->last_pixel_ratio_) { d->resizeBufferView(); if (d->caret_visible_) { d->hideCaret(); @@ -1251,6 +1251,8 @@ void GuiWorkArea::paintEvent(QPaintEvent * ev) } } + d->last_pixel_ratio_ = pixelRatio(); + GuiPainter pain(viewport(), pixelRatio()); d->buffer_view_->draw(pain, d->caret_visible_); diff --git a/src/frontends/qt4/GuiWorkArea_Private.h b/src/frontends/qt4/GuiWorkArea_Private.h index 8be28694cd..ef2bb7e1df 100644 --- a/src/frontends/qt4/GuiWorkArea_Private.h +++ b/src/frontends/qt4/GuiWorkArea_Private.h @@ -97,10 +97,6 @@ struct GuiWorkArea::Private void paintPreeditText(GuiPainter & pain); - bool needResize() const { - return need_resize_ || p->pixelRatio() != pixel_ratio_; - } - /// GuiWorkArea * p; /// @@ -133,7 +129,7 @@ struct GuiWorkArea::Private /// Ratio between physical pixels and device-independent pixels /// We save the last used value to detect changes of the /// current pixel_ratio of the viewport. - double pixel_ratio_; + double last_pixel_ratio_; /// GuiCompleter * completer_; From 7b99bf6a375e14882713d96338345d130cab1425 Mon Sep 17 00:00:00 2001 From: Jean-Marc Lasgouttes Date: Mon, 18 Sep 2017 11:21:18 +0200 Subject: [PATCH 021/121] Do not presume what the defaults for a new QPainter are (cherry picked from commit 275d306c73e3e0f60e0742adbcb06cce98c48ee5) --- src/frontends/qt4/GuiPainter.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/frontends/qt4/GuiPainter.cpp b/src/frontends/qt4/GuiPainter.cpp index bff8f9dc30..b03bb44ad3 100644 --- a/src/frontends/qt4/GuiPainter.cpp +++ b/src/frontends/qt4/GuiPainter.cpp @@ -52,10 +52,10 @@ GuiPainter::GuiPainter(QPaintDevice * device, double pixel_ratio) : QPainter(device), Painter(pixel_ratio), use_pixmap_cache_(false) { - // new QPainter has default QPen: - current_color_ = guiApp->colorCache().get(Color_black); - current_ls_ = line_solid; - current_lw_ = thin_line; + // set cache correctly + current_color_ = pen().color(); + current_ls_ = pen().style() == Qt::DotLine ? line_onoffdash : line_solid; + current_lw_ = pen().width(); } From f6cbc08a7db3c2185b6eae768c026c58f577b0bc Mon Sep 17 00:00:00 2001 From: Jean-Marc Lasgouttes Date: Wed, 27 Sep 2017 17:52:06 +0200 Subject: [PATCH 022/121] Fix bad refresh when changing zoom level Replace the tricky code in LFUN_SCREEN_FONT_UPDATE and replace it with proper use of DispatchResult flags. LFUN_BUFFER_ZOOM* does not need to call LFUN_SCREEN_FONT_UPDATE, since it already does everything that is required. (cherry picked from commit 9df59aac63bbb56d9d5f5ddcccfaa3ebace2f03d) --- src/frontends/qt4/GuiApplication.cpp | 9 +-------- src/frontends/qt4/GuiView.cpp | 2 +- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/src/frontends/qt4/GuiApplication.cpp b/src/frontends/qt4/GuiApplication.cpp index ee379ffb56..110b63ec21 100644 --- a/src/frontends/qt4/GuiApplication.cpp +++ b/src/frontends/qt4/GuiApplication.cpp @@ -1628,14 +1628,7 @@ void GuiApplication::dispatch(FuncRequest const & cmd, DispatchResult & dr) case LFUN_SCREEN_FONT_UPDATE: { // handle the screen font changes. d->font_loader_.update(); - // Backup current_view_ - GuiView * view = current_view_; - // Set current_view_ to zero to forbid GuiWorkArea::redraw() - // to skip the refresh. - current_view_ = 0; - theBufferList().changed(false); - // Restore current_view_ - current_view_ = view; + dr.screenUpdate(Update::Force | Update::FitCursor); break; } diff --git a/src/frontends/qt4/GuiView.cpp b/src/frontends/qt4/GuiView.cpp index 785abfdd9b..2aee2735d3 100644 --- a/src/frontends/qt4/GuiView.cpp +++ b/src/frontends/qt4/GuiView.cpp @@ -4152,7 +4152,7 @@ void GuiView::dispatch(FuncRequest const & cmd, DispatchResult & dr) // painting so we must reset it. QPixmapCache::clear(); guiApp->fontLoader().update(); - lyx::dispatch(FuncRequest(LFUN_SCREEN_FONT_UPDATE)); + dr.screenUpdate(Update::Force | Update::FitCursor); break; } From 6bd158dcba851beb4c22f8aa79a572b21f1a16d0 Mon Sep 17 00:00:00 2001 From: Jean-Marc Lasgouttes Date: Fri, 29 Sep 2017 10:29:39 +0200 Subject: [PATCH 023/121] Improve the logic of caret repainting For some reason the existing code only considered the bottom row that contained the cursor. There is no need for that, and actually it caused painting problems in nested insets. Tweak the logic of repaint_caret_row_ a bit: there is no need for repainting when there is currently no caret on screen. (cherry picked from commit 764a153c69bb9b46a6e6872ce48e06f5f867cc53) --- src/BufferView.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/BufferView.cpp b/src/BufferView.cpp index 58e4f8640f..53d374f07f 100644 --- a/src/BufferView.cpp +++ b/src/BufferView.cpp @@ -3057,15 +3057,15 @@ void BufferView::draw(frontend::Painter & pain, bool paint_caret) int const y = tm.first().second->position(); PainterInfo pi(this, pain); - CursorSlice const & bottomSlice = d->cursor_.bottom(); - /** A repaint of the previous cursor row is needed if - * 1/ the caret will be painted and is is not the same than the - * already painted one; - * 2/ the caret will not be painted, but there is already one on - * screen. + /** A repaint of the previous caret row is needed if there is + * caret painted on screen and either + * 1/ a new caret has to be painted at a place different from + * the existing one; + * 2/ there is no need for a caret anymore. */ - d->repaint_caret_row_ = (paint_caret && bottomSlice != d->caret_slice_) - || (! paint_caret && !d->caret_slice_.empty()); + d->repaint_caret_row_ = !d->caret_slice_.empty() && + ((paint_caret && d->cursor_.top() != d->caret_slice_) + || ! paint_caret); // Check whether the row where the cursor lives needs to be scrolled. // Update the drawing strategy if needed. @@ -3151,7 +3151,7 @@ void BufferView::draw(frontend::Painter & pain, bool paint_caret) // Remember what has just been done for the next draw() step if (paint_caret) - d->caret_slice_ = bottomSlice; + d->caret_slice_ = d->cursor_.top(); else d->caret_slice_ = CursorSlice(); } From 2b1b33189dc4113d2744cb9a68e691fbca4b884a Mon Sep 17 00:00:00 2001 From: Jean-Marc Lasgouttes Date: Mon, 2 Oct 2017 17:07:31 +0200 Subject: [PATCH 024/121] Create new method GuiWorkArea::Private:::updateCaretGeometry This replaces a showCaret/hideCaret pair and avoids an update. Also remove an update() call in resizeBufferView: is is not necessary since we are already in a pintEvent handler. (cherry picked from commit add342d088c1b65343234576a35e567507fb2d49) --- src/frontends/qt4/GuiWorkArea.cpp | 28 ++++++++++++------------- src/frontends/qt4/GuiWorkArea_Private.h | 6 ++++-- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/frontends/qt4/GuiWorkArea.cpp b/src/frontends/qt4/GuiWorkArea.cpp index f4380da5e8..c4463e3d3b 100644 --- a/src/frontends/qt4/GuiWorkArea.cpp +++ b/src/frontends/qt4/GuiWorkArea.cpp @@ -469,14 +469,12 @@ void GuiWorkArea::scheduleRedraw(bool update_metrics) // update caret position, because otherwise it has to wait until // the blinking interval is over - if (d->caret_visible_) { - d->hideCaret(); - d->showCaret(); - } + d->updateCaretGeometry(); LYXERR(Debug::WORKAREA, "WorkArea::redraw screen"); viewport()->update(); + /// FIXME: is this still true now that paintEvent does the actual painting? /// \warning: scrollbar updating *must* be done after the BufferView is drawn /// because \c BufferView::updateScrollbar() is called in \c BufferView::draw(). d->updateScrollbar(); @@ -574,7 +572,7 @@ void GuiWorkArea::Private::resizeBufferView() buffer_view_->resize(p->viewport()->width(), p->viewport()->height()); if (caret_in_view) buffer_view_->scrollToCursor(); - p->viewport()->update(); + updateCaretGeometry(); // Update scrollbars which might have changed due different // BufferView dimension. This is especially important when the @@ -592,11 +590,8 @@ void GuiWorkArea::Private::resizeBufferView() } -void GuiWorkArea::Private::showCaret() +void GuiWorkArea::Private::updateCaretGeometry() { - if (caret_visible_) - return; - Point point; int h = 0; buffer_view_->caretPosAndHeight(point, h); @@ -631,7 +626,15 @@ void GuiWorkArea::Private::showCaret() point.x_ -= buffer_view_->horizScrollOffset(); caret_->update(point.x_, point.y_, h, l_shape, isrtl, completable); +} + +void GuiWorkArea::Private::showCaret() +{ + if (caret_visible_) + return; + + updateCaretGeometry(); p->viewport()->update(caret_->rect()); } @@ -1243,13 +1246,8 @@ void GuiWorkArea::paintEvent(QPaintEvent * ev) // LYXERR(Debug::PAINTING, "paintEvent begin: x: " << rc.x() // << " y: " << rc.y() << " w: " << rc.width() << " h: " << rc.height()); - if (d->need_resize_ || pixelRatio() != d->last_pixel_ratio_) { + if (d->need_resize_ || pixelRatio() != d->last_pixel_ratio_) d->resizeBufferView(); - if (d->caret_visible_) { - d->hideCaret(); - d->showCaret(); - } - } d->last_pixel_ratio_ = pixelRatio(); diff --git a/src/frontends/qt4/GuiWorkArea_Private.h b/src/frontends/qt4/GuiWorkArea_Private.h index ef2bb7e1df..de20397c71 100644 --- a/src/frontends/qt4/GuiWorkArea_Private.h +++ b/src/frontends/qt4/GuiWorkArea_Private.h @@ -85,10 +85,12 @@ struct GuiWorkArea::Private /// void dispatch(FuncRequest const & cmd0); - /// hide the visible caret, if it is visible - void hideCaret(); + /// recompute the shape and position of the caret + void updateCaretGeometry(); /// show the caret if it is not visible void showCaret(); + /// hide the caret if it is visible + void hideCaret(); /// Set the range and value of the scrollbar and connect to its valueChanged /// signal. void updateScrollbar(); From 4ecbff00192fb097432bc2d0604c6c8d97aa883a Mon Sep 17 00:00:00 2001 From: Jean-Marc Lasgouttes Date: Wed, 11 Oct 2017 18:00:48 +0200 Subject: [PATCH 025/121] Allow multiple calls to processUpdateFlags before redraw The goal of this commit is to ensure that a processUpdateFlags call that requires no redraw will not override a previous one that did require a redraw. To this end, the semantics of the flag argument is now different: its value is now OR'ed with a private update_flags_ variable. This variable is only reset after the buffer view has actually been redrawn. A new Update::ForceRedraw flag has been added. It requires a full redraw but no metrics computation. It is not used in the main code (yet), but avoids to compute metrics repeatedly in consecutive processUpdateFlags calls. The process is now as follows: - if flags is just None, return immediately, there is nothing to do. - the Force flag is honored (full metrics computation) and replaced with ForceDraw. - the FitCursor flag is honored and removed from the flags. - the SinglePar update is added if ForceDraw is not in flags and only the current par has been modified. The remaining flags are only then added to the BufferView update flags, and the update strategy is computed for the next paint event. Finally the dubious call to updateMacros in updateMetrics has been removed for performance reasons. (cherry picked from commit 8d8988de475bf2055f253823e53fd5627be5de78) --- development/PAINTING_ANALYSIS | 21 ++-- src/BufferView.cpp | 196 ++++++++++++++++++---------------- src/BufferView.h | 9 +- src/TextMetrics.cpp | 15 ++- src/update_flags.h | 14 ++- 5 files changed, 141 insertions(+), 114 deletions(-) diff --git a/development/PAINTING_ANALYSIS b/development/PAINTING_ANALYSIS index f734edb3b0..ec3566e06c 100644 --- a/development/PAINTING_ANALYSIS +++ b/development/PAINTING_ANALYSIS @@ -60,12 +60,6 @@ cursor. * Clean-up of drawing code -The goal is to make painting with drawing disable fast enough that it -can be used after every metrics computation. Then we can separate real -drawing from metrics. - -Other changes are only clean-ups. - ** When a paragraph ends with a newline, compute correctly the height of the extra row. ** Merging bv::updateMetrics and tm::metrics @@ -76,7 +70,7 @@ insets. We should re-use the bv::updateMetrics logic: + transfer all the logic of bv::updateMetrics to tm. + Main InsetText should not be special. -The difficuly for a tall table cell for example, is that it may be +The difficulty for a tall table cell for example, is that it may be necessary to break the whole contents to know the width of the cell. @@ -113,11 +107,19 @@ DecorationUpdate). It triggers a recomputation of the metrics when either: existing metrics. Note that the Update::SinglePar flag is *never* taken into account. +If a computation of metrics has taken place, Force is removed from the +flags and ForceDraw is added instead. + +It is OK to call processUptateFlags several times before an update. In +this case, the effects are cumulative.processUpdateFlags execute the +metrics-related actions, but defers the actual drawing to the next +paint event. + The screen is drawn (with appropriate update strategy), except when update flag is Update::None. -** Metrics computation +** Metrics computation (and nodraw drawing phase) This is triggered by bv::updateMetrics, which calls tm::redoParagraph for all visible paragraphs. Some Paragraphs above or below the screen (needed @@ -127,6 +129,9 @@ tm::redoParagraph will call Inset::metrics for each inset. In the case of text insets, this will invoke recursively tm::metrics, which redoes all the paragraphs of the inset. +At the end of the function, bv::updatePosCache is called. It triggers +a repaint of the document with a NullPainter (a painter that does +nothing). This has the effect of caching all insets positions. ** Drawing the work area. diff --git a/src/BufferView.cpp b/src/BufferView.cpp index 53d374f07f..4e2428d7d7 100644 --- a/src/BufferView.cpp +++ b/src/BufferView.cpp @@ -228,7 +228,8 @@ enum ScreenUpdateStrategy { struct BufferView::Private { - Private(BufferView & bv) : update_strategy_(NoScreenUpdate), + Private(BufferView & bv) : update_strategy_(FullScreenUpdate), + update_flags_(Update::Force), wh_(0), cursor_(bv), anchor_pit_(0), anchor_ypos_(0), inlineCompletionUniqueChars_(0), @@ -245,6 +246,8 @@ struct BufferView::Private /// ScreenUpdateStrategy update_strategy_; /// + Update::flags update_flags_; + /// CoordCache coord_cache_; /// Estimated average par height for scrollbar. @@ -445,79 +448,85 @@ bool BufferView::needsFitCursor() const } +namespace { + +// this is for debugging only. +string flagsAsString(Update::flags flags) +{ + if (flags == Update::None) + return "None "; + return string((flags & Update::FitCursor) ? "FitCursor " : "") + + ((flags & Update::Force) ? "Force " : "") + + ((flags & Update::ForceDraw) ? "ForceDraw " : "") + + ((flags & Update::SinglePar) ? "SinglePar " : ""); +} + +} + void BufferView::processUpdateFlags(Update::flags flags) { - // This is close to a hot-path. - LYXERR(Debug::PAINTING, "BufferView::processUpdateFlags()" - << "[fitcursor = " << (flags & Update::FitCursor) - << ", forceupdate = " << (flags & Update::Force) - << ", singlepar = " << (flags & Update::SinglePar) - << "] buffer: " << &buffer_); - - // FIXME Does this really need doing here? It's done in updateBuffer, and - // if the Buffer doesn't need updating, then do the macros? - buffer_.updateMacros(); - - // Now do the first drawing step if needed. This consists on updating - // the CoordCache in updateMetrics(). - // The second drawing step is done in WorkArea::redraw() if needed. - // FIXME: is this still true now that Buffer::changed() is used all over? + LYXERR(Debug::PAINTING, "BufferView::processUpdateFlags( " + << flagsAsString(flags) << ") buffer: " << &buffer_); // Case when no explicit update is requested. - if (!flags) { + if (flags == Update::None) + return; + + // SinglePar is ignored for now (this should probably change). We + // set it ourselves below, at the price of always rebreaking the + // paragraph at cursor. This can be expensive for large tables. + flags = flags & ~Update::SinglePar; + + // First check whether the metrics and inset positions should be updated + if (flags & Update::Force) { + // This will update the CoordCache items and replace Force + // with ForceDraw in flags. + updateMetrics(flags); + } + + // Then make sure that the screen contains the cursor if needed + if (flags & Update::FitCursor) { + if (needsFitCursor()) { + scrollToCursor(d->cursor_, false); + // Metrics have to be recomputed (maybe again) + updateMetrics(flags); + } + flags = flags & ~Update::FitCursor; + } + + // Finally detect whether we can only repaint a single paragraph + if (!(flags & Update::ForceDraw)) { + if (singleParUpdate()) + flags = flags | Update::SinglePar; + else + updateMetrics(flags); + } + + // Add flags to the the update flags. These will be reset to None + // after the redraw is actually done + d->update_flags_ = d->update_flags_ | flags; + LYXERR(Debug::PAINTING, "Cumulative flags: " << flagsAsString(flags)); + + // Now compute the update strategy + // Possibly values in flag are None, Decoration, ForceDraw + LATTEST((d->update_flags_ & ~(Update::None | Update::SinglePar + | Update::Decoration | Update::ForceDraw)) == 0); + + if (d->update_flags_ & Update::ForceDraw) + d->update_strategy_ = FullScreenUpdate; + else if (d->update_flags_ & Update::Decoration) + d->update_strategy_ = DecorationUpdate; + else if (d->update_flags_ & Update::SinglePar) + d->update_strategy_ = SingleParUpdate; + else { // no need to redraw anything. d->update_strategy_ = NoScreenUpdate; - return; - } - - if (flags == Update::Decoration) { - d->update_strategy_ = DecorationUpdate; - buffer_.changed(false); - return; - } - - if (flags == Update::FitCursor - || flags == (Update::Decoration | Update::FitCursor)) { - // tell the frontend to update the screen if needed. - if (needsFitCursor()) { - showCursor(); - return; - } - if (flags & Update::Decoration) { - d->update_strategy_ = DecorationUpdate; - buffer_.changed(false); - return; - } - // no screen update is needed in principle, but this - // could change if cursor row needs horizontal scrolling. - d->update_strategy_ = NoScreenUpdate; - buffer_.changed(false); - return; - } - - bool const full_metrics = flags & Update::Force || !singleParUpdate(); - - if (full_metrics) - // We have to update the full screen metrics. - updateMetrics(); - - if (!(flags & Update::FitCursor)) { - // Nothing to do anymore. Trigger a redraw and return - buffer_.changed(false); - return; - } - - // updateMetrics() does not update paragraph position - // This is done at draw() time. So we need a redraw! - buffer_.changed(false); - - if (needsFitCursor()) { - // The cursor is off screen so ensure it is visible. - // refresh it: - showCursor(); } updateHoveredInset(); + + // Trigger a redraw. + buffer_.changed(false); } @@ -632,8 +641,7 @@ void BufferView::scrollDocView(int const value, bool update) // If the offset is less than 2 screen height, prefer to scroll instead. if (abs(value) <= 2 * height_) { d->anchor_ypos_ -= value; - buffer_.changed(true); - updateHoveredInset(); + processUpdateFlags(Update::Force); return; } @@ -830,12 +838,7 @@ bool BufferView::moveToPosition(pit_type bottom_pit, pos_type bottom_pos, d->cursor_.setCurrentFont(); // Do not forget to reset the anchor (see #9912) d->cursor_.resetAnchor(); - // To center the screen on this new position we need the - // paragraph position which is computed at draw() time. - // So we need a redraw! - buffer_.changed(false); - if (needsFitCursor()) - showCursor(); + processUpdateFlags(Update::FitCursor); } return success; @@ -877,19 +880,15 @@ void BufferView::showCursor() void BufferView::showCursor(DocIterator const & dit, bool recenter, bool update) { - if (scrollToCursor(dit, recenter) && update) { - buffer_.changed(true); - updateHoveredInset(); - } + if (scrollToCursor(dit, recenter) && update) + processUpdateFlags(Update::Force); } void BufferView::scrollToCursor() { - if (scrollToCursor(d->cursor_, false)) { - buffer_.changed(true); - updateHoveredInset(); - } + if (scrollToCursor(d->cursor_, false)) + processUpdateFlags(Update::Force); } @@ -1715,8 +1714,8 @@ void BufferView::dispatch(FuncRequest const & cmd, DispatchResult & dr) bool const in_texted = cur.inTexted(); cur.setCursor(doc_iterator_begin(cur.buffer())); cur.selHandle(false); - buffer_.changed(true); - updateHoveredInset(); + // Force an immediate computation of metrics because we need it below + processUpdateFlags(Update::Force); d->text_metrics_[&buffer_.text()].editXY(cur, p.x_, p.y_, true, act == LFUN_SCREEN_UP); @@ -1750,8 +1749,7 @@ void BufferView::dispatch(FuncRequest const & cmd, DispatchResult & dr) if (scroll_value) scroll(scroll_step * scroll_value); } - buffer_.changed(true); - updateHoveredInset(); + dr.screenUpdate(Update::ForceDraw); dr.forceBufferUpdate(); break; } @@ -2646,7 +2644,6 @@ bool BufferView::singleParUpdate() return false; tm.updatePosCache(bottom_pit); - d->update_strategy_ = SingleParUpdate; LYXERR(Debug::PAINTING, "\ny1: " << pm.position() - pm.ascent() << " y2: " << pm.position() + pm.descent() @@ -2657,6 +2654,13 @@ bool BufferView::singleParUpdate() void BufferView::updateMetrics() +{ + updateMetrics(d->update_flags_); + d->update_strategy_ = FullScreenUpdate; +} + + +void BufferView::updateMetrics(Update::flags & update_flags) { if (height_ == 0 || width_ == 0) return; @@ -2741,7 +2745,8 @@ void BufferView::updateMetrics() << " pit1 = " << pit1 << " pit2 = " << pit2); - d->update_strategy_ = FullScreenUpdate; + // metrics is done, full drawing is necessary now + update_flags = (update_flags & ~Update::Force) | Update::ForceDraw; // Now update the positions of insets in the cache. updatePosCache(); @@ -3050,8 +3055,8 @@ void BufferView::draw(frontend::Painter & pain, bool paint_caret) { if (height_ == 0 || width_ == 0) return; - LYXERR(Debug::PAINTING, "\t\t*** START DRAWING ***"); - + LYXERR(Debug::PAINTING, (pain.isNull() ? "\t\t--- START NODRAW ---" + : "\t\t*** START DRAWING ***")); Text & text = buffer_.text(); TextMetrics const & tm = d->text_metrics_[&text]; int const y = tm.first().second->position(); @@ -3130,7 +3135,8 @@ void BufferView::draw(frontend::Painter & pain, bool paint_caret) } break; } - LYXERR(Debug::PAINTING, "\n\t\t*** END DRAWING ***"); + LYXERR(Debug::PAINTING, (pain.isNull() ? "\t\t --- END NODRAW ---" + : "\t\t *** END DRAWING ***")); // The scrollbar needs an update. updateScrollbar(); @@ -3141,13 +3147,19 @@ void BufferView::draw(frontend::Painter & pain, bool paint_caret) for (pit_type pit = firstpm.first; pit <= lastpm.first; ++pit) { ParagraphMetrics const & pm = tm.parMetrics(pit); if (pm.position() + pm.descent() > 0) { + if (d->anchor_pit_ != pit + || d->anchor_ypos_ != pm.position()) + LYXERR(Debug::PAINTING, "Found new anchor pit = " << d->anchor_pit_ + << " anchor ypos = " << d->anchor_ypos_); d->anchor_pit_ = pit; d->anchor_ypos_ = pm.position(); break; } } - LYXERR(Debug::PAINTING, "Found new anchor pit = " << d->anchor_pit_ - << " anchor ypos = " << d->anchor_ypos_); + if (!pain.isNull()) { + // reset the update flags, everything has been done + d->update_flags_ = Update::None; + } // Remember what has just been done for the next draw() step if (paint_caret) diff --git a/src/BufferView.h b/src/BufferView.h index a5222599f2..3cbf22a8ba 100644 --- a/src/BufferView.h +++ b/src/BufferView.h @@ -120,11 +120,12 @@ public: /// \return true if the BufferView is at the bottom of the document. bool isBottomScreen() const; - /// perform pending metrics updates. - /** \c Update::FitCursor means first to do a FitCursor, and to + /// Add \p flags to current update flags and trigger an update. + /* If this method is invoked several times before the update + * actually takes place, the effect is cumulative. + * \c Update::FitCursor means first to do a FitCursor, and to * force an update if screen position changes. * \c Update::Force means to force an update in any case. - * \retval true if a screen redraw is needed */ void processUpdateFlags(Update::flags flags); @@ -367,6 +368,8 @@ private: /// Update current paragraph metrics. /// \return true if no further update is needed. bool singleParUpdate(); + /// do the work for the public updateMetrics() + void updateMetrics(Update::flags & update_flags); // Set the row on which the cursor lives. void setCurrentRowSlice(CursorSlice const & rowSlice); diff --git a/src/TextMetrics.cpp b/src/TextMetrics.cpp index 5eb85bf118..325b0b9c5a 100644 --- a/src/TextMetrics.cpp +++ b/src/TextMetrics.cpp @@ -1920,14 +1920,13 @@ void TextMetrics::drawParagraph(PainterInfo & pi, pit_type const pit, int const // Instrumentation for testing row cache (see also // 12 lines lower): if (lyxerr.debugging(Debug::PAINTING) - && (row.selection() || pi.full_repaint || row_has_changed)) { - string const foreword = text_->isMainText() ? - "main text redraw " : "inset text redraw: "; - LYXERR(Debug::PAINTING, foreword << "pit=" << pit << " row=" << i - << " row_selection=" << row.selection() - << " full_repaint=" << pi.full_repaint - << " row_has_changed=" << row_has_changed - << " null painter=" << pi.pain.isNull()); + && (row.selection() || pi.full_repaint || row_has_changed)) { + string const foreword = text_->isMainText() ? "main text redraw " + : "inset text redraw: "; + LYXERR0(foreword << "pit=" << pit << " row=" << i + << (row.selection() ? " row_selection": "") + << (pi.full_repaint ? " full_repaint" : "") + << (row_has_changed ? " row_has_changed" : "")); } // Backup full_repaint status and force full repaint diff --git a/src/update_flags.h b/src/update_flags.h index 3e877c1ca1..a40e88c556 100644 --- a/src/update_flags.h +++ b/src/update_flags.h @@ -21,13 +21,16 @@ namespace Update { /// Recenter the screen around the cursor if is found outside the /// visible area. FitCursor = 1, - /// Force a full screen metrics update. + /// Force a full screen metrics update and a full draw. Force = 2, + /// Force a full redraw (but no metrics computations) + ForceDraw = 4, /// Try to rebreak only the current paragraph metrics. - SinglePar = 4, + /// (currently ignored!) + SinglePar = 8, /// Only the inset decorations need to be redrawn, no text metrics /// update is needed. - Decoration = 8 + Decoration = 16 }; inline flags operator|(flags const f, flags const g) @@ -40,6 +43,11 @@ inline flags operator&(flags const f, flags const g) return static_cast(int(f) & int(g)); } +inline flags operator~(flags const f) +{ + return static_cast(~int(f)); +} + } // namespace Update } // namespace lyx From d2e15bd1893e288f3177dbec15b82b723bfca6a6 Mon Sep 17 00:00:00 2001 From: Jean-Marc Lasgouttes Date: Sat, 11 Nov 2017 11:57:39 +0100 Subject: [PATCH 026/121] Store change bar information in row element It is wrong to compute this at paint time. In general, painting a row should not require any access to a paragraph object, but we are far from there now. (cherry picked from commit 4858bb3bb68aac142815b530a017e3776d1c7c11) --- src/Row.cpp | 5 ++++- src/Row.h | 7 +++++++ src/RowPainter.cpp | 12 ------------ src/TextMetrics.cpp | 7 ++++++- 4 files changed, 17 insertions(+), 14 deletions(-) diff --git a/src/Row.cpp b/src/Row.cpp index db1bd2883c..20ff63e22a 100644 --- a/src/Row.cpp +++ b/src/Row.cpp @@ -164,7 +164,8 @@ Row::Row() begin_margin_sel(false), end_margin_sel(false), changed_(false), crc_(0), pit_(0), pos_(0), end_(0), - right_boundary_(false), flushed_(false), rtl_(false) + right_boundary_(false), flushed_(false), rtl_(false), + changebar_(false) {} @@ -371,6 +372,8 @@ void Row::finalizeLast() if (elt.final) return; elt.final = true; + if (elt.change.changed()) + changebar_ = true; if (elt.type == STRING) { dim_.wid -= elt.dim.wid; diff --git a/src/Row.h b/src/Row.h index 498fd07d7f..a2e77fbfb4 100644 --- a/src/Row.h +++ b/src/Row.h @@ -266,6 +266,11 @@ public: void reverseRTL(bool rtl_par); /// bool isRTL() const { return rtl_; } + /// + bool needsChangeBar() const { return changebar_; } + /// + void needsChangeBar(bool ncb) { changebar_ = ncb; } + /// Find row element that contains \c pos, and compute x offset. const_iterator const findElement(pos_type pos, bool boundary, double & x) const; @@ -326,6 +331,8 @@ private: Dimension dim_; /// true when this row lives in a right-to-left paragraph bool rtl_; + /// true when a changebar should be drawn in the margin + bool changebar_; }; diff --git a/src/RowPainter.cpp b/src/RowPainter.cpp index c4b9034fb4..38bcefadad 100644 --- a/src/RowPainter.cpp +++ b/src/RowPainter.cpp @@ -247,18 +247,6 @@ void RowPainter::paintChange(Row::Element const & e) const void RowPainter::paintChangeBar() const { - pos_type const start = row_.pos(); - pos_type end = row_.endpos(); - - if (par_.size() == end) { - // this is the last row of the paragraph; - // thus, we must also consider the imaginary end-of-par character - end++; - } - - if (start == end || !par_.isChanged(start, end)) - return; - int const height = tm_.isLastRow(row_) ? row_.ascent() : row_.height(); diff --git a/src/TextMetrics.cpp b/src/TextMetrics.cpp index 325b0b9c5a..cd33f7f190 100644 --- a/src/TextMetrics.cpp +++ b/src/TextMetrics.cpp @@ -964,6 +964,10 @@ bool TextMetrics::breakRow(Row & row, int const right_margin) const row.addVirtual(end, docstring(1, char_type(0x00B6)), f, Change()); } + // Is there a end-of-paragaph change? + if (i == end && par.lookupChange(end).changed() && !need_new_row) + row.needsChangeBar(true); + // if the row is too large, try to cut at last separator. In case // of success, reset indication that the row was broken abruptly. int const next_width = max_width_ - leftMargin(row.pit(), row.endpos()) @@ -1937,7 +1941,8 @@ void TextMetrics::drawParagraph(PainterInfo & pi, pit_type const pit, int const rp.paintSelection(); rp.paintAppendix(); rp.paintDepthBar(); - rp.paintChangeBar(); + if (row.needsChangeBar()) + rp.paintChangeBar(); if (i == 0 && !row.isRTL()) rp.paintFirst(); if (i == nrows - 1 && row.isRTL()) From a71610b9d72d346ac694518d6dab634f02247e2b Mon Sep 17 00:00:00 2001 From: Jean-Marc Lasgouttes Date: Sat, 11 Nov 2017 12:40:39 +0100 Subject: [PATCH 027/121] Remove row crc computation This computation did not make sense anymore since we began to put the contents in the Row object. The fact that it worked was a coincidence. Instead, we set rows as changed() on creation and reset that once they have been drawn. This will allow in the future for a finer definition of what to redraw or not. Also update the PAINTING_ANALYSIS document (cherry picked from commit 9e2da4a3eac83f46ab184ea8d674f84643814017) --- development/PAINTING_ANALYSIS | 36 +++++++++++++++++++++++++++++++++ src/ParagraphMetrics.cpp | 38 ----------------------------------- src/ParagraphMetrics.h | 3 --- src/Row.cpp | 9 +-------- src/Row.h | 6 +----- src/TextMetrics.cpp | 8 +++++--- 6 files changed, 43 insertions(+), 57 deletions(-) diff --git a/development/PAINTING_ANALYSIS b/development/PAINTING_ANALYSIS index ec3566e06c..32bc93a5ff 100644 --- a/development/PAINTING_ANALYSIS +++ b/development/PAINTING_ANALYSIS @@ -60,6 +60,42 @@ cursor. * Clean-up of drawing code +** Make SinglePar update flag useful again. + +The current code can be very expensive when moving cursor inside a +huge table, for example. We should test the flag again, although this +will probably lead to some glitches here and there. + +** Set Row::changed() in a finer way + +*** singleParUpdate + +When the height of the current paragraph changes, there is no need for +a full screen update. Only the rows after the current one need to have +their position recomputed. + +This is also true when scrolling (how to do that?) + +*** redoParagraph + +It should be possible to check whether the new row is the same as the +old one and keep its changed() status in this case. This would reduce +a lot the amount of stuff to redraw. + +** Put labels and friends in the Row as elements + +It should not be necessary to access the Paragraph object to draw. +Adding the static elements to Row is a lot of work, but worth it IMO. + +** Create a unique row by paragraph and break it afterwards + +This should be a performance gain (only if paragraph breaking still +shows as expensive after the rest is done) + +** do not add the vertical margin of main text to first/last row + +Would make code cleaner. Probably no so difficult. + ** When a paragraph ends with a newline, compute correctly the height of the extra row. ** Merging bv::updateMetrics and tm::metrics diff --git a/src/ParagraphMetrics.cpp b/src/ParagraphMetrics.cpp index 01db6cb934..1d3ce0db5c 100644 --- a/src/ParagraphMetrics.cpp +++ b/src/ParagraphMetrics.cpp @@ -47,8 +47,6 @@ #include "support/lstrings.h" #include "support/textutils.h" -#include - #include #include #include @@ -84,42 +82,6 @@ void ParagraphMetrics::reset(Paragraph const & par) } -size_t ParagraphMetrics::computeRowSignature(Row const & row, - BufferView const & bv) const -{ - boost::crc_32_type crc; - for (pos_type i = row.pos(); i < row.endpos(); ++i) { - if (par_->isInset(i)) { - Inset const * in = par_->getInset(i); - Dimension const d = in->dimension(bv); - int const b[] = { d.wid, d.asc, d.des }; - crc.process_bytes(b, sizeof(b)); - } else { - char_type const b[] = { par_->getChar(i) }; - crc.process_bytes(b, sizeof(char_type)); - } - if (bv.buffer().params().track_changes) { - Change change = par_->lookupChange(i); - char_type const b[] = { static_cast(change.type) }; - // 1 byte is enough to encode Change::Type - crc.process_bytes(b, 1); - } - } - - pos_type const b1[] = { row.sel_beg, row.sel_end }; - crc.process_bytes(b1, sizeof(b1)); - - Dimension const & d = row.dimension(); - int const b2[] = { row.begin_margin_sel, - row.end_margin_sel, - d.wid, d.asc, d.des }; - crc.process_bytes(b2, sizeof(b2)); - crc.process_bytes(&row.separator, sizeof(row.separator)); - - return crc.checksum(); -} - - void ParagraphMetrics::setPosition(int position) { position_ = position; diff --git a/src/ParagraphMetrics.h b/src/ParagraphMetrics.h index 55304fd9ed..63ed0f3cdf 100644 --- a/src/ParagraphMetrics.h +++ b/src/ParagraphMetrics.h @@ -85,9 +85,6 @@ public: /// bool hfillExpansion(Row const & row, pos_type pos) const; - /// - size_t computeRowSignature(Row const &, BufferView const & bv) const; - /// int position() const { return position_; } void setPosition(int position); diff --git a/src/Row.cpp b/src/Row.cpp index 20ff63e22a..ad492c1a7a 100644 --- a/src/Row.cpp +++ b/src/Row.cpp @@ -162,20 +162,13 @@ Row::Row() : separator(0), label_hfill(0), left_margin(0), right_margin(0), sel_beg(-1), sel_end(-1), begin_margin_sel(false), end_margin_sel(false), - changed_(false), crc_(0), + changed_(true), pit_(0), pos_(0), end_(0), right_boundary_(false), flushed_(false), rtl_(false), changebar_(false) {} -void Row::setCrc(size_type crc) const -{ - changed_ = crc != crc_; - crc_ = crc; -} - - bool Row::isMarginSelected(bool left_margin, DocIterator const & beg, DocIterator const & end) const { diff --git a/src/Row.h b/src/Row.h index a2e77fbfb4..a1fedd7e5d 100644 --- a/src/Row.h +++ b/src/Row.h @@ -139,9 +139,7 @@ public: /// bool changed() const { return changed_; } /// - void setChanged(bool c) { changed_ = c; } - /// - void setCrc(size_type crc) const; + void changed(bool c) const { changed_ = c; } /// Set the selection begin and end. /** * This is const because we update the selection status only at draw() @@ -315,8 +313,6 @@ private: /// has the Row appearance changed since last drawing? mutable bool changed_; - /// CRC of row contents. - mutable size_type crc_; /// Index of the paragraph that contains this row pit_type pit_; /// first pos covered by this row diff --git a/src/TextMetrics.cpp b/src/TextMetrics.cpp index cd33f7f190..1f4516f1af 100644 --- a/src/TextMetrics.cpp +++ b/src/TextMetrics.cpp @@ -468,7 +468,7 @@ bool TextMetrics::redoParagraph(pit_type const pit) row.pit(pit); need_new_row = breakRow(row, right_margin); setRowHeight(row); - row.setChanged(false); + row.changed(true); if (row_index || row.endpos() < par.size() || (row.right_boundary() && par.inInset().lyxCode() != CELL_CODE)) { /* If there is more than one row or the row has been @@ -1888,8 +1888,7 @@ void TextMetrics::drawParagraph(PainterInfo & pi, pit_type const pit, int const row.end_margin_sel = sel_end.pit() > pit; } - // Row signature; has row changed since last paint? - row.setCrc(pm.computeRowSignature(row, *bv_)); + // has row changed since last paint? bool row_has_changed = row.changed() || bv_->hadHorizScrollOffset(text_, pit, row.pos()) || bv_->needRepaint(text_, row); @@ -1907,6 +1906,7 @@ void TextMetrics::drawParagraph(PainterInfo & pi, pit_type const pit, int const // Paint only the insets if the text itself is // unchanged. rp.paintOnlyInsets(); + row.changed(false); y += row.descent(); continue; } @@ -1958,6 +1958,8 @@ void TextMetrics::drawParagraph(PainterInfo & pi, pit_type const pit, int const // Restore full_repaint status. pi.full_repaint = tmp; + + row.changed(false); } //LYXERR(Debug::PAINTING, "."); From fa4fc6fc4d97f5c3d3e8ba44ad8b52f750293623 Mon Sep 17 00:00:00 2001 From: Jean-Marc Lasgouttes Date: Thu, 23 Nov 2017 15:38:17 +0100 Subject: [PATCH 028/121] Avoid some caret ghosts When the caret is at end of row, if may happen that it is drawn after the end of the row. In this case caret blinking will not work properly. This patch extends the row background on the left and right by Inset::TEXT_TO_INSET_OFFSET. This is only a hack that will not work if the caret has a ridiculous width like 6. Additionally, introduce some (disabled) debug code that numbers the rows on screen by painting order. Finally, make the code that detects whether the caret was in a given row more precise (take boundary into account). Fixes (mostly, see above) bug #10797. (cherry picked from commit e64ea3576c4534fc647a74d1c9f5e67db39ef783) --- src/BufferView.cpp | 8 +++++--- src/TextMetrics.cpp | 27 +++++++++++++++++++++++++-- 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/src/BufferView.cpp b/src/BufferView.cpp index 4e2428d7d7..acde1ceef3 100644 --- a/src/BufferView.cpp +++ b/src/BufferView.cpp @@ -2979,7 +2979,7 @@ namespace { bool sliceInRow(CursorSlice const & cs, Text const * text, Row const & row) { return !cs.empty() && cs.text() == text && cs.pit() == row.pit() - && row.pos() <= cs.pos() && cs.pos() <= row.endpos(); + && row.pos() <= cs.pos() && cs.pos() < row.endpos(); } } @@ -3162,9 +3162,11 @@ void BufferView::draw(frontend::Painter & pain, bool paint_caret) } // Remember what has just been done for the next draw() step - if (paint_caret) + if (paint_caret) { d->caret_slice_ = d->cursor_.top(); - else + if (d->cursor_.boundary()) + --d->caret_slice_.pos(); + } else d->caret_slice_ = CursorSlice(); } diff --git a/src/TextMetrics.cpp b/src/TextMetrics.cpp index 1f4516f1af..42637d7899 100644 --- a/src/TextMetrics.cpp +++ b/src/TextMetrics.cpp @@ -45,6 +45,7 @@ #include "frontends/Painter.h" #include "frontends/NullPainter.h" +#include "support/convert.h" #include "support/debug.h" #include "support/lassert.h" @@ -1917,8 +1918,16 @@ void TextMetrics::drawParagraph(PainterInfo & pi, pit_type const pit, int const LYXERR(Debug::PAINTING, "Clear rect@(" << max(row_x, 0) << ", " << y - row.ascent() << ")=" << width() << " x " << row.height()); - pi.pain.fillRectangle(max(row_x, 0), y - row.ascent(), - width(), row.height(), pi.background_color); + // FIXME: this is a hack. We know that at least this + // amount of pixels can be cleared on right and left. + // Doing so gets rid of caret ghosts when the cursor is at + // the begining/end of row. However, it will not work if + // the caret has a ridiculous width like 6. (see ticket + // #10797) + pi.pain.fillRectangle(max(row_x, 0) - Inset::TEXT_TO_INSET_OFFSET, + y - row.ascent(), + width() + 2 * Inset::TEXT_TO_INSET_OFFSET, + row.height(), pi.background_color); } // Instrumentation for testing row cache (see also @@ -1956,6 +1965,20 @@ void TextMetrics::drawParagraph(PainterInfo & pi, pit_type const pit, int const row_x + row.right_x() > bv_->workWidth()); y += row.descent(); +#if 0 + // This debug code shows on screen which rows are repainted. + // FIXME: since the updates related to caret blinking restrict + // the painter to a small rectangle, the numbers are not + // updated when this happens. Change the code in + // GuiWorkArea::Private::show/hideCaret if this is important. + static int count = 0; + ++count; + FontInfo fi(sane_font); + fi.setSize(FONT_SIZE_TINY); + fi.setColor(Color_red); + pi.pain.text(row_x, y, convert(count), fi); +#endif + // Restore full_repaint status. pi.full_repaint = tmp; From 9c8e3df86bb3140435e022d67cd7b6f7f8575c71 Mon Sep 17 00:00:00 2001 From: Jean-Marc Lasgouttes Date: Fri, 24 Nov 2017 23:36:28 +0100 Subject: [PATCH 029/121] Fixup ac4bcb12 Cursor at end of paragraph should be treated as if boundary was on. (cherry picked from commit d01dd54bf14167e880c1d0a6382b87e622c2c2ed) --- src/BufferView.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/BufferView.cpp b/src/BufferView.cpp index acde1ceef3..23d0055221 100644 --- a/src/BufferView.cpp +++ b/src/BufferView.cpp @@ -3164,7 +3164,8 @@ void BufferView::draw(frontend::Painter & pain, bool paint_caret) // Remember what has just been done for the next draw() step if (paint_caret) { d->caret_slice_ = d->cursor_.top(); - if (d->cursor_.boundary()) + if (d->cursor_.boundary() + || d->cursor_.top().pos() == d->cursor_.top().lastpos()) --d->caret_slice_.pos(); } else d->caret_slice_ = CursorSlice(); From 8af3077753381238e1fb3e21d65017b94778a47c Mon Sep 17 00:00:00 2001 From: Jean-Marc Lasgouttes Date: Wed, 29 Nov 2017 11:16:09 +0100 Subject: [PATCH 030/121] Make sure that rows are repainted when they get (un)selected The bug is the following: when selecting several paragraphs quickly enough, some rows do not get selected.This is a consequence of the removal of row crc, which lead to not taking into account the selection status of the row in the decision to repaint. The solution chosen here is to add a Row::change() helper function to modify row members. This will set the Row changed status whenever the value of the member changes. (cherry picked from commit ae60749f89fb4ee0fca05ac75979d434f6b0401d) --- src/Row.cpp | 16 ++++++++-------- src/Row.h | 23 +++++++++++++++++++++++ src/TextMetrics.cpp | 4 ++-- 3 files changed, 33 insertions(+), 10 deletions(-) diff --git a/src/Row.cpp b/src/Row.cpp index ad492c1a7a..3fb87bd7e1 100644 --- a/src/Row.cpp +++ b/src/Row.cpp @@ -203,8 +203,8 @@ void Row::setSelectionAndMargins(DocIterator const & beg, setSelection(beg.pos(), end.pos()); if (selection()) { - end_margin_sel = isMarginSelected(false, beg, end); - begin_margin_sel = isMarginSelected(true, beg, end); + change(end_margin_sel, isMarginSelected(false, beg, end)); + change(begin_margin_sel, isMarginSelected(true, beg, end)); } } @@ -212,18 +212,18 @@ void Row::setSelectionAndMargins(DocIterator const & beg, void Row::setSelection(pos_type beg, pos_type end) const { if (pos_ >= beg && pos_ <= end) - sel_beg = pos_; + change(sel_beg, pos_); else if (beg > pos_ && beg <= end_) - sel_beg = beg; + change(sel_beg, beg); else - sel_beg = -1; + change(sel_beg, -1); if (end_ >= beg && end_ <= end) - sel_end = end_; + change(sel_end,end_); else if (end < end_ && end >= pos_) - sel_end = end; + change(sel_end, end); else - sel_end = -1; + change(sel_end, -1); } diff --git a/src/Row.h b/src/Row.h index a1fedd7e5d..49513d32b9 100644 --- a/src/Row.h +++ b/src/Row.h @@ -136,6 +136,29 @@ public: /// Row(); + /** + * Helper function: set variable \c var to value \c val, and mark + * row as changed is the values were different. This is intended + * for use when changing members of the row object. + */ + template + void change(T1 & var, T2 const val) { + if (var != val) + changed(true); + var = val; + } + /** + * Helper function: set variable \c var to value \c val, and mark + * row as changed is the values were different. This is intended + * for use when changing members of the row object. + * This is the const version, useful for mutable members. + */ + template + void change(T1 & var, T2 const val) const { + if (var != val) + changed(true); + var = val; + } /// bool changed() const { return changed_; } /// diff --git a/src/TextMetrics.cpp b/src/TextMetrics.cpp index 42637d7899..e7bd6190e2 100644 --- a/src/TextMetrics.cpp +++ b/src/TextMetrics.cpp @@ -1884,9 +1884,9 @@ void TextMetrics::drawParagraph(PainterInfo & pi, pit_type const pit, int const // whether this row is the first or last and update the margins. if (row.selection()) { if (row.sel_beg == 0) - row.begin_margin_sel = sel_beg.pit() < pit; + row.change(row.begin_margin_sel, sel_beg.pit() < pit); if (row.sel_end == sel_end_par.lastpos()) - row.end_margin_sel = sel_end.pit() > pit; + row.change(row.end_margin_sel, sel_end.pit() > pit); } // has row changed since last paint? From c6771569384edc1e100d427365d6a4976bc5bd95 Mon Sep 17 00:00:00 2001 From: Jean-Marc Lasgouttes Date: Sat, 25 Nov 2017 12:31:11 +0100 Subject: [PATCH 031/121] Use a backing store on macOS Qt on macOS does not respect the Qt::WA_OpaquePaintEvent attribute and clears the widget backing store at each update. Therefore, we use our own backing store in this case. This restores a simplified version of the code that was removed at 06253dfe. (cherry picked from commit 2316435f2fd2da28c70e1b251b852d3bf6d8011a) --- src/frontends/qt4/GuiWorkArea.cpp | 11 +++++-- src/frontends/qt4/GuiWorkArea_Private.h | 44 +++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 2 deletions(-) diff --git a/src/frontends/qt4/GuiWorkArea.cpp b/src/frontends/qt4/GuiWorkArea.cpp index c4463e3d3b..6df7e4e290 100644 --- a/src/frontends/qt4/GuiWorkArea.cpp +++ b/src/frontends/qt4/GuiWorkArea.cpp @@ -306,6 +306,7 @@ void GuiWorkArea::init() generateSyntheticMouseEvent(); }); + d->resetScreen(); // With Qt4.5 a mouse event will happen before the first paint event // so make sure that the buffer view has an up to date metrics. d->buffer_view_->resize(viewport()->width(), viewport()->height()); @@ -1246,12 +1247,15 @@ void GuiWorkArea::paintEvent(QPaintEvent * ev) // LYXERR(Debug::PAINTING, "paintEvent begin: x: " << rc.x() // << " y: " << rc.y() << " w: " << rc.width() << " h: " << rc.height()); - if (d->need_resize_ || pixelRatio() != d->last_pixel_ratio_) + if (d->need_resize_ || pixelRatio() != d->last_pixel_ratio_) { + d->resetScreen(); d->resizeBufferView(); + } d->last_pixel_ratio_ = pixelRatio(); - GuiPainter pain(viewport(), pixelRatio()); + GuiPainter pain(d->screenDevice(), pixelRatio()); + d->buffer_view_->draw(pain, d->caret_visible_); // The preedit text, if needed @@ -1260,6 +1264,9 @@ void GuiWorkArea::paintEvent(QPaintEvent * ev) // and the caret if (d->caret_visible_) d->caret_->draw(pain); + + d->updateScreen(ev->rect()); + ev->accept(); } diff --git a/src/frontends/qt4/GuiWorkArea_Private.h b/src/frontends/qt4/GuiWorkArea_Private.h index de20397c71..83012fa99f 100644 --- a/src/frontends/qt4/GuiWorkArea_Private.h +++ b/src/frontends/qt4/GuiWorkArea_Private.h @@ -20,6 +20,14 @@ #include #include +#ifdef Q_OS_MAC +/* Qt on macOS does not respect the Qt::WA_OpaquePaintEvent attribute + * and resets the widget backing store at each update. Therefore, we + * use our own backing store in this case */ +#define LYX_BACKINGSTORE 1 +#include +#endif + namespace lyx { class Buffer; @@ -99,6 +107,38 @@ struct GuiWorkArea::Private void paintPreeditText(GuiPainter & pain); + void resetScreen() { +#ifdef LYX_BACKINGSTORE + int const pr = p->pixelRatio(); + screen_ = QImage(static_cast(pr * p->viewport()->width()), + static_cast(pr * p->viewport()->height()), + QImage::Format_ARGB32_Premultiplied); +# if QT_VERSION >= 0x050000 + screen_.setDevicePixelRatio(pr); +# endif +#endif + } + + QPaintDevice * screenDevice() { +#ifdef LYX_BACKINGSTORE + return &screen_; +#else + return p->viewport(); +#endif + } + +#ifdef LYX_BACKINGSTORE + void updateScreen(QRectF const & rc) { + QPainter qpain(p->viewport()); + double const pr = p->pixelRatio(); + QRectF const rcs = QRectF(rc.x() * pr, rc.y() * pr, + rc.width() * pr, rc.height() * pr); + qpain.drawImage(rc, screen_, rcs); + } +#else + void updateScreen(QRectF const & ) {} +#endif + /// GuiWorkArea * p; /// @@ -106,6 +146,10 @@ struct GuiWorkArea::Private /// GuiView * lyx_view_; +#ifdef LYX_BACKINGSTORE + /// + QImage screen_; +#endif /// CaretWidget * caret_; /// is the caret currently displayed From be35ba31bfff429330d628b848ecc7d65265590d Mon Sep 17 00:00:00 2001 From: Jean-Marc Lasgouttes Date: Sat, 6 Jan 2018 20:46:06 +0100 Subject: [PATCH 032/121] Fix compilation in monolithic mode (cherry picked from commit 3aa10c8dbaf4813fb30d6e9487a5d50720c7affd) --- src/frontends/qt4/GuiApplication.cpp | 1 + src/frontends/qt4/GuiInclude.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/frontends/qt4/GuiApplication.cpp b/src/frontends/qt4/GuiApplication.cpp index 110b63ec21..323e654a41 100644 --- a/src/frontends/qt4/GuiApplication.cpp +++ b/src/frontends/qt4/GuiApplication.cpp @@ -122,6 +122,7 @@ #include #include #include +#undef CursorShape #undef None #elif defined(QPA_XCB) #include diff --git a/src/frontends/qt4/GuiInclude.cpp b/src/frontends/qt4/GuiInclude.cpp index aa2fc65725..edbf7a19c4 100644 --- a/src/frontends/qt4/GuiInclude.cpp +++ b/src/frontends/qt4/GuiInclude.cpp @@ -31,9 +31,9 @@ #include "insets/InsetListingsParams.h" #include "insets/InsetInclude.h" -#include #include #include +#include #include From 61c5769e3981825b5fef9aecf512679e94e0fc53 Mon Sep 17 00:00:00 2001 From: Jean-Marc Lasgouttes Date: Mon, 8 Jan 2018 11:49:40 +0100 Subject: [PATCH 033/121] Fix ghost caret This fixes a regression in e64ea357, where a test has been (badly) tightened to avoid that two consecutive rows may be redrawn to get rid of caret ghosts. The test prohibited empty rows from being redrawn. Moreover, improve the test of cursor boundary to avoid the case where cursor position is already 0. Fixes bug #10952. (cherry picked from commit 66c677b9463feb0687a8228603f86eddd4e859fd) --- src/BufferView.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/BufferView.cpp b/src/BufferView.cpp index 23d0055221..36ac46cdde 100644 --- a/src/BufferView.cpp +++ b/src/BufferView.cpp @@ -2978,8 +2978,14 @@ namespace { bool sliceInRow(CursorSlice const & cs, Text const * text, Row const & row) { + /* The normal case is the last line. The previous line takes care + * of empty rows (e.g. empty paragraphs). Cursor boundary issues + * are taken care of when setting caret_slice_ in + * BufferView::draw. + */ return !cs.empty() && cs.text() == text && cs.pit() == row.pit() - && row.pos() <= cs.pos() && cs.pos() < row.endpos(); + && ((row.pos() == row.endpos() && row.pos() == cs.pos()) + || (row.pos() <= cs.pos() && cs.pos() < row.endpos())); } } @@ -3164,8 +3170,9 @@ void BufferView::draw(frontend::Painter & pain, bool paint_caret) // Remember what has just been done for the next draw() step if (paint_caret) { d->caret_slice_ = d->cursor_.top(); - if (d->cursor_.boundary() - || d->cursor_.top().pos() == d->cursor_.top().lastpos()) + if (d->caret_slice_.pos() > 0 + && (d->cursor_.boundary() + || d->caret_slice_.pos() == d->caret_slice_.lastpos())) --d->caret_slice_.pos(); } else d->caret_slice_ = CursorSlice(); From e836cc0aacb4a90e582690ca26f61fb94fbe8280 Mon Sep 17 00:00:00 2001 From: Pavel Sanda Date: Thu, 8 Feb 2018 21:33:37 +0100 Subject: [PATCH 034/121] Unify graphics-groups inside marked block functionality. Fixes #11026. https://www.mail-archive.com/lyx-devel@lists.lyx.org/msg203683.html --- lib/ui/stdcontext.inc | 1 + src/BufferView.cpp | 45 +++++++++++++++++++++++++++++++++++++++++++ src/FuncCode.h | 3 ++- src/LyXAction.cpp | 11 +++++++++++ 4 files changed, 59 insertions(+), 1 deletion(-) diff --git a/lib/ui/stdcontext.inc b/lib/ui/stdcontext.inc index 3e490927be..9acf334562 100644 --- a/lib/ui/stdcontext.inc +++ b/lib/ui/stdcontext.inc @@ -358,6 +358,7 @@ Menuset Item "Apply Last Text Style|A" "textstyle-apply" Submenu "Text Style|x" "edit_textstyles" Item "Paragraph Settings...|P" "layout-paragraph" + OptItem "Unify Graphics Groups|U" "graphics-unify" LanguageSelector Separator Item "Fullscreen Mode" "ui-toggle fullscreen" diff --git a/src/BufferView.cpp b/src/BufferView.cpp index 36ac46cdde..edea2eb320 100644 --- a/src/BufferView.cpp +++ b/src/BufferView.cpp @@ -1134,6 +1134,10 @@ bool BufferView::getStatus(FuncRequest const & cmd, FuncStatus & flag) flag.setEnabled(true); break; + case LFUN_GRAPHICS_UNIFY: + flag.setEnabled(cur.selection()); + break; + case LFUN_WORD_FINDADV: { FindAndReplaceOptions opt; istringstream iss(to_utf8(cmd.argument())); @@ -1655,6 +1659,47 @@ void BufferView::dispatch(FuncRequest const & cmd, DispatchResult & dr) break; } + case LFUN_GRAPHICS_UNIFY: { + + cur.recordUndoFullBuffer(); + + DocIterator from, to; + from = cur.selectionBegin(); + to = cur.selectionEnd(); + + string newId = cmd.getArg(0); + bool fetchId=newId.empty(); //if we wait for groupId from first graphics inset + + InsetGraphicsParams grp_par; + InsetGraphics::string2params(graphics::getGroupParams(buffer_, newId), buffer_, grp_par); + + if (!from.nextInset()) //move to closest inset + from.forwardInset(); + + while (!from.empty() && from < to) { + Inset * inset = from.nextInset(); + if (!inset) + break; + if (inset->lyxCode() == GRAPHICS_CODE) { + InsetGraphics * ig = inset->asInsetGraphics(); + if (!ig) + break; + InsetGraphicsParams inspar = ig->getParams(); + if (fetchId) { + grp_par = inspar; + fetchId = false; + + } else { + grp_par.filename = inspar.filename; + ig->setParams(grp_par); + } + } + from.forwardInset(); + } + dr.screenUpdate(Update::Force); //needed if triggered from context menu + break; + } + case LFUN_STATISTICS: { DocIterator from, to; if (cur.selection()) { diff --git a/src/FuncCode.h b/src/FuncCode.h index 4a5983147d..cce61f0df5 100644 --- a/src/FuncCode.h +++ b/src/FuncCode.h @@ -476,7 +476,8 @@ enum FuncCode LFUN_DEVEL_MODE_TOGGLE, // lasgouttes 20170723 //370 LFUN_EXPORT_CANCEL, // rgh, 20171227 - LFUN_BUFFER_ANONYMIZE, // sanda, 20180201 + LFUN_BUFFER_ANONYMIZE, // sanda, 20180201 + LFUN_GRAPHICS_UNIFY, // sanda, 20180207 LFUN_LASTACTION // end of the table }; diff --git a/src/LyXAction.cpp b/src/LyXAction.cpp index 33d5100a82..871612ed4a 100644 --- a/src/LyXAction.cpp +++ b/src/LyXAction.cpp @@ -3545,6 +3545,17 @@ void LyXAction::init() */ { LFUN_SET_GRAPHICS_GROUP, "set-graphics-group", Noop, Edit }, +/*! + * \var lyx::FuncCode lyx::LFUN_GRAPHICS_UNIFY + * \li Action: Set the same group for all graphics insets in the marked block. + * \li Syntax: graphics-unify [] + * \li Params: : Id for an existing group. In case the Id is an empty string, + the group Id from the first graphics inset will be used. + * \li Origin: sanda, 7 Feb 2018 + * \endvar + */ + { LFUN_GRAPHICS_UNIFY, "graphics-unify", Noop, Edit }, + /*! * \var lyx::FuncCode lyx::LFUN_SPACE_INSERT From 1713b53516f53f854f8431363472ec44259e537f Mon Sep 17 00:00:00 2001 From: Pavel Sanda Date: Fri, 9 Feb 2018 23:46:14 +0100 Subject: [PATCH 035/121] Cosmetics per JMarc's suggestions. --- src/BufferView.cpp | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/BufferView.cpp b/src/BufferView.cpp index edea2eb320..5e5f1bc40a 100644 --- a/src/BufferView.cpp +++ b/src/BufferView.cpp @@ -1667,11 +1667,12 @@ void BufferView::dispatch(FuncRequest const & cmd, DispatchResult & dr) from = cur.selectionBegin(); to = cur.selectionEnd(); - string newId = cmd.getArg(0); - bool fetchId=newId.empty(); //if we wait for groupId from first graphics inset + string const newId = cmd.getArg(0); + bool fetchId = newId.empty(); //if we wait for groupId from first graphics inset InsetGraphicsParams grp_par; - InsetGraphics::string2params(graphics::getGroupParams(buffer_, newId), buffer_, grp_par); + if (!fetchId) + InsetGraphics::string2params(graphics::getGroupParams(buffer_, newId), buffer_, grp_par); if (!from.nextInset()) //move to closest inset from.forwardInset(); @@ -1680,15 +1681,12 @@ void BufferView::dispatch(FuncRequest const & cmd, DispatchResult & dr) Inset * inset = from.nextInset(); if (!inset) break; - if (inset->lyxCode() == GRAPHICS_CODE) { - InsetGraphics * ig = inset->asInsetGraphics(); - if (!ig) - break; + InsetGraphics * ig = inset->asInsetGraphics(); + if (ig) { InsetGraphicsParams inspar = ig->getParams(); if (fetchId) { grp_par = inspar; fetchId = false; - } else { grp_par.filename = inspar.filename; ig->setParams(grp_par); From 25741ca5bd2ff4c7eb55de0fabfa41bbf476c77e Mon Sep 17 00:00:00 2001 From: Pavel Sanda Date: Thu, 15 Feb 2018 21:48:23 +0100 Subject: [PATCH 036/121] Oops, asInsetGrpahics is new to master. --- src/BufferView.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/BufferView.cpp b/src/BufferView.cpp index 5e5f1bc40a..e23883cd06 100644 --- a/src/BufferView.cpp +++ b/src/BufferView.cpp @@ -1681,15 +1681,15 @@ void BufferView::dispatch(FuncRequest const & cmd, DispatchResult & dr) Inset * inset = from.nextInset(); if (!inset) break; - InsetGraphics * ig = inset->asInsetGraphics(); - if (ig) { - InsetGraphicsParams inspar = ig->getParams(); + if (inset->lyxCode() == GRAPHICS_CODE) { + InsetGraphics & ig = static_cast(*inset); + InsetGraphicsParams inspar = ig.getParams(); if (fetchId) { grp_par = inspar; fetchId = false; } else { grp_par.filename = inspar.filename; - ig->setParams(grp_par); + ig.setParams(grp_par); } } from.forwardInset(); From c17f706a1c76cac6f7a9f3c3c8bcfe44b3cfcad9 Mon Sep 17 00:00:00 2001 From: Pavel Sanda Date: Thu, 15 Feb 2018 21:48:47 +0100 Subject: [PATCH 037/121] * status file --- status.23x | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/status.23x b/status.23x index 863f74e7fe..432e5a7c4a 100644 --- a/status.23x +++ b/status.23x @@ -33,6 +33,10 @@ What's new - Handle properly top/bottom of inset with mac-like cursor movement (bug 10701). +- Allow unification of graphic groups inside marked block via context + menu. + + * DOCUMENTATION AND LOCALIZATION From a4a50ac35845b6395e06f8815f85705389f6ac5e Mon Sep 17 00:00:00 2001 From: Pavel Sanda Date: Thu, 15 Feb 2018 22:41:43 +0100 Subject: [PATCH 038/121] * UserGuide - add sentence about graphic groups unification. --- lib/doc/UserGuide.lyx | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/lib/doc/UserGuide.lyx b/lib/doc/UserGuide.lyx index fb8cac9d10..fa0b3081a2 100644 --- a/lib/doc/UserGuide.lyx +++ b/lib/doc/UserGuide.lyx @@ -145,6 +145,7 @@ enumitem \html_math_output 0 \html_css_as_file 0 \html_be_strict true +\author 5863208 "ab" \end_header \begin_body @@ -19952,6 +19953,24 @@ LyX options tab. Joining an existing group can be done using the context menu of the image and checking the name of the desired group. + +\change_inserted 5863208 1518729806 + If there are too many images which need to be assigned to a single group + you can simply put all of them into single selection and choose +\family sans +Unify +\begin_inset space ~ +\end_inset + +Graphics +\begin_inset space ~ +\end_inset + +Groups +\family default + in context menu. +\change_unchanged + \end_layout \begin_layout Section From c0ef31d9b9816a81d00ae3f37625ff69e1be30ec Mon Sep 17 00:00:00 2001 From: Juergen Spitzmueller Date: Wed, 6 Dec 2017 09:11:18 +0100 Subject: [PATCH 039/121] Recreate citation label after paste Fixes: #10829 (cherry picked from commit 7e34e659431691fd723e408010f90973c0a25b39) --- src/CutAndPaste.cpp | 11 +++++++++++ src/insets/InsetCitation.h | 2 ++ 2 files changed, 13 insertions(+) diff --git a/src/CutAndPaste.cpp b/src/CutAndPaste.cpp index f611d59395..57a8313957 100644 --- a/src/CutAndPaste.cpp +++ b/src/CutAndPaste.cpp @@ -40,6 +40,7 @@ #include "insets/InsetBibitem.h" #include "insets/InsetBranch.h" +#include "insets/InsetCitation.h" #include "insets/InsetCommand.h" #include "insets/InsetFlex.h" #include "insets/InsetGraphics.h" @@ -357,6 +358,16 @@ pasteSelectionHelper(DocIterator const & cur, ParagraphList const & parlist, break; } + case CITE_CODE: { + InsetCitation & cit = static_cast(*it); + // This actually only needs to be done if the cite engine + // differs, but we do it in general. + cit.redoLabel(); + // We need to update the list of citations. + need_update = true; + break; + } + case BIBITEM_CODE: { // check for duplicates InsetBibitem & bib = static_cast(*it); diff --git a/src/insets/InsetCitation.h b/src/insets/InsetCitation.h index 992a85ee21..3e5e3baa35 100644 --- a/src/insets/InsetCitation.h +++ b/src/insets/InsetCitation.h @@ -82,6 +82,8 @@ public: static bool isCompatibleCommand(std::string const &); //@} /// + void redoLabel() { cache.recalculate = true; } + /// CitationStyle getCitationStyle(BufferParams const & bp, std::string const & input, std::vector const & valid_styles) const; /// From bd879efaa8107b9064124c186967a500a53e7807 Mon Sep 17 00:00:00 2001 From: Juergen Spitzmueller Date: Sat, 23 Dec 2017 13:25:13 +0100 Subject: [PATCH 040/121] Fix switch of language and line spacing in InTitle commands. Fixes: #9332, #10849 (cherry picked from commit 49e3f8e830a7c8a15f4d9f73e4dab78e93b24bf7) --- src/Paragraph.cpp | 8 +++- src/Spacing.cpp | 22 +++++++++++ src/Spacing.h | 3 ++ src/output_latex.cpp | 88 ++++++++++++++++++++++++++++++++------------ 4 files changed, 96 insertions(+), 25 deletions(-) diff --git a/src/Paragraph.cpp b/src/Paragraph.cpp index c905856e9c..dd0920bda6 100644 --- a/src/Paragraph.cpp +++ b/src/Paragraph.cpp @@ -2426,7 +2426,9 @@ void Paragraph::latex(BufferParams const & bparams, // if the paragraph is empty, the loop will not be entered at all if (empty()) { - if (style.isCommand()) { + // For InTitle commands, we have already opened a group + // in output_latex::TeXOnePar. + if (style.isCommand() && style.intitle) { os << '{'; ++column; } @@ -2464,7 +2466,9 @@ void Paragraph::latex(BufferParams const & bparams, os << "}] "; column +=3; } - if (style.isCommand()) { + // For InTitle commands, we have already opened a group + // in output_latex::TeXOnePar. + if (style.isCommand() && !style.intitle) { os << '{'; ++column; } diff --git a/src/Spacing.cpp b/src/Spacing.cpp index cd5816e600..9ac8345ab4 100644 --- a/src/Spacing.cpp +++ b/src/Spacing.cpp @@ -99,6 +99,18 @@ string envName(Spacing::Space space, bool useSetSpace) return useSetSpace ? name : support::ascii_lowercase(name); } +string cmdName(Spacing::Space space, bool useSetSpace) +{ + static char const * const cmd_names[] + = { "SingleSpacing", "OnehalfSpacing", "DoubleSpacing", "SetStretch", ""}; + string const name = cmd_names[space]; + + if (useSetSpace && name == "SetStretch") + return "setSpacing"; + + return useSetSpace ? name : support::ascii_lowercase(name); +} + } // namespace string const Spacing::writeEnvirBegin(bool useSetSpace) const @@ -118,6 +130,16 @@ string const Spacing::writeEnvirEnd(bool useSetSpace) const } +string const Spacing::writeCmd(bool useSetSpace) const +{ + string const name = cmdName(space, useSetSpace); + if (space == Other) + return "\\" + name + "{" + getValueAsString() + '}'; + else + return name.empty() ? string() : "\\" + name + "{}"; +} + + string const Spacing::writePreamble(bool useSetSpace) const { string preamble; diff --git a/src/Spacing.h b/src/Spacing.h index 274cfc20f2..7311f792b5 100644 --- a/src/Spacing.h +++ b/src/Spacing.h @@ -62,6 +62,9 @@ public: std::string const writeEnvirEnd(bool useSetSpace) const; /// useSetSpace is true when using the variant supported by /// the memoir class. + std::string const writeCmd(bool useSetSpace) const; + /// useSetSpace is true when using the variant supported by + /// the memoir class. std::string const writePreamble(bool useSetSpace) const; private: diff --git a/src/output_latex.cpp b/src/output_latex.cpp index 0ee9af1003..5cac0ad89f 100644 --- a/src/output_latex.cpp +++ b/src/output_latex.cpp @@ -812,6 +812,14 @@ void TeXOnePar(Buffer const & buf, bool const using_begin_end = use_polyglossia || !lang_end_command.empty(); + // For InTitle commands, we need to switch the language inside the command + // (see #10849); thus open the command here. + bool const intitle_command = style.intitle && style.latextype == LATEX_COMMAND; + if (intitle_command) { + parStartCommand(par, os, runparams, style); + os << '{'; + } + // In some insets (such as Arguments), we cannot use \selectlanguage bool const localswitch = text.inset().forceLocalFontSwitch() || (using_begin_end && text.inset().forcePlainLayout()); @@ -975,19 +983,34 @@ void TeXOnePar(Buffer const & buf, os << "\n\\appendix\n"; } - if (!par.params().spacing().isDefault() - && (pit == 0 || !priorpar->hasSameLayout(par))) - { - os << from_ascii(par.params().spacing().writeEnvirBegin(useSetSpace)) - << '\n'; - } + // InTitle commands must use switches (not environments) + // inside the commands (see #9332) + if (style.intitle) { + if (!par.params().spacing().isDefault()) + { + if (runparams.moving_arg) + os << "\\protect"; + os << from_ascii(par.params().spacing().writeCmd(useSetSpace)); + } + } else { + if (!par.params().spacing().isDefault() + && (pit == 0 || !priorpar->hasSameLayout(par))) + { + os << from_ascii(par.params().spacing().writeEnvirBegin(useSetSpace)) + << '\n'; + } - if (style.isCommand()) { - os << '\n'; + if (style.isCommand()) { + os << '\n'; + } } } - parStartCommand(par, os, runparams, style); + // For InTitle commands, we already started the command before + // the language switch + if (!intitle_command) + parStartCommand(par, os, runparams, style); + Font const outerfont = text.outerFont(pit); // FIXME UNICODE @@ -1000,13 +1023,16 @@ void TeXOnePar(Buffer const & buf, bool const is_command = style.isCommand(); - if (is_command) { - os << '}'; - if (!style.postcommandargs().empty()) - latexArgInsets(par, os, runparams, style.postcommandargs(), "post:"); - if (runparams.encoding != prev_encoding) { - runparams.encoding = prev_encoding; - os << setEncoding(prev_encoding->iconvName()); + // InTitle commands need to be closed after the language has been closed. + if (!intitle_command) { + if (is_command) { + os << '}'; + if (!style.postcommandargs().empty()) + latexArgInsets(par, os, runparams, style.postcommandargs(), "post:"); + if (runparams.encoding != prev_encoding) { + runparams.encoding = prev_encoding; + os << setEncoding(prev_encoding->iconvName()); + } } } @@ -1039,12 +1065,13 @@ void TeXOnePar(Buffer const & buf, // possible // fall through default: - // we don't need it for the last paragraph!!! - if (nextpar) + // we don't need it for the last paragraph and in InTitle commands!!! + if (nextpar && !intitle_command) pending_newline = true; } - if (par.allowParagraphCustomization()) { + // InTitle commands use switches (not environments) for space settings + if (par.allowParagraphCustomization() && !style.intitle) { if (!par.params().spacing().isDefault() && (runparams.isLastPar || !nextpar->hasSameLayout(par))) { if (pending_newline) @@ -1060,9 +1087,10 @@ void TeXOnePar(Buffer const & buf, } } - // Closing the language is needed for the last paragraph; it is also - // needed if we're within an \L or \R that we may have opened above (not - // necessarily in this paragraph) and are about to close. + // Closing the language is needed for the last paragraph in a given language + // as well as for any InTitleCommand (since these set the language locally); + // it is also needed if we're within an \L or \R that we may have opened above + // (not necessarily in this paragraph) and are about to close. bool closing_rtl_ltr_environment = !using_begin_end // not for ArabTeX && (par_language->lang() != "arabic_arabtex" @@ -1074,7 +1102,8 @@ void TeXOnePar(Buffer const & buf, &&((nextpar && par_lang != nextpar_lang) || (runparams.isLastPar && par_lang != outer_lang)); - if (closing_rtl_ltr_environment + if ((intitle_command && using_begin_end) + || closing_rtl_ltr_environment || ((runparams.isLastPar || close_lang_switch) && (par_lang != outer_lang || (using_begin_end && style.isEnvironment() @@ -1145,6 +1174,19 @@ void TeXOnePar(Buffer const & buf, if (closing_rtl_ltr_environment) os << "}"; + // InTitle commands need to be closed after the language has been closed. + if (intitle_command) { + if (is_command) { + os << '}'; + if (!style.postcommandargs().empty()) + latexArgInsets(par, os, runparams, style.postcommandargs(), "post:"); + if (runparams.encoding != prev_encoding) { + runparams.encoding = prev_encoding; + os << setEncoding(prev_encoding->iconvName()); + } + } + } + bool const last_was_separator = par.size() > 0 && par.isEnvSeparator(par.size() - 1); From 961b79975c1578c2f35c7c2ff54559d6e54af7a1 Mon Sep 17 00:00:00 2001 From: Juergen Spitzmueller Date: Tue, 26 Dec 2017 11:40:58 +0100 Subject: [PATCH 041/121] Fix inpreamble styles. (cherry picked from commit e55e9c842f25b4425db362cd5cb487187f34ba2b) --- src/Paragraph.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Paragraph.cpp b/src/Paragraph.cpp index dd0920bda6..8830efb1b5 100644 --- a/src/Paragraph.cpp +++ b/src/Paragraph.cpp @@ -2428,7 +2428,7 @@ void Paragraph::latex(BufferParams const & bparams, if (empty()) { // For InTitle commands, we have already opened a group // in output_latex::TeXOnePar. - if (style.isCommand() && style.intitle) { + if (style.isCommand() && (!style.intitle || style.inpreamble)) { os << '{'; ++column; } @@ -2468,7 +2468,7 @@ void Paragraph::latex(BufferParams const & bparams, } // For InTitle commands, we have already opened a group // in output_latex::TeXOnePar. - if (style.isCommand() && !style.intitle) { + if (style.isCommand() && (!style.intitle || style.inpreamble)) { os << '{'; ++column; } From da3dc1b61f5de4eee3a38d9bf72a63852fea1332 Mon Sep 17 00:00:00 2001 From: Juergen Spitzmueller Date: Tue, 26 Dec 2017 13:11:00 +0100 Subject: [PATCH 042/121] Use TeXOnePar for the inpreamble layouts This considers paragraph language and spacing (and simplifies the code) (cherry picked from commit a2f886d52617815e8c80f12ef66198307d3432d6) --- src/Paragraph.cpp | 35 ++++++----------------------------- src/output_latex.cpp | 11 ++++++----- src/output_latex.h | 3 ++- 3 files changed, 14 insertions(+), 35 deletions(-) diff --git a/src/Paragraph.cpp b/src/Paragraph.cpp index 8830efb1b5..52bc993d2a 100644 --- a/src/Paragraph.cpp +++ b/src/Paragraph.cpp @@ -1437,9 +1437,7 @@ bool Paragraph::Private::latexSpecialT3(char_type const c, otexstream & os, void Paragraph::Private::validate(LaTeXFeatures & features) const { if (layout_->inpreamble && inset_owner_) { - bool const is_command = layout_->latextype == LATEX_COMMAND; - Font f; - // Using a string stream here circumvents the encoding + // FIXME: Using a string stream here circumvents the encoding // switching machinery of odocstream. Therefore the // output is wrong if this paragraph contains content // that needs to switch encoding. @@ -1448,32 +1446,11 @@ void Paragraph::Private::validate(LaTeXFeatures & features) const ? buf.masterParams() : buf.params(); otexstringstream os; os << layout_->preamble(); - if (is_command) { - os << '\\' << from_ascii(layout_->latexname()); - // we have to provide all the optional arguments here, even though - // the last one is the only one we care about. - // Separate handling of optional argument inset. - if (!layout_->latexargs().empty()) { - OutputParams rp = features.runparams(); - rp.local_font = &owner_->getFirstFontSettings(bp); - latexArgInsets(*owner_, os, rp, layout_->latexargs()); - } - os << from_ascii(layout_->latexparam()); - } size_t const length = os.length(); - // this will output "{" at the beginning, but not at the end - owner_->latex(bp, f, os, features.runparams(), 0, -1, true); - if (os.length() > length) { - if (is_command) { - os << '}'; - if (!layout_->postcommandargs().empty()) { - OutputParams rp = features.runparams(); - rp.local_font = &owner_->getFirstFontSettings(bp); - latexArgInsets(*owner_, os, rp, layout_->postcommandargs(), "post:"); - } - } + TeXOnePar(buf, buf.text(), buf.getParFromID(owner_->id()).pit(), os, + features.runparams(), string(), 0, -1, true); + if (os.length() > length) features.addPreambleSnippet(os.release(), true); - } } if (features.runparams().flavor == OutputParams::HTML @@ -2428,7 +2405,7 @@ void Paragraph::latex(BufferParams const & bparams, if (empty()) { // For InTitle commands, we have already opened a group // in output_latex::TeXOnePar. - if (style.isCommand() && (!style.intitle || style.inpreamble)) { + if (style.isCommand() && !style.intitle) { os << '{'; ++column; } @@ -2468,7 +2445,7 @@ void Paragraph::latex(BufferParams const & bparams, } // For InTitle commands, we have already opened a group // in output_latex::TeXOnePar. - if (style.isCommand() && (!style.intitle || style.inpreamble)) { + if (style.isCommand() && !style.intitle) { os << '{'; ++column; } diff --git a/src/output_latex.cpp b/src/output_latex.cpp index 5cac0ad89f..f8bb151954 100644 --- a/src/output_latex.cpp +++ b/src/output_latex.cpp @@ -683,7 +683,8 @@ void TeXOnePar(Buffer const & buf, otexstream & os, OutputParams const & runparams_in, string const & everypar, - int start_pos, int end_pos) + int start_pos, int end_pos, + bool const force) { BufferParams const & bparams = runparams_in.is_child ? buf.masterParams() : buf.params(); @@ -694,7 +695,7 @@ void TeXOnePar(Buffer const & buf, Layout const & style = text.inset().forcePlainLayout() ? bparams.documentClass().plainLayout() : par.layout(); - if (style.inpreamble) + if (style.inpreamble && !force) return; LYXERR(Debug::LATEX, "TeXOnePar for paragraph " << pit << " ptr " << &par << " '" @@ -728,7 +729,7 @@ void TeXOnePar(Buffer const & buf, os << '\n'; } - par.latex(bparams, outerfont, os, runparams, start_pos, end_pos); + par.latex(bparams, outerfont, os, runparams, start_pos, end_pos, force); return; } @@ -739,7 +740,7 @@ void TeXOnePar(Buffer const & buf, Font const outerfont = text.outerFont(pit); parStartCommand(par, os, runparams, style); - par.latex(bparams, outerfont, os, runparams, start_pos, end_pos); + par.latex(bparams, outerfont, os, runparams, start_pos, end_pos, force); // I did not create a parEndCommand for this minuscule // task because in the other user of parStartCommand @@ -1015,7 +1016,7 @@ void TeXOnePar(Buffer const & buf, // FIXME UNICODE os << from_utf8(everypar); - par.latex(bparams, outerfont, os, runparams, start_pos, end_pos); + par.latex(bparams, outerfont, os, runparams, start_pos, end_pos, force); Font const font = par.empty() ? par.getLayoutFont(bparams, outerfont) diff --git a/src/output_latex.h b/src/output_latex.h index 1dd9689851..cf37173604 100644 --- a/src/output_latex.h +++ b/src/output_latex.h @@ -91,7 +91,8 @@ void TeXOnePar(Buffer const & buf, otexstream & os, OutputParams const & runparams, std::string const & everypar = std::string(), - int start_pos = -1, int end_pos = -1); + int start_pos = -1, int end_pos = -1, + bool const force = false); } // namespace lyx From d20de88953e260d081c0a917bcbec3c0cc6b3e96 Mon Sep 17 00:00:00 2001 From: Juergen Spitzmueller Date: Wed, 27 Dec 2017 11:49:54 +0100 Subject: [PATCH 043/121] Open intitle command explicitly also for passthru. (cherry picked from commit 87960e3dd892cd7c60925efd44d40f593ac7883e) --- src/output_latex.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/output_latex.cpp b/src/output_latex.cpp index f8bb151954..67f9bdd08c 100644 --- a/src/output_latex.cpp +++ b/src/output_latex.cpp @@ -736,9 +736,13 @@ void TeXOnePar(Buffer const & buf, Paragraph const * nextpar = runparams.isLastPar ? 0 : ¶graphs.at(pit + 1); + bool const intitle_command = style.intitle && style.latextype == LATEX_COMMAND; + if (style.pass_thru) { Font const outerfont = text.outerFont(pit); parStartCommand(par, os, runparams, style); + if (intitle_command) + os << '{'; par.latex(bparams, outerfont, os, runparams, start_pos, end_pos, force); @@ -815,7 +819,6 @@ void TeXOnePar(Buffer const & buf, // For InTitle commands, we need to switch the language inside the command // (see #10849); thus open the command here. - bool const intitle_command = style.intitle && style.latextype == LATEX_COMMAND; if (intitle_command) { parStartCommand(par, os, runparams, style); os << '{'; From a26173f171bbb11504f3d81f0d882bd6b6e67359 Mon Sep 17 00:00:00 2001 From: Juergen Spitzmueller Date: Fri, 16 Feb 2018 17:47:14 +0100 Subject: [PATCH 044/121] Revove unused variable --- src/Paragraph.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Paragraph.cpp b/src/Paragraph.cpp index 52bc993d2a..135cd80fec 100644 --- a/src/Paragraph.cpp +++ b/src/Paragraph.cpp @@ -1442,8 +1442,6 @@ void Paragraph::Private::validate(LaTeXFeatures & features) const // output is wrong if this paragraph contains content // that needs to switch encoding. Buffer const & buf = inset_owner_->buffer(); - BufferParams const & bp = features.runparams().is_child - ? buf.masterParams() : buf.params(); otexstringstream os; os << layout_->preamble(); size_t const length = os.length(); From e1f7cc964bdc46d63f03089eff656b68146f94bb Mon Sep 17 00:00:00 2001 From: Juergen Spitzmueller Date: Fri, 16 Feb 2018 18:19:05 +0100 Subject: [PATCH 045/121] update status --- status.23x | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/status.23x b/status.23x index 432e5a7c4a..b6c4427c49 100644 --- a/status.23x +++ b/status.23x @@ -15,7 +15,7 @@ What's new * DOCUMENT INPUT/OUTPUT -- it possible to anonymize document's content for bug submissions +- It possible to anonymize document's content for bug submissions via buffer-anonymize lfun (bug 7259). @@ -49,6 +49,9 @@ What's new * DOCUMENT INPUT/OUTPUT +- Fix language settings annd line spacing in InPreamble-titles + (bug 9332, 1049). + * LYX2LYX @@ -59,6 +62,9 @@ What's new - Improve rendering of square roots in math editor (bug 10814). +- Fix display of citation labels when pasting from a document + with other citation type (bug 10829). + * INTERNALS From f135013b3075f3e077f05b5fcc2bdc9e86825f4c Mon Sep 17 00:00:00 2001 From: Pavel Sanda Date: Sat, 17 Feb 2018 19:01:53 +0100 Subject: [PATCH 046/121] * eu.po - update from Inaki. --- po/eu.po | 184 +++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 116 insertions(+), 68 deletions(-) diff --git a/po/eu.po b/po/eu.po index b858bc1f9b..6a358e3b84 100644 --- a/po/eu.po +++ b/po/eu.po @@ -10,7 +10,7 @@ msgstr "" "Project-Id-Version: lyx_2.0.0_eu\n" "Report-Msgid-Bugs-To: lyx-devel@lists.lyx.org\n" "POT-Creation-Date: 2018-02-12 16:39+0100\n" -"PO-Revision-Date: 2018-02-12 20:50+0100\n" +"PO-Revision-Date: 2018-02-17 18:34+0100\n" "Last-Translator: Inaki Larranaga Murgoitio \n" "Language-Team: Basque \n" "Language: eu\n" @@ -627,9 +627,10 @@ msgstr "Hautatu adarra" msgid "Inverted" msgstr "Alderantzikatuta" +# adarra #: src/frontends/qt4/ui/BranchesUi.ui:25 msgid "&New:[[branch]]" -msgstr "&Berria:[[adarra]]" +msgstr "&Berria:" #: src/frontends/qt4/ui/BranchesUi.ui:35 msgid "" @@ -2084,9 +2085,12 @@ msgstr "Estekatu fitxategia" msgid "Fi&le" msgstr "&Fitxategia" +# 'listing' pakete baten izena da, progamazioko iturburua nabarmentzeko eginbidea eskaintzen du. LyX-eko agerpenetan 'zerrendatua' gisa euskaratu da. +# +# https://en.wikibooks.org/wiki/LaTeX/Source_Code_Listings #: src/frontends/qt4/ui/IncludeUi.ui:36 msgid "Listing Parameters" -msgstr "Zerrendaren parametroak" +msgstr "Zerrendatuaren parametroak" #: src/frontends/qt4/ui/IncludeUi.ui:66 #: src/frontends/qt4/ui/ListingsSettingsUi.ui:79 @@ -2148,10 +2152,11 @@ msgstr "Sarrera" msgid "Verbatim" msgstr "Hitzez hitz" +# erabili 'zerrendatua' termino 'listing' terminoaren itzulen gisa #: src/frontends/qt4/ui/IncludeUi.ui:308 src/insets/InsetInclude.cpp:1305 #: src/insets/InsetInclude.cpp:1311 msgid "Program Listing" -msgstr "Programaren zerrenda" +msgstr "Iturburuaren zerrendatua" #: src/frontends/qt4/ui/IncludeUi.ui:342 msgid "Edit the file" @@ -2197,9 +2202,10 @@ msgstr "Aktibatu hainbat indize behar badituzu (adib. Izenen indizea)" msgid "&Use multiple indexes" msgstr "&Erabili indize anitzak" +# indizea #: src/frontends/qt4/ui/IndicesUi.ui:114 msgid "&New:[[index]]" -msgstr "&Berria:[[indizea]]" +msgstr "&Berria:" #: src/frontends/qt4/ui/IndicesUi.ui:124 msgid "" @@ -2407,7 +2413,7 @@ msgstr "Lerroaren lodieraren balioa." #: src/frontends/qt4/ui/ListingsSettingsUi.ui:47 msgid "Input here the listings parameters" -msgstr "Sartu hemen zerrenden parametroak" +msgstr "Sartu hemen zerrendatuaren parametroak" #: src/frontends/qt4/ui/ListingsSettingsUi.ui:63 #: src/frontends/qt4/ui/ListingsUi.ui:477 @@ -2427,7 +2433,7 @@ msgstr "&Sintaxiaren nabarmentzeko paketea:" #: lib/layouts/stdinsets.inc:388 src/insets/InsetCaption.cpp:388 #: src/insets/InsetListings.cpp:464 src/insets/InsetListings.cpp:466 msgid "Listing" -msgstr "Zerrenda" +msgstr "Zerrendatua" #: src/frontends/qt4/ui/ListingsUi.ui:23 msgid "&Main Settings" @@ -2439,15 +2445,15 @@ msgstr "Kokapena" #: src/frontends/qt4/ui/ListingsUi.ui:35 msgid "Check for inline listings" -msgstr "Aktibatu lerroko zerrendentzako" +msgstr "Aktibatu lerroko zerrendatuak" #: src/frontends/qt4/ui/ListingsUi.ui:38 msgid "&Inline listing" -msgstr "&Lerroko zerrenda" +msgstr "&Lerroko zerrendatuak" #: src/frontends/qt4/ui/ListingsUi.ui:45 msgid "Check for floating listings" -msgstr "Aktibatu zerrenda mugikorrentzako" +msgstr "Aktibatu zerrendatu mugikorrentzako" #: src/frontends/qt4/ui/ListingsUi.ui:48 msgid "&Float" @@ -2459,7 +2465,7 @@ msgstr "&Kokapena:" #: src/frontends/qt4/ui/ListingsUi.ui:68 msgid "Specify placement (htbp) for floating listings" -msgstr "Zehaztu zerrenda mugikorren kokapena (htpb)" +msgstr "Zehaztu zerrendatu mugikorren kokapena (htpb)" #: src/frontends/qt4/ui/ListingsUi.ui:78 msgid "Line numbering" @@ -2593,7 +2599,7 @@ msgstr "Parametro gehiago" #: src/frontends/qt4/ui/ListingsUi.ui:499 msgid "Input listing parameters here. Enter ? for a list of parameters." msgstr "" -"Sartu zerrendaren parametroak hemen. Sartu ? parametroen zerrenda " +"Sartu zerrendatuaren parametroak hemen. Sartu ? parametroen zerrenda " "eskuratzeko." #: src/frontends/qt4/ui/LocalLayoutUi.ui:19 @@ -3899,10 +3905,11 @@ msgstr "Automatikoa" msgid "Always Babel" msgstr "Beti erabili Babel" +# hizkuntzaren paketea #: src/frontends/qt4/ui/PrefLanguageUi.ui:71 #: src/frontends/qt4/GuiDocument.cpp:1095 msgid "None[[language package]]" -msgstr "Bat ere ez [[hizkuntzaren paketea]]" +msgstr "Bat ere ez" #: src/frontends/qt4/ui/PrefLanguageUi.ui:88 msgid "Command s&tart:" @@ -4524,9 +4531,10 @@ msgstr "Bistaratu egoera-barrako mezuak?" msgid "&Statusbar messages" msgstr "&Egoera-barrako mezuak" +# bufferra #: src/frontends/qt4/ui/RefUi.ui:73 msgid "&In[[buffer]]:" -msgstr "&Sarrera[[bufferra]]:" +msgstr "&Sarrera:" #: src/frontends/qt4/ui/RefUi.ui:92 msgid "Filter case-sensitively" @@ -4655,9 +4663,10 @@ msgstr "Ez atera etiketaren \":\" aurreko zatia" msgid "No Prefix" msgstr "Aurrizkirik ez" +# bilaketa #: src/frontends/qt4/ui/SearchUi.ui:101 msgid "Case &sensitive[[search]]" -msgstr "Maiuskula/&Minuskula[[bilaketa]]" +msgstr "Maiuskula/&minuskula" #: src/frontends/qt4/ui/SearchUi.ui:108 msgid "Match w&hole words only" @@ -5535,10 +5544,11 @@ msgstr "Aipu automatikoa" msgid "Auto" msgstr "Automatikoa" +# Egile guztien aukerako ordezkoa #: lib/citeengines/biblatex-natbib.citeengine:150 #: lib/citeengines/biblatex.citeengine:142 msgid "F&orce full title[[Possible substitute to All aut&hors]]" -msgstr "&Derrigortu titulu osoa[[Egile guztien aukerako ordezkoa]]" +msgstr "&Derrigortu titulu osoa" #: lib/citeengines/biblatex-natbib.citeengine:151 #: lib/citeengines/biblatex.citeengine:143 @@ -5573,9 +5583,10 @@ msgstr "" "Biblatex arruntaren antzera, bibliografiaren prozesadore gisa 'biber' " "erabiltzea gomendatzen da." +# Egile guztien aukerako ordezkoa #: lib/citeengines/biblatex.citeengine:140 msgid "S&horten author list[[Possible substitute to All aut&hors]]" -msgstr "Egile &laburren zerrenda[[Egile &guztien aukerako ordezkoa]]" +msgstr "Egile &laburren zerrenda" #: lib/citeengines/biblatex.citeengine:141 msgid "Force a short author list (using et al.)" @@ -7519,17 +7530,20 @@ msgstr "Diagrama" msgid "List of Charts" msgstr "Diagramen zerrenda" +# matematikoak #: lib/layouts/achemso.layout:210 msgid "Graphs[[mathematical]]" -msgstr "Grafikoak[[matematikoak]]" +msgstr "Grafikoak" +# matematikoak #: lib/layouts/achemso.layout:216 lib/layouts/achemso.layout:228 msgid "Graph[[mathematical]]" -msgstr "Grafikoa[[matematikoak]]" +msgstr "Grafikoa" +# matematikoak #: lib/layouts/achemso.layout:222 msgid "List of Graphs[[mathematical]]" -msgstr "Grafikoen zerrenda[[matematikoak]]" +msgstr "Grafikoen zerrenda" #: lib/layouts/achemso.layout:256 msgid "SupplementalInfo" @@ -15374,7 +15388,7 @@ msgstr "Indize-sarrerak" #: lib/layouts/stdinsets.inc:16 msgid "Listings" -msgstr "Zerrendak" +msgstr "Zerrendatuak" #: lib/layouts/stdinsets.inc:19 src/insets/InsetMarginal.cpp:36 msgid "margin" @@ -15394,18 +15408,20 @@ msgstr "Grisa" msgid "ERT" msgstr "ITG" +# Sarreren zerrenda edo programen zerrenda... #: lib/layouts/stdinsets.inc:287 lib/layouts/stdinsets.inc:293 msgid "Listings[[List of Listings]]" -msgstr "Zerrendak[[Zerrenden zerrenda]]" +msgstr "Zerrendatuak" #: lib/layouts/stdinsets.inc:310 lib/layouts/stdinsets.inc:316 #: src/insets/InsetTOC.cpp:77 msgid "List of Listings" -msgstr "Zerrenden zerrenda" +msgstr "Zerrendatuen zerrenda" +# txertakuntza #: lib/layouts/stdinsets.inc:344 src/frontends/qt4/GuiDocument.cpp:1509 msgid "Listings[[inset]]" -msgstr "Zerrendak[[txertakuntza]]" +msgstr "Zerrendatuak" #: lib/layouts/stdinsets.inc:407 msgid "Idx" @@ -15423,17 +15439,20 @@ msgstr "etiketa gabe" msgid "Preview" msgstr "Aurrebista" +# nomenklatura #: lib/layouts/stdinsets.inc:703 lib/layouts/stdinsets.inc:711 msgid "see equation[[nomencl]]" -msgstr "ikus ekuazioa[[nomenklatura]]" +msgstr "ikus ekuazioa" +# nomenklatura #: lib/layouts/stdinsets.inc:704 lib/layouts/stdinsets.inc:712 msgid "page[[nomencl]]" -msgstr "orrialdea[[nomenklatura]]" +msgstr "orrialdea" +# irteera #: lib/layouts/stdinsets.inc:705 lib/layouts/stdinsets.inc:713 msgid "Nomenclature[[output]]" -msgstr "Nomenklatura[[irteera]]" +msgstr "Nomenklatura" #: lib/layouts/stdlayouts.inc:99 msgid "Verbatim*" @@ -18107,7 +18126,7 @@ msgstr "Berritsua (tarteak markatuta)|e" #: lib/ui/stdcontext.inc:296 lib/ui/stdcontext.inc:581 msgid "Listing|L" -msgstr "Zerrenda|Z" +msgstr "Zerrendatua|Z" #: lib/ui/stdcontext.inc:300 lib/ui/stdcontext.inc:585 msgid "Edit Included File...|E" @@ -18768,7 +18787,7 @@ msgstr "Informazioaren ezarpenak...|f" #: lib/ui/stdmenus.inc:149 msgid "Listings Settings...|g" -msgstr "Zerrenden ezarpenak..|r" +msgstr "Zerrendatuen ezarpenak..|r" #: lib/ui/stdmenus.inc:153 msgid "Table Settings...|a" @@ -19126,9 +19145,10 @@ msgstr "Txertakuntza pertsonalizatuak" msgid "File|e" msgstr "Fitxategia|F" +# menua #: lib/ui/stdmenus.inc:379 msgid "Box[[Menu]]|x" -msgstr "Kutxa[[menua]]|x" +msgstr "Kutxa|x" #: lib/ui/stdmenus.inc:382 msgid "Citation...|C" @@ -19170,9 +19190,10 @@ msgstr "Oin-oharra|n" msgid "Marginal Note|M" msgstr "Albo-oharra|A" +# menua #: lib/ui/stdmenus.inc:395 msgid "Program Listing[[Menu]]" -msgstr "Programen zerrenda[[menua]]" +msgstr "Iturburuaren zerrendatua" #: lib/ui/stdmenus.inc:402 src/insets/Inset.cpp:92 msgid "TeX Code" @@ -19304,7 +19325,7 @@ msgstr "Gaien aurkibidea|G" #: lib/ui/stdmenus.inc:487 msgid "List of Listings|L" -msgstr "Zerrenden zerrenda|Z" +msgstr "Zerrendatuen zerrenda|Z" #: lib/ui/stdmenus.inc:488 msgid "Nomenclature|N" @@ -20022,9 +20043,10 @@ msgstr "IPA tonuen eta hitzen azentuak" msgid "Command Buffer" msgstr "Komandoaren bufferra" +# tresna-barra #: lib/ui/stdtoolbars.inc:232 msgid "Review[[Toolbar]]" -msgstr "Berrikusi[[tresna-barra]]" +msgstr "Berrikusi" #: lib/ui/stdtoolbars.inc:233 msgid "Track changes" @@ -21117,9 +21139,10 @@ msgstr "doteq" msgid "neq" msgstr "neq" +# erlazio matematikoa #: lib/ui/stdtoolbars.inc:584 msgid "in[[math relation]]" -msgstr "in[[erlazio matematikoa]]" +msgstr "in" #: lib/ui/stdtoolbars.inc:585 msgid "ni" @@ -24921,10 +24944,12 @@ msgstr "LyX artxiboa (zip)" msgid "LyX Archive (tar.gz)" msgstr "LyX artxiboa (tar.gz)" +# %1$s : izena +# %2$s helb elektronikoa #: src/Author.cpp:57 #, c-format msgid "%1$s[[name]] (%2$s[[email]])" -msgstr "%1$s[[name]] (%2$s[[email]])" +msgstr "%1$s (%2$s)" #: src/BiblioInfo.cpp:797 src/BiblioInfo.cpp:847 src/BiblioInfo.cpp:858 #: src/BiblioInfo.cpp:913 src/BiblioInfo.cpp:917 @@ -26110,7 +26135,7 @@ msgstr "kutxak itzaldurarekin" #: src/Color.cpp:244 msgid "listings background" -msgstr "zerrenden atzeko planoa" +msgstr "zerrendatuaren atzeko planoa" #: src/Color.cpp:245 msgid "branch label" @@ -27884,10 +27909,12 @@ msgstr "Karakterea ez da kodekagarria 'hitzez hitz' testuinguran." msgid "[Change Tracking] " msgstr "[Aldaketen jarraipena] " +# %1$s: egila +# %2$s: data #: src/Text.cpp:1912 #, c-format msgid "Changed by %1$s[[author]] on %2$s[[date]]. " -msgstr "Aldatuta: %1$s[[author]] -- %2$s[[date]]. " +msgstr "Aldatuta: %1$s -- %2$s. " #: src/Text.cpp:1922 src/mathed/InsetMathFont.cpp:237 #: src/mathed/InsetMathFontOld.cpp:111 @@ -28460,9 +28487,10 @@ msgstr "" msgid "Could not read template" msgstr "Ezin izan da txantiloia irakurri" +# buletak #: src/frontends/qt4/BulletsModule.cpp:41 msgid "Standard[[Bullets]]" -msgstr "Arrunta[[buletak]]" +msgstr "Arrunta" #: src/frontends/qt4/BulletsModule.cpp:42 msgid "Maths" @@ -29287,21 +29315,25 @@ msgstr "desberdintasunak" msgid "Compare different revisions" msgstr "Konparatu bertsio desberdinak" +# mugatzailearen tamaina #: src/frontends/qt4/GuiDelimiter.cpp:61 msgid "big[[delimiter size]]" -msgstr "handia[[mugatzailearen tamaina]]" +msgstr "handia" +# mugatzailearen tamaina #: src/frontends/qt4/GuiDelimiter.cpp:62 msgid "Big[[delimiter size]]" -msgstr "Handia[[mugatzailearen tamaina]]" +msgstr "Handia" +# mugatzailearen tamaina #: src/frontends/qt4/GuiDelimiter.cpp:63 msgid "bigg[[delimiter size]]" -msgstr "Oso handia[[mugatzailearen tamaina]]" +msgstr "oso handia" +# mugatzailearen tamaina #: src/frontends/qt4/GuiDelimiter.cpp:64 msgid "Bigg[[delimiter size]]" -msgstr "Oso Handia[[mugatzailearen tamaina]]" +msgstr "Oso handia" #: src/frontends/qt4/GuiDelimiter.cpp:184 msgid "Math Delimiter" @@ -29589,7 +29621,8 @@ msgstr "" #: src/frontends/qt4/GuiDocument.cpp:1622 msgid "Input listings parameters below. Enter ? for a list of parameters." msgstr "" -"Sarrerako zerrenden parametroak azpian. Sartu ? parametroen zerrendarentzako." +"Sarrerako zerrendatuen parametroak azpian. Sartu ? parametroen " +"zerrendarentzako." #: src/frontends/qt4/GuiDocument.cpp:1493 msgid "Document Class" @@ -29639,9 +29672,10 @@ msgstr "Mugikor-kokapena" msgid "Bullets" msgstr "Buletak" +# irteera #: src/frontends/qt4/GuiDocument.cpp:1512 msgid "Formats[[output]]" -msgstr "Formatuak[[irteera]]" +msgstr "Formatuak" #: src/frontends/qt4/GuiDocument.cpp:1513 msgid "LaTeX Preamble" @@ -30042,9 +30076,10 @@ msgstr "cm" msgid "mm" msgstr "mm" +# neurketaren unitatea #: src/frontends/qt4/GuiGraphics.cpp:500 src/lengthcommon.cpp:42 msgid "in[[unit of measure]]" -msgstr "in[[neurketaren unitatea]]" +msgstr "in" #: src/frontends/qt4/GuiGraphics.cpp:780 msgid "Select graphics file" @@ -30132,7 +30167,7 @@ msgstr "Hiperestekaren ezarpenak" msgid "" "Input listing parameters on the right. Enter ? for a list of parameters." msgstr "" -"Sartu zerrendaren parametroak eskuinean. Sartu ? parametroak zerrendatzeko." +"Sartu zerrendatuaren parametroak eskuinean. Sartu ? parametroak zerrendatzeko." #: src/frontends/qt4/GuiInclude.cpp:312 msgid "Select document to include" @@ -30242,7 +30277,7 @@ msgstr "Hizkuntzarik ez" #: src/frontends/qt4/GuiListings.cpp:166 msgid "Program Listing Settings" -msgstr "Programen zerrendaren ezarpenak" +msgstr "Iturburuaren zerrendatuaren ezarpenak" #: src/frontends/qt4/GuiListings.cpp:424 msgid "No dialect" @@ -31631,9 +31666,10 @@ msgstr "Desgaitu shell-aren ihes-ikurra" msgid "Code Preview" msgstr "Kodearen aurrebista" +# aurrebista-formatuaren izena #: src/frontends/qt4/GuiViewSource.cpp:457 msgid "%1[[preview format name]] Preview" -msgstr "%1[[aurrebista-formatuaren izena]] aurrebista" +msgstr "%1 aurrebista" #: src/frontends/qt4/GuiWorkArea.cpp:1600 msgid "Close File" @@ -31830,13 +31866,15 @@ msgstr "%1$s (dinamikoa)" msgid "Use dynamic quotes (%1$s)|d" msgstr "Erabili komatxo dinamikoak (%1$s)|d" +# Komatxoak #: src/frontends/qt4/Menus.cpp:1832 msgid "dynamic[[Quotes]]" -msgstr "dinamikoa[[Komatxoak]]" +msgstr "dinamikoa" +# Komatxoak #: src/frontends/qt4/Menus.cpp:1832 src/frontends/qt4/Menus.cpp:1842 msgid "static[[Quotes]]" -msgstr "estatikoa[[Komatxoak]]" +msgstr "estatikoa" #: src/frontends/qt4/Menus.cpp:1834 #, c-format @@ -31988,13 +32026,14 @@ msgstr "" "%1$s gakoa badago lehendik ere.\n" "Hona aldatuko da: %2$s." +# BibTeX/Biblatex #: src/insets/InsetBibtex.cpp:156 #, c-format msgid "" "The %1$s[[BibTeX/Biblatex]] inset includes %2$s databases.\n" "If you proceed, all of them will be opened." msgstr "" -"%1$s[[BibTeX/Biblatex]] txertakuntzak %2$s datu-base ditu.\n" +"%1$s txertakuntzak %2$s datu-base ditu.\n" "Aurrera jarraitzen baduzu, guzti horiek irekiko dira." #: src/insets/InsetBibtex.cpp:159 @@ -32494,17 +32533,18 @@ msgid "" "For the time being, I have replaced '!' by a warning, but you\n" "must investigate!" msgstr "" -"Lerroko programen zerrendetan, karaktere bat\n" +"Lerroko iturburuen zerrendatuetan, karaktere bat\n" "mugatzaile gisa gorde behar da. Hala ere,\n" -"zerrendetariko batek karaktere guztiak\n" +"zerrendatutako batek karaktere guztiak\n" "darabilzkienez, ez da bat bera ere erabilgarri gelditzen.\n" "Oraingoz, '!' abisu batekin ordeztu da, baina ikertu egin\n" "behar duzu." #: src/insets/InsetListings.cpp:347 src/insets/InsetListings.cpp:356 msgid "Uncodable characters in listings inset" -msgstr "Kodetu ezin daitezkeen karaktereak zerrenden txertakuntzan" +msgstr "Kodetu ezin daitezkeen karaktereak zerrendatuen txertakuntzan" +# Paketea aipatzean, bere jatorrizko izena komatxoen artean erabili: 'listings' #: src/insets/InsetListings.cpp:348 #, c-format msgid "" @@ -32516,7 +32556,7 @@ msgid "" "Toggling 'Use non-TeX fonts' in Document > Settings...\n" "might help." msgstr "" -"Programen zerrendetako bateko honako karaktereak\n" +"Iturburuen zerrendatuetako batean honako karaktereak\n" "ezin dira uneko kodeketarekin adierazi, eta kanpoan utzi dira:\n" "%1$s.\n" "'listings' paketearen murriztapen bat da hau, '%2$s' kodeketa\n" @@ -32531,7 +32571,7 @@ msgid "" "not representable in the current encoding and have been omitted:\n" "%1$s." msgstr "" -"Programen zerrendetako bateko honako karaktereak\n" +"Iturburuen zerrendatutako batean honako karaktereak\n" "ezin dira uneko kodeketarekin adierazi, eta kanpoan utzi dira:\n" "%1$s." @@ -32658,7 +32698,7 @@ msgid "" msgstr "" "Parametroa ez litzakete hemen sartu behar. Erabili epigrafearen edizio-" "koadroa (ume-dokumentuaren elkarrizketa-koadroa erabiltzean) edo Txertatu-" -">Epigrafea menua (zerrendaren txertakuntza bat definitzean)" +">Epigrafea menua (zerrendatuaren txertakuntza bat definitzean)" #: src/insets/InsetListingsParams.cpp:468 #: src/insets/InsetListingsParams.cpp:678 @@ -32669,7 +32709,7 @@ msgid "" msgstr "" "Parametroa ez litzakete hemen sartu behar. Erabili etiketaren edizio-koadroa " "(ume-dokumentuaren elkarrizketa-koadroa erabiltzean) edo Txertatu->Etiketa " -"menua (zerrendaren txertakuntza bat definitzean)" +"menua (zerrendatuaren txertakuntza bat definitzean)" #: src/insets/InsetListingsParams.cpp:689 msgid "default: _minted-" @@ -32705,7 +32745,8 @@ msgid "" "inset, it is better using the language combo box, unless you need to enter " "a language not offered there, otherwise the combo box will be disabled." msgstr "" -"Sartu onartutako hizkuntzetariko bat. Hala ere, zerrenden txertakuntza bat " +"Sartu onartutako hizkuntzetariko bat. Hala ere, zerrendatuaren txertakuntza " +"bat " "definitzen ari bazara, egokiagoa da hizkuntzaren konbinazio-koadroa " "erabiltzea, hemen eskaintzen ez den hizkuntza bat sartu behar ez baduzu " "bederen. Bestela, konbinazio-koadroa desgaituko baita." @@ -32741,17 +32782,17 @@ msgstr "Latex kodea iruzkinetan gaitzen du" #: src/insets/InsetListingsParams.cpp:898 msgid "Invalid (empty) listing parameter name." -msgstr "Zerrendaren parametro-izen baliogabea (hutsa)." +msgstr "Zerrendatuaren parametro-izen baliogabea (hutsa)." #: src/insets/InsetListingsParams.cpp:914 #, c-format msgid "Available listing parameters are %1$s" -msgstr "Zerrendaren parametro erabilgarriak: %1$s" +msgstr "Zerrendatuaren parametro erabilgarriak: %1$s" #: src/insets/InsetListingsParams.cpp:917 #, c-format msgid "Available listings parameters containing string \"%1$s\" are %2$s" -msgstr "\"%1$s\" katea duten zerrendaren parametro erabilgarriak: %2$s" +msgstr "\"%1$s\" katea duten zerrendatuaren parametro erabilgarriak: %2$s" #: src/insets/InsetListingsParams.cpp:928 #, c-format @@ -32761,7 +32802,7 @@ msgstr "%1$s parametroa: " #: src/insets/InsetListingsParams.cpp:941 #, c-format msgid "Unknown listing parameter name: %1$s" -msgstr "Zerrendaren parametro-izen ezezaguna: %1$s" +msgstr "Zerrendatuaren parametro-izen ezezaguna: %1$s" #: src/insets/InsetListingsParams.cpp:944 #, c-format @@ -32828,15 +32869,17 @@ msgstr "mamuh" msgid "vphantom" msgstr "mamub" +# komatxoak #: src/insets/InsetQuotes.cpp:567 #, c-format msgid "%1$souter%2$s and %3$sinner%4$s[[quotation marks]]" -msgstr "%1$souter%2$s eta %3$sinner%4$s[[komatxoak]]" +msgstr "%1$souter%2$s eta %3$sinner%4$s" +# komatxoaren azalpena #: src/insets/InsetQuotes.cpp:577 #, c-format msgid "%1$s[[quot. mark description]] (language default)" -msgstr "%1$s[[azalpenaren komatxoak]] (hizkuntzaren lehenetsia)" +msgstr "%1$s (hizkuntzaren lehenetsia)" #: src/insets/InsetQuotes.cpp:590 #, c-format @@ -33062,9 +33105,10 @@ msgstr "Aurrebista prest" msgid "Preview failed" msgstr "Aurrebistak huts egin du" +# neurketaren unitatea #: src/lengthcommon.cpp:41 msgid "cc[[unit of measure]]" -msgstr "cc[[neurketaren unitatea]]" +msgstr "cc" #: src/lengthcommon.cpp:41 msgid "dd" @@ -33078,9 +33122,10 @@ msgstr "em" msgid "ex" msgstr "ex" +# neurketaren unitatea #: src/lengthcommon.cpp:42 msgid "mu[[unit of measure]]" -msgstr "mu[[neurketaren unitatea]]" +msgstr "mu" #: src/lengthcommon.cpp:42 msgid "pc" @@ -33311,9 +33356,12 @@ msgstr "Adierazpen erregularren editore modua" msgid "Autocorrect On ( to exit)" msgstr "Zuzenketa automatikoa gaituta ( amaitzeko)" +# Oharra [[xxxx]] ez da euskaratu edo itzuli behar. Itzulpenaren testuingurua azaltzeko soilik erabiltzen da. +# +# mathref #: src/mathed/InsetMathRef.cpp:240 msgid "Standard[[mathref]]" -msgstr "Arrunta[[mathref]]" +msgstr "Arrunta" #: src/mathed/InsetMathRef.cpp:245 msgid "PrettyRef" From 2136af92b5b64f4488e765f52bf5a41d27106e9c Mon Sep 17 00:00:00 2001 From: Pavel Sanda Date: Sat, 17 Feb 2018 19:07:02 +0100 Subject: [PATCH 047/121] * layouttranslations reviewed by Inaki --- lib/layouttranslations | 10 +++++----- lib/layouttranslations.review | 5 ++--- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/lib/layouttranslations b/lib/layouttranslations index f350f2327c..f96320f916 100644 --- a/lib/layouttranslations +++ b/lib/layouttranslations @@ -436,11 +436,11 @@ Translation eu "List of Algorithms" "Algoritmoen zerrenda" "List of Charts" "Diagramen zerrenda" "List of Graphs[[mathematical]]" "Grafikoen zerrenda" - "List of Listings" "Zerrenden zerrenda" + "List of Listings" "Zerrendatuen zerrenda" "List of Schemes" "Eskemen zerrenda" "List of Tableaux" "Taulen zerrenda" - "Listing" "Zerrenda" - "Listings[[List of Listings]]" "Zerrendak" + "Listing" "Zerrendatua" + "Listings[[List of Listings]]" "Zerrendatuak" "Nomenclature[[output]]" "Nomenklatura" "Notation" "Notazioa" "Note" "Oharra" @@ -455,8 +455,8 @@ Translation eu "Summary" "Laburpena" "Tableau" "Taula" "Theorem" "Teorema" - "page[[nomencl]]" "page" - "see equation[[nomencl]]" "see equation" + "page[[nomencl]]" "orrialdea" + "see equation[[nomencl]]" "ikus ekuazioa" End Translation fi diff --git a/lib/layouttranslations.review b/lib/layouttranslations.review index 7a9d149492..39474b700b 100644 --- a/lib/layouttranslations.review +++ b/lib/layouttranslations.review @@ -21,7 +21,6 @@ Additionally to the top ones, these languages should be reviewed for the followi "Listing" "Listings" -eu hu id ro @@ -31,9 +30,9 @@ sr (30.11.2017, LyX 2.3.0 release ) Additionally to the top ones, these languages should be reviewed for the following strings "List of Listings" -ar bg ca da el eu es fi gl he hu ia id ko nb nl nn pl ro sl sr sv tr uk zh_CN zh_TW +ar bg ca da el es fi gl he hu ia id ko nb nl nn pl ro sl sr sv tr uk zh_CN zh_TW "Nomenclature[[output]]" -> The string that is output to PDF for the nomenclature list "see equation[[nomencl]]" "page[[nomencl]]" -ar bg ca da el eu fi gl he hu ia id ja ko nb nl nn pl ro sl sr sv tr zh_CN zh_TW +ar bg ca da el fi gl he hu ia id ja ko nb nl nn pl ro sl sr sv tr zh_CN zh_TW From a2e1021aba81371b29bf6a61d184383cffda7f9d Mon Sep 17 00:00:00 2001 From: Jean-Marc Lasgouttes Date: Mon, 12 Feb 2018 17:11:09 +0100 Subject: [PATCH 048/121] Use parMetrics to access the par_metrics_ map In cursorY, it is dangerous to access par_petrics_[0], since one does not know whether metrics have been computed for this paragraph (which may be off-screen). It is safer to use parMetrics(0), that will compute the paragraph metrics as needed. Fixes bug #8120. (cherry picked from commit a25b48f86cdde98bbd5f8ece06c6bf2f12ee84db) --- src/TextMetrics.cpp | 6 +++--- status.23x | 2 ++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/TextMetrics.cpp b/src/TextMetrics.cpp index e7bd6190e2..5d4b88d604 100644 --- a/src/TextMetrics.cpp +++ b/src/TextMetrics.cpp @@ -1502,14 +1502,14 @@ int TextMetrics::cursorX(CursorSlice const & sl, int TextMetrics::cursorY(CursorSlice const & sl, bool boundary) const { //lyxerr << "TextMetrics::cursorY: boundary: " << boundary << endl; - ParagraphMetrics const & pm = par_metrics_[sl.pit()]; + ParagraphMetrics const & pm = parMetrics(sl.pit()); if (pm.rows().empty()) return 0; int h = 0; - h -= par_metrics_[0].rows()[0].ascent(); + h -= parMetrics(0).rows()[0].ascent(); for (pit_type pit = 0; pit < sl.pit(); ++pit) { - h += par_metrics_[pit].height(); + h += parMetrics(pit).height(); } int pos = sl.pos(); if (pos && boundary) diff --git a/status.23x b/status.23x index b6c4427c49..726bcf4644 100644 --- a/status.23x +++ b/status.23x @@ -58,6 +58,8 @@ What's new * USER INTERFACE +- Fix crash with server-get-xy and tall inset (bug 8120). + - Improve Undo for operations that act on several buffers (bug 10823). - Improve rendering of square roots in math editor (bug 10814). From 257f978d626d272abc2212bdd4c3e64a65eacf63 Mon Sep 17 00:00:00 2001 From: Alexander Dunlap Date: Thu, 15 Feb 2018 11:28:34 -0800 Subject: [PATCH 049/121] save session when we save a buffer Implements enhancement #10712. (cherry picked from commit cca365f26c7d541cc13453fc42fc9b6de7736319) --- src/frontends/qt4/GuiView.cpp | 5 ++++- status.23x | 2 ++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/frontends/qt4/GuiView.cpp b/src/frontends/qt4/GuiView.cpp index 2aee2735d3..361439bee0 100644 --- a/src/frontends/qt4/GuiView.cpp +++ b/src/frontends/qt4/GuiView.cpp @@ -2228,8 +2228,10 @@ Buffer * GuiView::loadDocument(FileName const & filename, bool tolastfiles) setBuffer(newBuffer); newBuffer->errors("Parse"); - if (tolastfiles) + if (tolastfiles) { theSession().lastFiles().add(filename); + theSession().writeFile(); + } return newBuffer; } @@ -2768,6 +2770,7 @@ bool GuiView::saveBuffer(Buffer & b, FileName const & fn) bool const success = (fn.empty() ? b.save() : b.saveAs(fn)); if (success) { theSession().lastFiles().add(b.fileName()); + theSession().writeFile(); return true; } diff --git a/status.23x b/status.23x index 726bcf4644..65854cb0a7 100644 --- a/status.23x +++ b/status.23x @@ -67,6 +67,8 @@ What's new - Fix display of citation labels when pasting from a document with other citation type (bug 10829). +- Save the list of recent files when a file is open/saved so that it + is up to date after a crash (bug 10712). * INTERNALS From 31c7ce19fbc47ee1dd059005ff5dd295a5b8c21b Mon Sep 17 00:00:00 2001 From: Jean-Marc Lasgouttes Date: Wed, 21 Feb 2018 12:05:40 +0100 Subject: [PATCH 050/121] Add Alex Dunlap to our contributors (cherry picked from commit 4447fb349cbbc18f0aaebd9010fb320700d58c79) (cherry picked from commit 6d582e5e50e5ccc91bfb0565fef51ccff995481c) --- lib/CREDITS | 3 +++ lib/generate_contributions.py | 8 ++++++++ 2 files changed, 11 insertions(+) diff --git a/lib/CREDITS b/lib/CREDITS index 1575ab5183..9ef4043ebb 100644 --- a/lib/CREDITS +++ b/lib/CREDITS @@ -118,6 +118,9 @@ @bMin Ding @iE-mail: u5032331 () uds ! anu ! edu ! au Chinese (simplified) translations +@bAlexander Dunlap +@iE-mail: alexander.dunlap () gmail ! com + Improvement to recent files support @bAnders Ekberg @iE-mail: anek () chalmers ! se Improvements to the Swedish translation of the Windows Installer diff --git a/lib/generate_contributions.py b/lib/generate_contributions.py index 2bb442cd88..75710d3858 100755 --- a/lib/generate_contributions.py +++ b/lib/generate_contributions.py @@ -647,6 +647,14 @@ contributors = [ "27 April 2014", u"Chinese (simplified) translations"), + contributor(u"Alexander Dunlap", + "alexander.dunlap () gmail ! com", + "GPL", + "licensing statement", + "m=151914230920804", + "20 February 2018", + u"Improvement to recent files support"), + contributor(u"Anders Ekberg", "anek () chalmers ! se", "GPL", From 721cc085a26b2a362e90fd2578c5af6f7cfea1a0 Mon Sep 17 00:00:00 2001 From: Juergen Spitzmueller Date: Wed, 21 Feb 2018 16:37:07 +0100 Subject: [PATCH 051/121] Implement IsTocCaption for normal layouts. But use default "true" to maintain current behavior if not explicitly stated otherwise. Fixes: #11045 (cherry picked from commit 8a703573ea9718a06c94522e40671d46f0b83522) --- lib/layouts/IEEEtran.layout | 1 + lib/layouts/aguplus.inc | 1 + lib/layouts/agutex.layout | 1 + lib/layouts/amsdefs.inc | 1 + lib/layouts/beamer.layout | 1 + lib/layouts/cl2emult.layout | 1 + lib/layouts/egs.layout | 1 + lib/layouts/elsarticle.layout | 1 + lib/layouts/ijmpc.layout | 1 + lib/layouts/ijmpd.layout | 1 + lib/layouts/iopart.layout | 1 + lib/layouts/jasatex.layout | 1 + lib/layouts/kluwer.layout | 1 + lib/layouts/llncs.layout | 1 + lib/layouts/moderncv.layout | 1 + lib/layouts/powerdot.layout | 3 ++- lib/layouts/siamltex.layout | 1 + lib/layouts/simplecv.layout | 1 + lib/layouts/stdstruct.inc | 1 + lib/layouts/svcommon.inc | 1 + src/Layout.cpp | 2 +- src/Paragraph.cpp | 2 ++ status.23x | 3 +++ 23 files changed, 27 insertions(+), 2 deletions(-) diff --git a/lib/layouts/IEEEtran.layout b/lib/layouts/IEEEtran.layout index 52b867af10..21e117f499 100644 --- a/lib/layouts/IEEEtran.layout +++ b/lib/layouts/IEEEtran.layout @@ -364,6 +364,7 @@ Style Bibliography Size Larger EndFont TocLevel 1 + IsTocCaption 0 End diff --git a/lib/layouts/aguplus.inc b/lib/layouts/aguplus.inc index 57ebab331c..6c23fc97a0 100644 --- a/lib/layouts/aguplus.inc +++ b/lib/layouts/aguplus.inc @@ -177,6 +177,7 @@ Style Bibliography Size Huge EndFont TocLevel 1 + IsTocCaption 0 End diff --git a/lib/layouts/agutex.layout b/lib/layouts/agutex.layout index eacc73eac5..ee812d3e9e 100644 --- a/lib/layouts/agutex.layout +++ b/lib/layouts/agutex.layout @@ -228,5 +228,6 @@ Style Bibliography Size Larger EndFont TocLevel 1 + IsTocCaption 0 End diff --git a/lib/layouts/amsdefs.inc b/lib/layouts/amsdefs.inc index 3820739bc7..0744ecdd06 100644 --- a/lib/layouts/amsdefs.inc +++ b/lib/layouts/amsdefs.inc @@ -226,4 +226,5 @@ Style Bibliography Shape Smallcaps EndFont TocLevel 1 + IsTocCaption 0 End diff --git a/lib/layouts/beamer.layout b/lib/layouts/beamer.layout index ff8046ad54..ed15d26fe8 100644 --- a/lib/layouts/beamer.layout +++ b/lib/layouts/beamer.layout @@ -1126,6 +1126,7 @@ Style Bibliography Size Larger EndFont TocLevel 1 + IsTocCaption 0 End diff --git a/lib/layouts/cl2emult.layout b/lib/layouts/cl2emult.layout index 0dadd2af7d..69e5fbbac7 100644 --- a/lib/layouts/cl2emult.layout +++ b/lib/layouts/cl2emult.layout @@ -126,6 +126,7 @@ Style Bibliography Size Larger EndFont TocLevel 1 + IsTocCaption 0 End diff --git a/lib/layouts/egs.layout b/lib/layouts/egs.layout index ac53e616dd..b411c4384f 100644 --- a/lib/layouts/egs.layout +++ b/lib/layouts/egs.layout @@ -596,6 +596,7 @@ Style Bibliography Series Bold EndFont TocLevel 1 + IsTocCaption 0 End diff --git a/lib/layouts/elsarticle.layout b/lib/layouts/elsarticle.layout index 42e86fec1f..89a6a20cd0 100644 --- a/lib/layouts/elsarticle.layout +++ b/lib/layouts/elsarticle.layout @@ -326,5 +326,6 @@ Style Bibliography Size Larger EndFont TocLevel 1 + IsTocCaption 0 End diff --git a/lib/layouts/ijmpc.layout b/lib/layouts/ijmpc.layout index 38b43131e1..0f2b25c609 100644 --- a/lib/layouts/ijmpc.layout +++ b/lib/layouts/ijmpc.layout @@ -468,4 +468,5 @@ Style Bibliography Size Larger EndFont TocLevel 1 + IsTocCaption 0 End diff --git a/lib/layouts/ijmpd.layout b/lib/layouts/ijmpd.layout index c3835b828b..e35f852bcc 100644 --- a/lib/layouts/ijmpd.layout +++ b/lib/layouts/ijmpd.layout @@ -481,4 +481,5 @@ Style Bibliography Size Larger EndFont TocLevel 1 + IsTocCaption 0 End diff --git a/lib/layouts/iopart.layout b/lib/layouts/iopart.layout index 3ff99ef7b6..cea40c800f 100644 --- a/lib/layouts/iopart.layout +++ b/lib/layouts/iopart.layout @@ -288,6 +288,7 @@ Style "Bibliography (plain)" Size Larger EndFont TocLevel 1 + IsTocCaption 0 End diff --git a/lib/layouts/jasatex.layout b/lib/layouts/jasatex.layout index 4c1f46e80c..6dc7b2b6c4 100644 --- a/lib/layouts/jasatex.layout +++ b/lib/layouts/jasatex.layout @@ -289,5 +289,6 @@ Style Bibliography Size Larger EndFont TocLevel 1 + IsTocCaption 0 End diff --git a/lib/layouts/kluwer.layout b/lib/layouts/kluwer.layout index 9fed36753d..8e8ee3428b 100644 --- a/lib/layouts/kluwer.layout +++ b/lib/layouts/kluwer.layout @@ -367,4 +367,5 @@ Style References Series Bold EndFont TocLevel 1 + IsTocCaption 0 End diff --git a/lib/layouts/llncs.layout b/lib/layouts/llncs.layout index 0787825b15..6942f224a6 100644 --- a/lib/layouts/llncs.layout +++ b/lib/layouts/llncs.layout @@ -288,6 +288,7 @@ Style Bibliography Series Bold EndFont TocLevel 0 + IsTocCaption 0 End diff --git a/lib/layouts/moderncv.layout b/lib/layouts/moderncv.layout index afcfd1e115..03c2ed8582 100644 --- a/lib/layouts/moderncv.layout +++ b/lib/layouts/moderncv.layout @@ -520,6 +520,7 @@ Style Bibliography Family Sans EndFont TocLevel 1 + IsTocCaption 0 End Style Recipient diff --git a/lib/layouts/powerdot.layout b/lib/layouts/powerdot.layout index 4c3e37edf8..f59b48b2da 100644 --- a/lib/layouts/powerdot.layout +++ b/lib/layouts/powerdot.layout @@ -371,7 +371,8 @@ Style Bibliography LabelType Bibliography LabelString "" LabelBottomSep 0 - TocLevel 1 + TocLevel 1 + IsTocCaption 0 End ### diff --git a/lib/layouts/siamltex.layout b/lib/layouts/siamltex.layout index a0f4565bb3..2515d49125 100644 --- a/lib/layouts/siamltex.layout +++ b/lib/layouts/siamltex.layout @@ -349,6 +349,7 @@ Style Bibliography Shape Smallcaps EndFont TocLevel 1 + IsTocCaption 0 End NoStyle Chapter diff --git a/lib/layouts/simplecv.layout b/lib/layouts/simplecv.layout index 88a452f43a..dc3654e6fe 100644 --- a/lib/layouts/simplecv.layout +++ b/lib/layouts/simplecv.layout @@ -165,4 +165,5 @@ Style Bibliography Size Tiny EndFont TocLevel 1 + IsTocCaption 0 End diff --git a/lib/layouts/stdstruct.inc b/lib/layouts/stdstruct.inc index b323cf37ea..1c2c8c60ed 100644 --- a/lib/layouts/stdstruct.inc +++ b/lib/layouts/stdstruct.inc @@ -82,4 +82,5 @@ Style Bibliography span.bibitemlabel:after { content: "] "; } EndHTMLStyle TocLevel 1 + ISTocCaption 0 End diff --git a/lib/layouts/svcommon.inc b/lib/layouts/svcommon.inc index 3b1ea043ab..1adc110a49 100644 --- a/lib/layouts/svcommon.inc +++ b/lib/layouts/svcommon.inc @@ -594,6 +594,7 @@ Style Bibliography Series Bold EndFont TocLevel 0 + IsTocCaption 0 End Style Description diff --git a/src/Layout.cpp b/src/Layout.cpp index 0a783d0aad..005acb2258 100644 --- a/src/Layout.cpp +++ b/src/Layout.cpp @@ -120,7 +120,7 @@ enum LayoutTags { ///////////////////// Layout::Layout() - : add_to_toc_(false), is_toc_caption_(false) + : add_to_toc_(false), is_toc_caption_(true) { unknown_ = false; margintype = MARGIN_STATIC; diff --git a/src/Paragraph.cpp b/src/Paragraph.cpp index 135cd80fec..350418c564 100644 --- a/src/Paragraph.cpp +++ b/src/Paragraph.cpp @@ -3510,6 +3510,8 @@ void Paragraph::forOutliner(docstring & os, size_t const maxlen, size_t tmplen = shorten ? maxlen + 1 : maxlen; if (label && !labelString().empty()) os += labelString() + ' '; + if (!layout().isTocCaption()) + return; for (pos_type i = 0; i < size() && os.length() < tmplen; ++i) { if (isDeleted(i)) continue; diff --git a/status.23x b/status.23x index 65854cb0a7..e548e7dc12 100644 --- a/status.23x +++ b/status.23x @@ -70,6 +70,9 @@ What's new - Save the list of recent files when a file is open/saved so that it is up to date after a crash (bug 10712). +- Only show header for bibliography in outliner (bug 11045). + + * INTERNALS From 04e8526460fb26c933fc6e40ea37b96a8f17f1ee Mon Sep 17 00:00:00 2001 From: Richard Heck Date: Thu, 22 Feb 2018 15:24:28 -0500 Subject: [PATCH 052/121] Respect "literal" setting when entering citation via LyX server. This requires moving the bool that tracks this somewhere that it is visible from BufferView. It seemed to make sense to put it as a static member of InsetCitation. (cherry picked from commit f8e8877f839dcd0d133e6982d107b7d167c524c3) --- src/BufferView.cpp | 2 ++ src/frontends/qt4/GuiCitation.cpp | 12 +++++++----- src/frontends/qt4/GuiCitation.h | 3 --- src/insets/InsetCitation.cpp | 6 ++++++ src/insets/InsetCitation.h | 2 ++ status.23x | 3 +++ 6 files changed, 20 insertions(+), 8 deletions(-) diff --git a/src/BufferView.cpp b/src/BufferView.cpp index e23883cd06..7788f76d3d 100644 --- a/src/BufferView.cpp +++ b/src/BufferView.cpp @@ -2022,6 +2022,8 @@ void BufferView::dispatch(FuncRequest const & cmd, DispatchResult & dr) icp["key"] = from_utf8(arg); if (!opt1.empty()) icp["before"] = from_utf8(opt1); + icp["literal"] = + from_ascii(InsetCitation::last_literal ? "true" : "false"); string icstr = InsetCommand::params2string(icp); FuncRequest fr(LFUN_INSET_INSERT, icstr); lyx::dispatch(fr); diff --git a/src/frontends/qt4/GuiCitation.cpp b/src/frontends/qt4/GuiCitation.cpp index 66e7ba7aa4..ffc8254b6e 100644 --- a/src/frontends/qt4/GuiCitation.cpp +++ b/src/frontends/qt4/GuiCitation.cpp @@ -27,6 +27,7 @@ #include "TextClass.h" #include "FuncRequest.h" +#include "insets/InsetCitation.h" #include "insets/InsetCommand.h" #include "support/debug.h" @@ -92,7 +93,7 @@ static vector to_docstring_vector(QStringList const & qlist) GuiCitation::GuiCitation(GuiView & lv) : DialogView(lv, "citation", qt_("Citation")), - style_(QString()), literal_(false), params_(insetCode("citation")) + style_(QString()), params_(insetCode("citation")) { setupUi(this); @@ -237,7 +238,7 @@ void GuiCitation::on_restorePB_clicked() void GuiCitation::on_literalCB_clicked() { - literal_ = literalCB->isChecked(); + InsetCitation::last_literal = literalCB->isChecked(); changed(); } @@ -768,7 +769,7 @@ void GuiCitation::init() // if this is a new citation, we set the literal checkbox // to its last set value. if (cited_keys_.isEmpty()) - literalCB->setChecked(literal_); + literalCB->setChecked(InsetCitation::last_literal); else literalCB->setChecked(params_["literal"] == "true"); @@ -1061,7 +1062,7 @@ void GuiCitation::saveSession(QSettings & settings) const settings.setValue( sessionKey() + "/citestyle", style_); settings.setValue( - sessionKey() + "/literal", literal_); + sessionKey() + "/literal", InsetCitation::last_literal); } @@ -1073,7 +1074,8 @@ void GuiCitation::restoreSession() casesense_->setChecked(settings.value(sessionKey() + "/casesensitive").toBool()); instant_->setChecked(settings.value(sessionKey() + "/autofind", true).toBool()); style_ = settings.value(sessionKey() + "/citestyle").toString(); - literal_ = settings.value(sessionKey() + "/literal", false).toBool(); + InsetCitation::last_literal = + settings.value(sessionKey() + "/literal", false).toBool(); updateFilterHint(); } diff --git a/src/frontends/qt4/GuiCitation.h b/src/frontends/qt4/GuiCitation.h index 008d2d556d..4d85c0315a 100644 --- a/src/frontends/qt4/GuiCitation.h +++ b/src/frontends/qt4/GuiCitation.h @@ -183,9 +183,6 @@ private: /// last used citation style QString style_; - /// last set value for literal - /// this is used only for new citations - bool literal_; /// GuiSelectionManager * selectionManager; /// available keys. diff --git a/src/insets/InsetCitation.cpp b/src/insets/InsetCitation.cpp index 8571a28643..ca96d1d56b 100644 --- a/src/insets/InsetCitation.cpp +++ b/src/insets/InsetCitation.cpp @@ -62,6 +62,12 @@ InsetCitation::~InsetCitation() } +// May well be over-ridden when session settings are loaded +// in GuiCitation. Unfortunately, that will not happen until +// such a dialog is created. +bool InsetCitation::last_literal = true; + + ParamInfo const & InsetCitation::findInfo(string const & /* cmdName */) { // standard cite does only take one argument, but biblatex, jurabib diff --git a/src/insets/InsetCitation.h b/src/insets/InsetCitation.h index 3e5e3baa35..957488cd80 100644 --- a/src/insets/InsetCitation.h +++ b/src/insets/InsetCitation.h @@ -88,6 +88,8 @@ public: std::vector const & valid_styles) const; /// std::map getQualifiedLists(docstring const p) const; + /// + static bool last_literal; private: /// tries to make a pretty label and makes a basic one if not diff --git a/status.23x b/status.23x index e548e7dc12..d72f1bb6f1 100644 --- a/status.23x +++ b/status.23x @@ -33,6 +33,9 @@ What's new - Handle properly top/bottom of inset with mac-like cursor movement (bug 10701). +- Respect the last setting of the 'literal' checkbox when adding citations + via the LyX server (e.g., from JabRef). + - Allow unification of graphic groups inside marked block via context menu. From 797babd46299ac9e9d68a34d3621f83dbc5bc16e Mon Sep 17 00:00:00 2001 From: Richard Heck Date: Thu, 22 Feb 2018 15:40:05 -0500 Subject: [PATCH 053/121] Fix bug #10817. Respect 'literal' setting when calculating longest bibitem. (cherry picked from commit 224e56c935074729b39aa59994d3e42031f6db17) --- src/insets/InsetBibitem.cpp | 4 ++++ status.23x | 2 ++ 2 files changed, 6 insertions(+) diff --git a/src/insets/InsetBibitem.cpp b/src/insets/InsetBibitem.cpp index 08e8c76665..f9b244c460 100644 --- a/src/insets/InsetBibitem.cpp +++ b/src/insets/InsetBibitem.cpp @@ -249,6 +249,7 @@ docstring bibitemWidest(Buffer const & buffer, OutputParams const & runparams) ParagraphList::const_iterator it = buffer.paragraphs().begin(); ParagraphList::const_iterator end = buffer.paragraphs().end(); + bool is_literal = false; for (; it != end; ++it) { if (it->insetList().empty()) continue; @@ -274,11 +275,14 @@ docstring bibitemWidest(Buffer const & buffer, OutputParams const & runparams) if (wx > w) { w = wx; lbl = label; + is_literal = (bitem->getParam("literal") == "true"); } } if (!lbl.empty()) { InsetCommandParams p(BIBITEM_CODE); + if (is_literal) + p["literal"] = from_ascii("true"); return p.prepareCommand(runparams, lbl, ParamInfo::HANDLING_LATEXIFY); } diff --git a/status.23x b/status.23x index d72f1bb6f1..19a25ef6ae 100644 --- a/status.23x +++ b/status.23x @@ -55,6 +55,8 @@ What's new - Fix language settings annd line spacing in InPreamble-titles (bug 9332, 1049). +- Respect 'literal' setting when calculating longest bibitem (bug 10817). + * LYX2LYX From 2e67181036c1b7ff8829931d70a4a2e316bb791b Mon Sep 17 00:00:00 2001 From: Jean-Marc Lasgouttes Date: Thu, 22 Feb 2018 17:00:54 +0100 Subject: [PATCH 054/121] Improve documentation of inset-(begin|end)(|-select) Make it clear that it can go at the beginning/end of the document. (cherry picked from commit f4693ef8ab68c978c42bb987634eabcad92d592d) --- src/LyXAction.cpp | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/src/LyXAction.cpp b/src/LyXAction.cpp index 871612ed4a..d2e92b1c94 100644 --- a/src/LyXAction.cpp +++ b/src/LyXAction.cpp @@ -1950,8 +1950,10 @@ void LyXAction::init() /*! * \var lyx::FuncCode lyx::LFUN_INSET_BEGIN * \li Action: Move the cursor to the beginning of the current inset - if it is not already there, or at the beginning of the - enclosing inset otherwise + if it is not already there. If the cursor is already at + the beginning of the current inset, move it to the + beginning of the enclosing inset or the main work area, + respectively, if there is no enclosing inset. * \li Syntax: inset-begin * \li Origin: lasgouttes, 16 Mar 2009 * \endvar @@ -1961,8 +1963,10 @@ void LyXAction::init() /*! * \var lyx::FuncCode lyx::LFUN_INSET_BEGIN_SELECT * \li Action: Move the cursor to the beginning of the current inset - if it is not already there, or at the beginning of the - enclosing inset otherwise (adding the + if it is not already there. If the cursor is already at + the beginning of the current inset, move it to the + beginning of the enclosing inset or the main work area, + respectively, if there is no enclosing inset (adding the traversed text to the selection). * \li Syntax: inset-begin-select * \li Origin: lasgouttes, 16 Mar 2009 @@ -2021,9 +2025,11 @@ void LyXAction::init() /*! * \var lyx::FuncCode lyx::LFUN_INSET_END - * \li Action: Move the cursor to the end of the current inset - if it is not already there, or at the end of the - enclosing inset otherwise + * \li Action: Move the cursor to the end of the current inset if it + is not already there. If the cursor is already at the + end of the current inset, move it to the end of the + enclosing inset or the main work area, respectively, if + there is no enclosing inset. * \li Syntax: inset-end * \li Origin: lasgouttes, 16 Mar 2009 * \endvar @@ -2032,9 +2038,11 @@ void LyXAction::init() /*! * \var lyx::FuncCode lyx::LFUN_INSET_END_SELECT - * \li Action: Move the cursor to the end of the current inset - if it is not already there, or at the end of the - enclosing inset otherwise (adding the + * \li Action: Move the cursor to the end of the current inset if it + is not already there. If the cursor is already at the + end of the current inset, move it to the end of the + enclosing inset or the main work area, respectively, if + there is no enclosing inset (adding the traversed text to the selection). * \li Syntax: inset-end-select * \li Origin: lasgouttes, 16 Mar 2009 From 9df4806f7f01428ddae86756c54de36bd1554b1e Mon Sep 17 00:00:00 2001 From: Pavel Sanda Date: Sun, 25 Feb 2018 14:49:21 +0100 Subject: [PATCH 055/121] We don't want external change to automatically marked the buffer dirty. https://www.mail-archive.com/lyx-devel@lists.lyx.org/msg203995.html --- src/Buffer.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Buffer.cpp b/src/Buffer.cpp index 1ae48acc8a..a9f66a674c 100644 --- a/src/Buffer.cpp +++ b/src/Buffer.cpp @@ -5360,7 +5360,6 @@ void Buffer::Impl::fileExternallyModified(bool const exists) "checksum unchanged: " << filename); return; } - lyx_clean = bak_clean = false; // If the file has been deleted, only mark the file as dirty since it is // pointless to prompt for reloading. If later a file is moved into this // location, then the externally modified warning will appear then. From 98e9e53882da33a5a1fb4343e58be46f7921530a Mon Sep 17 00:00:00 2001 From: Juergen Spitzmueller Date: Sun, 25 Feb 2018 17:19:42 +0100 Subject: [PATCH 056/121] Take actual font height (ascent, descent) into account when drawing placeholder box for graphics Fixes: #11048 (cherry picked from commit 5ddd377a0ae6c8c18f566463988e3e3f596e57bb) --- src/insets/RenderGraphic.cpp | 5 +++++ status.23x | 3 +++ 2 files changed, 8 insertions(+) diff --git a/src/insets/RenderGraphic.cpp b/src/insets/RenderGraphic.cpp index 52e9803133..e01bcd3997 100644 --- a/src/insets/RenderGraphic.cpp +++ b/src/insets/RenderGraphic.cpp @@ -157,6 +157,7 @@ void RenderGraphic::metrics(MetricsInfo & mi, Dimension & dim) const dim.des = 0; int font_width = 0; + int font_height = 0; FontInfo msgFont(mi.base.font); msgFont.setFamily(SANS_FAMILY); @@ -166,6 +167,7 @@ void RenderGraphic::metrics(MetricsInfo & mi, Dimension & dim) const if (!justname.empty()) { msgFont.setSize(FONT_SIZE_FOOTNOTE); font_width = theFontMetrics(msgFont).width(justname); + font_height = theFontMetrics(msgFont).maxHeight(); } docstring const msg = statusMessage(params_, loader_.status()); @@ -173,9 +175,12 @@ void RenderGraphic::metrics(MetricsInfo & mi, Dimension & dim) const msgFont.setSize(FONT_SIZE_TINY); font_width = max(font_width, theFontMetrics(msgFont).width(msg)); + font_height += theFontMetrics(msgFont).maxAscent(); + dim.des = theFontMetrics(msgFont).maxDescent(); } dim.wid = max(50, font_width + 15); + dim.asc = max(50, font_height + 15); dim_ = dim; } diff --git a/status.23x b/status.23x index 19a25ef6ae..1a7312f84a 100644 --- a/status.23x +++ b/status.23x @@ -77,6 +77,9 @@ What's new - Only show header for bibliography in outliner (bug 11045). +- Take actual font height into account when drawing placeholder box + for graphics (bug 11048). + * INTERNALS From 749ff439df2f557694d0f8241a4f3a031f3a97c6 Mon Sep 17 00:00:00 2001 From: Juergen Spitzmueller Date: Mon, 26 Feb 2018 17:06:31 +0100 Subject: [PATCH 057/121] No manual intervention needed for polyglossia (bidi) and RTL numbers. See https://tex.stackexchange.com/a/256837/19291 (cherry picked from commit 00d4144352ffecfb229fcaaf104a2103002235bc) --- src/Font.cpp | 16 ++++++++++------ status.23x | 3 +++ 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/Font.cpp b/src/Font.cpp index 5ac0328ea5..e81e12449b 100644 --- a/src/Font.cpp +++ b/src/Font.cpp @@ -349,9 +349,11 @@ int Font::latexWriteStartChanges(odocstream & os, BufferParams const & bparams, // If the current language is Hebrew, Arabic, or Farsi // the numbers are written Left-to-Right. ArabTeX package - // reorders the number automatically but the packages used - // for Hebrew and Farsi (Arabi) do not. - if (!runparams.pass_thru && bits_.number() == FONT_ON + // and bidi (polyglossia) reorder the number automatically + // but the packages used for Hebrew and Farsi (Arabi) do not. + if (!runparams.use_polyglossia + && !runparams.pass_thru + && bits_.number() == FONT_ON && prev.fontInfo().number() != FONT_ON && (language()->lang() == "hebrew" || language()->lang() == "farsi" @@ -552,9 +554,11 @@ int Font::latexWriteEndChanges(otexstream & os, BufferParams const & bparams, // If the current language is Hebrew, Arabic, or Farsi // the numbers are written Left-to-Right. ArabTeX package - // reorders the number automatically but the packages used - // for Hebrew and Farsi (Arabi) do not. - if (!runparams.pass_thru && bits_.number() == FONT_ON + // and bidi (polyglossia) reorder the number automatically + // but the packages used for Hebrew and Farsi (Arabi) do not. + if (!runparams.use_polyglossia + && !runparams.pass_thru + && bits_.number() == FONT_ON && next.fontInfo().number() != FONT_ON && (language()->lang() == "hebrew" || language()->lang() == "farsi" diff --git a/status.23x b/status.23x index 1a7312f84a..e7e9ce5e9f 100644 --- a/status.23x +++ b/status.23x @@ -57,6 +57,9 @@ What's new - Respect 'literal' setting when calculating longest bibitem (bug 10817). +- Do not embrace numbers in \beginL ... \endL with polyglossia in Right- + to-Left languages, since bidi handles the numbers automatically. + * LYX2LYX From e97a82b7ff54eb2a3e6ac48ae0484cb3ddb9e031 Mon Sep 17 00:00:00 2001 From: Pavel Sanda Date: Fri, 2 Mar 2018 00:49:15 +0100 Subject: [PATCH 058/121] Filter in citation dialog is not respected when reloading databaze. --- src/frontends/qt4/GuiCitation.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/frontends/qt4/GuiCitation.cpp b/src/frontends/qt4/GuiCitation.cpp index ffc8254b6e..46cdd8d36f 100644 --- a/src/frontends/qt4/GuiCitation.cpp +++ b/src/frontends/qt4/GuiCitation.cpp @@ -233,6 +233,7 @@ void GuiCitation::on_restorePB_clicked() { init(); updateFilterHint(); + filterPressed(); } From 3d6b8c0abbfc61d803f82251c53d1ea81d033214 Mon Sep 17 00:00:00 2001 From: Pavel Sanda Date: Fri, 2 Mar 2018 20:48:08 +0100 Subject: [PATCH 059/121] Allow reload if buffer is externally modified. Follow-up of 2df82c4a44b7. --- src/frontends/qt4/GuiView.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/frontends/qt4/GuiView.cpp b/src/frontends/qt4/GuiView.cpp index 361439bee0..56a2e73d53 100644 --- a/src/frontends/qt4/GuiView.cpp +++ b/src/frontends/qt4/GuiView.cpp @@ -1879,7 +1879,8 @@ bool GuiView::getStatus(FuncRequest const & cmd, FuncStatus & flag) case LFUN_BUFFER_RELOAD: enable = doc_buffer && !doc_buffer->isUnnamed() - && doc_buffer->fileName().exists() && !doc_buffer->isClean(); + && doc_buffer->fileName().exists() + && (!doc_buffer->isClean() || doc_buffer->notifiesExternalModification()); break; case LFUN_BUFFER_CHILD_OPEN: From 84b59c90e778e1afabad17e06700aa044b9cf4a5 Mon Sep 17 00:00:00 2001 From: Juergen Spitzmueller Date: Sun, 4 Mar 2018 12:08:08 +0100 Subject: [PATCH 060/121] tex2lyx: import straight quotation marks as ERT This assures that they are output as straight quotations marks (e.g., babel shorthands). Fixes: #75 [sic!] (cherry picked from commit ccb9ae96709ea32cf983d6e5fb5d655b28a817e1) --- src/tex2lyx/text.cpp | 26 ++++++++++++++++++++++++++ status.23x | 1 + 2 files changed, 27 insertions(+) diff --git a/src/tex2lyx/text.cpp b/src/tex2lyx/text.cpp index 56931ddc55..36316edc72 100644 --- a/src/tex2lyx/text.cpp +++ b/src/tex2lyx/text.cpp @@ -2626,6 +2626,32 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, else if (t.cat() == catSpace || (t.cat() == catNewline && ! p.isParagraph())) check_space(p, os, context); + // babel shorthands (also used by polyglossia) + // Since these can have different meanings for different languages + // we import them as ERT (but they must be put in ERT to get output + // verbatim). + else if (t.asInput() == "\"") { + string s = "\""; + // These are known pairs. We put them together in + // one ERT inset. In other cases (such as "a), only + // the quotation mark is ERTed. + if (p.next_token().asInput() == "\"" + || p.next_token().asInput() == "|" + || p.next_token().asInput() == "-" + || p.next_token().asInput() == "~" + || p.next_token().asInput() == "=" + || p.next_token().asInput() == "/" + || p.next_token().asInput() == "~" + || p.next_token().asInput() == "'" + || p.next_token().asInput() == "`" + || p.next_token().asInput() == "<" + || p.next_token().asInput() == ">") { + s += p.next_token().asInput(); + p.get_token(); + } + output_ert_inset(os, s, context); + } + else if (t.character() == '[' && noweb_mode && p.next_token().character() == '[') { // These can contain underscores diff --git a/status.23x b/status.23x index e7e9ce5e9f..cff2cb4755 100644 --- a/status.23x +++ b/status.23x @@ -97,6 +97,7 @@ What's new * TEX2LYX +- Import straight quotations marks (e.g. babel shorthands) as ERT (bug 75). * ADVANCED FIND AND REPLACE From 3e6a1eecc5f64997a1f211b56257493051da0a90 Mon Sep 17 00:00:00 2001 From: Juergen Spitzmueller Date: Sun, 4 Mar 2018 16:45:37 +0100 Subject: [PATCH 061/121] tex2lyx: consider options passed via \PassOptionsToPackage (cherry picked from commit 476401a76f8bdb3dd2c2a482b2088f00dbe501d9) --- src/tex2lyx/Preamble.cpp | 17 +++++++++++++++++ src/tex2lyx/Preamble.h | 2 ++ status.23x | 2 ++ 3 files changed, 21 insertions(+) diff --git a/src/tex2lyx/Preamble.cpp b/src/tex2lyx/Preamble.cpp index fe722f48e2..1cff58db3c 100644 --- a/src/tex2lyx/Preamble.cpp +++ b/src/tex2lyx/Preamble.cpp @@ -418,6 +418,15 @@ void Preamble::add_package(string const & name, vector & options) if (used_packages.find(name) == used_packages.end()) used_packages[name] = split_options(h_options); + // Insert options passed via PassOptionsToPackage + for (auto const & p : extra_package_options_) { + if (p.first == name) { + vector eo = getVectorFromString(p.second); + for (auto const & eoi : eo) + options.push_back(eoi); + } + + } vector & v = used_packages[name]; v.insert(v.end(), options.begin(), options.end()); if (name == "jurabib") { @@ -1033,6 +1042,8 @@ void Preamble::handle_package(Parser &p, string const & name, options.erase(it); } } + if (!options.empty()) + h_biblio_options = join(options, ","); } else if (name == "jurabib") { @@ -1407,6 +1418,12 @@ void Preamble::parse(Parser & p, string const & forceclass, h_preamble << t.asInput(); } + else if (t.cs() == "PassOptionsToPackage") { + string const poptions = p.getArg('{', '}'); + string const package = p.verbatim_item(); + extra_package_options_.insert(make_pair(package, poptions)); + } + else if (t.cs() == "pagestyle") h_paperpagestyle = p.verbatim_item(); diff --git a/src/tex2lyx/Preamble.h b/src/tex2lyx/Preamble.h index 5dcc6718d7..288dd87bf6 100644 --- a/src/tex2lyx/Preamble.h +++ b/src/tex2lyx/Preamble.h @@ -241,6 +241,8 @@ private: AuthorList authors_; /// special table column types std::map special_columns_; + /// + std::map extra_package_options_; }; diff --git a/status.23x b/status.23x index cff2cb4755..d8efc4fd0c 100644 --- a/status.23x +++ b/status.23x @@ -99,6 +99,8 @@ What's new - Import straight quotations marks (e.g. babel shorthands) as ERT (bug 75). +- Consider options passed via \PassOptionsToPackage. + * ADVANCED FIND AND REPLACE From 50b78507b9b9157b1f73691781a306e954a75fc9 Mon Sep 17 00:00:00 2001 From: Juergen Spitzmueller Date: Sun, 4 Mar 2018 16:46:31 +0100 Subject: [PATCH 062/121] tex2lyx: support biblatex (qualified citation lists and multibib not yet supported) (cherry picked from commit f22213a04fe53dd128f11db9b228623b3fc3dda7) --- src/tex2lyx/Preamble.cpp | 53 ++++++++- src/tex2lyx/Preamble.h | 5 + src/tex2lyx/TODO.txt | 28 ----- src/tex2lyx/tex2lyx.cpp | 2 + src/tex2lyx/tex2lyx.h | 1 + src/tex2lyx/text.cpp | 233 +++++++++++++++++++++++++++++++++++++++ status.23x | 2 + 7 files changed, 294 insertions(+), 30 deletions(-) diff --git a/src/tex2lyx/Preamble.cpp b/src/tex2lyx/Preamble.cpp index 1cff58db3c..15cb037a45 100644 --- a/src/tex2lyx/Preamble.cpp +++ b/src/tex2lyx/Preamble.cpp @@ -1046,10 +1046,45 @@ void Preamble::handle_package(Parser &p, string const & name, h_biblio_options = join(options, ","); } + else if (name == "biblatex") { + h_biblio_style = "plainnat"; + h_cite_engine = "biblatex"; + h_cite_engine_type = "authoryear"; + string opt; + vector::iterator it = + find(options.begin(), options.end(), "natbib"); + if (it != options.end()) { + options.erase(it); + h_cite_engine = "biblatex-natbib"; + } else { + opt = process_keyval_opt(options, "natbib"); + if (opt == "true") + h_cite_engine = "biblatex-natbib"; + } + opt = process_keyval_opt(options, "style"); + if (!opt.empty()) { + h_biblatex_citestyle = opt; + h_biblatex_bibstyle = opt; + } else { + opt = process_keyval_opt(options, "citestyle"); + if (!opt.empty()) + h_biblatex_citestyle = opt; + opt = process_keyval_opt(options, "bibstyle"); + if (!opt.empty()) + h_biblatex_bibstyle = opt; + } + if (!options.empty()) { + h_biblio_options = join(options, ","); + options.clear(); + } + } + else if (name == "jurabib") { h_biblio_style = "jurabib"; h_cite_engine = "jurabib"; h_cite_engine_type = "authoryear"; + if (!options.empty()) + h_biblio_options = join(options, ","); } else if (name == "bibtopic") @@ -1270,8 +1305,14 @@ bool Preamble::writeLyXHeader(ostream & os, bool subdoc, string const & outfiled os << "\\cite_engine " << h_cite_engine << '\n' << "\\cite_engine_type " << h_cite_engine_type << '\n' << "\\biblio_style " << h_biblio_style << "\n" - << "\\use_bibtopic " << h_use_bibtopic << "\n" - << "\\use_indices " << h_use_indices << "\n" + << "\\use_bibtopic " << h_use_bibtopic << "\n"; + if (!h_biblio_options.empty()) + os << "\\biblio_options " << h_biblio_options << "\n"; + if (!h_biblatex_bibstyle.empty()) + os << "\\biblatex_bibstyle " << h_biblatex_bibstyle << "\n"; + if (!h_biblatex_citestyle.empty()) + os << "\\biblatex_citestyle " << h_biblatex_citestyle << "\n"; + os << "\\use_indices " << h_use_indices << "\n" << "\\paperorientation " << h_paperorientation << '\n' << "\\suppress_date " << h_suppress_date << '\n' << "\\justification " << h_justification << '\n' @@ -1566,6 +1607,14 @@ void Preamble::parse(Parser & p, string const & forceclass, p.skip_spaces(); } + else if (t.cs() == "addbibresource") + biblatex_bibliographies.push_back(removeExtension(p.getArg('{', '}'))); + + else if (t.cs() == "bibliography") { + vector bibs = getVectorFromString(p.getArg('{', '}')); + biblatex_bibliographies.insert(biblatex_bibliographies.end(), bibs.begin(), bibs.end()); + } + else if (t.cs() == "RS@ifundefined") { string const name = p.verbatim_item(); string const body1 = p.verbatim_item(); diff --git a/src/tex2lyx/Preamble.h b/src/tex2lyx/Preamble.h index 288dd87bf6..389bf5e48a 100644 --- a/src/tex2lyx/Preamble.h +++ b/src/tex2lyx/Preamble.h @@ -104,6 +104,8 @@ public: static const char * const polyglossia_languages[]; /// the same as polyglossia_languages with .lyx names static const char * const coded_polyglossia_languages[]; + /// + std::vector biblatex_bibliographies; private: /// @@ -132,6 +134,9 @@ private: std::ostringstream h_preamble; std::string h_backgroundcolor; std::string h_biblio_style; + std::string h_biblio_options; + std::string h_biblatex_bibstyle; + std::string h_biblatex_citestyle; std::string h_bibtex_command; std::string h_boxbgcolor; std::string h_cite_engine; diff --git a/src/tex2lyx/TODO.txt b/src/tex2lyx/TODO.txt index c448a45569..f5744e7f93 100644 --- a/src/tex2lyx/TODO.txt +++ b/src/tex2lyx/TODO.txt @@ -102,34 +102,6 @@ Format LaTeX feature LyX feature - cjkangle (angle brackets) \begin_inset Quotes k.. 526 Plural and capitalized refstyles InsetRef -528 Biblatex - \usepackage{biblatex} \cite_engine biblatex - ...[...natbib=true...]... \cite_engine biblatex-natbib - ...[...style=...]... \biblatex_bibstyle - \biblatex_citestyle - ...[...bibstyle=...]... \biblatex_bibstyle - ...[...citestyle=...]... \biblatex_citestyle - ...[......]... \biblio_options - \printbibliography[] \begin_inset CommandInset bibtex - biblatexopts "" - \addbibresource{file.bib} \begin_inset CommandInset bibtex - [multiple possible!] bibfiles "...,file,..." [NB: strip ext!] - \bibliography{file1,file2,...} \begin_inset CommandInset bibtex - bibfiles "...,file1,file2,..." - \begin_inset CommandInset citation - \Cite LatexCmd Cite - \cite* LatexCmd citeyear - \citeyear LatexCmd citebyear - \{T,t}extcite LatexCmd {C,c}itet - \{P,p}arencite LatexCmd {C,c}itep - \parencite* LatexCmd citeyearpar - \{S,s}martcite LatexCmd {F,f}ootcite - \{F,f}ootcite LatexCmd {F,f}ootcite - \{A,a}utocite LatexCmd {A,a}utocite - \citecite[*] LatexCmd citecite[*] - \fullcite LatexCmd fullcite - \footfullcite LatexCmd footfullcite - \supercite LatexCmd supercite 531 Biblatex "qualified citation lists" \cites(pre)(post)[pre1][post1]{key1}[pre2][post2]{key2}... \begin_inset CommandInset citation diff --git a/src/tex2lyx/tex2lyx.cpp b/src/tex2lyx/tex2lyx.cpp index fc6ea1efc8..cbdd7500b6 100644 --- a/src/tex2lyx/tex2lyx.cpp +++ b/src/tex2lyx/tex2lyx.cpp @@ -878,6 +878,8 @@ bool tex2lyx(idocstream & is, ostream & os, string const & encoding, context.font.language = preamble.defaultLanguage(); // parse the main text parse_text(p, ss, FLAG_END, true, context); + // check if we need a commented bibtex inset (biblatex) + check_comment_bib(ss, context); if (Context::empty) // Empty document body. LyX needs at least one paragraph. context.check_layout(ss); diff --git a/src/tex2lyx/tex2lyx.h b/src/tex2lyx/tex2lyx.h index 5c3595f447..ff8185653f 100644 --- a/src/tex2lyx/tex2lyx.h +++ b/src/tex2lyx/tex2lyx.h @@ -49,6 +49,7 @@ std::string translate_len(std::string const &); void parse_text(Parser & p, std::ostream & os, unsigned flags, bool outer, Context & context); +void check_comment_bib(std::ostream & os, Context & context); /*! * Parses a subdocument, usually useful in insets (whence the name). diff --git a/src/tex2lyx/text.cpp b/src/tex2lyx/text.cpp index 36316edc72..175c384064 100644 --- a/src/tex2lyx/text.cpp +++ b/src/tex2lyx/text.cpp @@ -184,6 +184,18 @@ char const * const known_jurabib_commands[] = { "cite", "citet", "citep", // "footciteauthor", "footciteyear", "footciteyearpar", "citefield", "citetitle", 0 }; +/*! + * biblatex commands. + * Known starred forms: \cite*, \citeauthor*, \Citeauthor*, \parencite*, \citetitle*. + */ +char const * const known_biblatex_commands[] = { "cite", "Cite", "textcite", "Textcite", +"parencite", "Parencite", "citeauthor", "Citeauthor", "citeyear", "smartcite", "Smartcite", + "footcite", "Footcite", "autocite", "Autocite", "citetitle", "fullcite", "footfullcite", +"supercite", 0 }; + +// Whether we need to insert a bibtex inset in a comment +bool need_commentbib = false; + /// LaTeX names for quotes char const * const known_quotes[] = { "dq", "guillemotleft", "flqq", "og", "guillemotright", "frqq", "fg", "glq", "glqq", "textquoteleft", "grq", "grqq", @@ -2476,6 +2488,11 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, string bibliographystyle = "default"; bool const use_natbib = isProvided("natbib"); bool const use_jurabib = isProvided("jurabib"); + bool const use_biblatex = isProvided("biblatex") + && preamble.citeEngine() != "biblatex-natbib"; + bool const use_biblatex_natbib = isProvided("biblatex-natbib") + || (isProvided("biblatex") && preamble.citeEngine() == "biblatex-natbib"); + need_commentbib = use_biblatex || use_biblatex_natbib; string last_env; // it is impossible to determine the correct encoding for non-CJK Japanese. @@ -3813,6 +3830,157 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, preamble.citeEngine("natbib"); } + else if (use_biblatex + && is_known(t.cs(), known_biblatex_commands) + && ((t.cs() == "cite" + || t.cs() == "citeauthor" + || t.cs() == "Citeauthor" + || t.cs() == "parencite" + || t.cs() == "citetitle") + || p.next_token().asInput() != "*")) { + context.check_layout(os); + string command = t.cs(); + if (p.next_token().asInput() == "*") { + command += '*'; + p.get_token(); + } + + // text before the citation + string before; + // text after the citation + string after; + get_cite_arguments(p, true, before, after); + + // These use natbib cmd names in LyX + // for inter-citeengine compativility + if (command == "citeyear") + command = "citebyear"; + else if (command == "cite*") + command = "citeyear"; + else if (command == "textcite") + command = "citet"; + else if (command == "Textcite") + command = "Citet"; + else if (command == "parencite") + command = "citep"; + else if (command == "Parencite") + command = "Citep"; + else if (command == "parencite*") + command = "citeyearpar"; + else if (command == "smartcite") + command = "footcite"; + else if (command == "Smartcite") + command = "Footcite"; + + if (before.empty() && after == "[]") + // avoid \cite[]{a} + after.erase(); + else if (before == "[]" && after == "[]") { + // avoid \cite[][]{a} + before.erase(); + after.erase(); + } + // remove the brackets around after and before + if (!after.empty()) { + after.erase(0, 1); + after.erase(after.length() - 1, 1); + after = convert_command_inset_arg(after); + } + if (!before.empty()) { + before.erase(0, 1); + before.erase(before.length() - 1, 1); + before = convert_command_inset_arg(before); + } + begin_command_inset(os, "citation", command); + os << "after " << '"' << after << '"' << "\n"; + os << "before " << '"' << before << '"' << "\n"; + os << "key \"" + << convert_command_inset_arg(p.verbatim_item()) + << "\"\n" + << "literal \"true\"\n"; + end_inset(os); + // Need to set the cite engine if biblatex is loaded by + // the document class directly + if (preamble.citeEngine() == "basic") + preamble.citeEngine("biblatex"); + } + + else if (use_biblatex_natbib + && (is_known(t.cs(), known_biblatex_commands) + || is_known(t.cs(), known_natbib_commands)) + && ((t.cs() == "cite" || t.cs() == "citet" || t.cs() == "Citet" + || t.cs() == "citep" || t.cs() == "Citep" || t.cs() == "citealt" + || t.cs() == "Citealt" || t.cs() == "citealp" || t.cs() == "Citealp" + || t.cs() == "citeauthor" || t.cs() == "Citeauthor" + || t.cs() == "parencite" || t.cs() == "citetitle") + || p.next_token().asInput() != "*")) { + context.check_layout(os); + string command = t.cs(); + if (p.next_token().asInput() == "*") { + command += '*'; + p.get_token(); + } + + // text before the citation + string before; + // text after the citation + string after; + get_cite_arguments(p, true, before, after); + + // These use natbib cmd names in LyX + // for inter-citeengine compativility + if (command == "citeyear") + command = "citebyear"; + else if (command == "cite*") + command = "citeyear"; + else if (command == "textcite") + command = "citet"; + else if (command == "Textcite") + command = "Citet"; + else if (command == "parencite") + command = "citep"; + else if (command == "Parencite") + command = "Citep"; + else if (command == "parencite*") + command = "citeyearpar"; + else if (command == "smartcite") + command = "footcite"; + else if (command == "Smartcite") + command = "Footcite"; + + if (before.empty() && after == "[]") + // avoid \cite[]{a} + after.erase(); + else if (before == "[]" && after == "[]") { + // avoid \cite[][]{a} + before.erase(); + after.erase(); + } + // remove the brackets around after and before + if (!after.empty()) { + after.erase(0, 1); + after.erase(after.length() - 1, 1); + after = convert_command_inset_arg(after); + } + if (!before.empty()) { + before.erase(0, 1); + before.erase(before.length() - 1, 1); + before = convert_command_inset_arg(before); + } + begin_command_inset(os, "citation", command); + os << "after " << '"' << after << '"' << "\n"; + os << "before " << '"' << before << '"' << "\n"; + os << "key \"" + << convert_command_inset_arg(p.verbatim_item()) + << "\"\n" + << "literal \"true\"\n"; + end_inset(os); + // Need to set the cite engine if biblatex is loaded by + // the document class directly + if (preamble.citeEngine() == "basic") + preamble.citeEngine("biblatex-natbib"); + } + else if (use_jurabib && is_known(t.cs(), known_jurabib_commands) && (t.cs() == "cite" || p.next_token().asInput() != "*")) { @@ -4457,6 +4625,46 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, end_inset(os); } + else if (t.cs() == "printbibliography") { + context.check_layout(os); + string BibOpts; + string bbloptions = p.hasOpt() ? p.getArg('[', ']') : string(); + vector opts = getVectorFromString(bbloptions); + vector::iterator it = + find(opts.begin(), opts.end(), "heading=bibintoc"); + if (it != opts.end()) { + opts.erase(it); + BibOpts = "bibtotoc"; + } + bbloptions = getStringFromVector(opts); + begin_command_inset(os, "bibtex", "bibtex"); + if (!btprint.empty()) { + os << "btprint " << '"' << "btPrintAll" << '"' << "\n"; + // clear the string because the next BibTeX inset can be without the + // \nocite{*} option + btprint.clear(); + } + string bibfiles; + for (auto const & bf : preamble.biblatex_bibliographies) { + if (!bibfiles.empty()) + bibfiles += ","; + bibfiles += normalize_filename(bf); + } + if (!bibfiles.empty()) + os << "bibfiles " << '"' << bibfiles << '"' << "\n"; + // Do we have addcontentsline? + if (contentslineContent == "\\refname") { + BibOpts = "bibtotoc"; + // clear string because next BibTeX inset can be without addcontentsline + contentslineContent.clear(); + } + os << "options " << '"' << BibOpts << '"' << "\n"; + if (!bbloptions.empty()) + os << "biblatexopts " << '"' << bbloptions << '"' << "\n"; + end_inset(os); + need_commentbib = false; + } + else if (t.cs() == "parbox") { // Test whether this is an outer box of a shaded box p.pushPosition(); @@ -5191,6 +5399,31 @@ string guessLanguage(Parser & p, string const & lang) return use->first; } + +void check_comment_bib(ostream & os, Context & context) +{ + if (!need_commentbib) + return; + // We have a bibliography database, but no bibliography with biblatex + // which is completely valid. Insert a bibtex inset in a note. + context.check_layout(os); + begin_inset(os, "Note Note\n"); + os << "status open\n"; + os << "\\begin_layout Plain Layout\n"; + begin_command_inset(os, "bibtex", "bibtex"); + string bibfiles; + for (auto const & bf : preamble.biblatex_bibliographies) { + if (!bibfiles.empty()) + bibfiles += ","; + bibfiles += normalize_filename(bf); + } + if (!bibfiles.empty()) + os << "bibfiles " << '"' << bibfiles << '"' << "\n"; + end_inset(os);// Bibtex + os << "\\end_layout\n"; + end_inset(os);// Note +} + // }]) diff --git a/status.23x b/status.23x index d8efc4fd0c..3698b0648a 100644 --- a/status.23x +++ b/status.23x @@ -101,6 +101,8 @@ What's new - Consider options passed via \PassOptionsToPackage. +- Add support for biblatex. + * ADVANCED FIND AND REPLACE From 8ab9b8e0b6743680faa7059ea1f3ff1d9822ba4a Mon Sep 17 00:00:00 2001 From: Juergen Spitzmueller Date: Sun, 4 Mar 2018 17:29:59 +0100 Subject: [PATCH 063/121] tex2lyx: refsection and bibbysection support (biblatex) (cherry picked from commit 1a3dbbf07ad837a685af93bf3d1d1a784e0d27ae) --- src/tex2lyx/Preamble.cpp | 12 ++++++++++++ src/tex2lyx/Preamble.h | 1 + src/tex2lyx/TODO.txt | 6 +----- src/tex2lyx/text.cpp | 29 +++++++++++++++++++++++++++++ 4 files changed, 43 insertions(+), 5 deletions(-) diff --git a/src/tex2lyx/Preamble.cpp b/src/tex2lyx/Preamble.cpp index 15cb037a45..f86576ce3c 100644 --- a/src/tex2lyx/Preamble.cpp +++ b/src/tex2lyx/Preamble.cpp @@ -1073,6 +1073,16 @@ void Preamble::handle_package(Parser &p, string const & name, if (!opt.empty()) h_biblatex_bibstyle = opt; } + opt = process_keyval_opt(options, "refsection"); + if (!opt.empty()) { + if (opt == "none" || opt == "part" + || opt == "chapter" || opt == "section" + || opt == "subsection") + h_multibib = opt; + else + cerr << "Ignoring unkown refesection value '" + << opt << "'."; + } if (!options.empty()) { h_biblio_options = join(options, ","); options.clear(); @@ -1312,6 +1322,8 @@ bool Preamble::writeLyXHeader(ostream & os, bool subdoc, string const & outfiled os << "\\biblatex_bibstyle " << h_biblatex_bibstyle << "\n"; if (!h_biblatex_citestyle.empty()) os << "\\biblatex_citestyle " << h_biblatex_citestyle << "\n"; + if (!h_multibib.empty()) + os << "\\multibib " << h_multibib << "\n"; os << "\\use_indices " << h_use_indices << "\n" << "\\paperorientation " << h_paperorientation << '\n' << "\\suppress_date " << h_suppress_date << '\n' diff --git a/src/tex2lyx/Preamble.h b/src/tex2lyx/Preamble.h index 389bf5e48a..074a85c613 100644 --- a/src/tex2lyx/Preamble.h +++ b/src/tex2lyx/Preamble.h @@ -133,6 +133,7 @@ private: std::ostringstream h_preamble; std::string h_backgroundcolor; + std::string h_multibib; std::string h_biblio_style; std::string h_biblio_options; std::string h_biblatex_bibstyle; diff --git a/src/tex2lyx/TODO.txt b/src/tex2lyx/TODO.txt index f5744e7f93..e5488b5936 100644 --- a/src/tex2lyx/TODO.txt +++ b/src/tex2lyx/TODO.txt @@ -114,13 +114,9 @@ Format LaTeX feature LyX feature Same for: \Cites, \textcites, \Textcites, \parencites, \Parencites, \smartcites, \Smartcites, \autocites, Autocites 533 Multibib support - \begin{btUnit}...\end{btUnit} \multibib {none|part|chapter|section|subsetion} + \begin{btUnit}...\end{btUnit} \multibib {none|part|chapter|section|subsection} (if a part, chapter, section etc. follows the \begin...) - \usepackage[refsection= \multibib - \bibbysection[] \begin_inset CommandInset bibtex - biblatexopts "" - btprint "bibbysection" 534 Chapterbib support \usepackage{chapterbib} \multibib child diff --git a/src/tex2lyx/text.cpp b/src/tex2lyx/text.cpp index 175c384064..0e1290062b 100644 --- a/src/tex2lyx/text.cpp +++ b/src/tex2lyx/text.cpp @@ -4665,6 +4665,35 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, need_commentbib = false; } + else if (t.cs() == "bibbysection") { + context.check_layout(os); + string BibOpts; + string bbloptions = p.hasOpt() ? p.getArg('[', ']') : string(); + vector opts = getVectorFromString(bbloptions); + vector::iterator it = + find(opts.begin(), opts.end(), "heading=bibintoc"); + if (it != opts.end()) { + opts.erase(it); + BibOpts = "bibtotoc"; + } + bbloptions = getStringFromVector(opts); + begin_command_inset(os, "bibtex", "bibtex"); + os << "btprint " << '"' << "bibbysection" << '"' << "\n"; + string bibfiles; + for (auto const & bf : preamble.biblatex_bibliographies) { + if (!bibfiles.empty()) + bibfiles += ","; + bibfiles += normalize_filename(bf); + } + if (!bibfiles.empty()) + os << "bibfiles " << '"' << bibfiles << '"' << "\n"; + os << "options " << '"' << BibOpts << '"' << "\n"; + if (!bbloptions.empty()) + os << "biblatexopts " << '"' << bbloptions << '"' << "\n"; + end_inset(os); + need_commentbib = false; + } + else if (t.cs() == "parbox") { // Test whether this is an outer box of a shaded box p.pushPosition(); From 8d02bff57eaa2597609d7bf5c1fd5be90645f855 Mon Sep 17 00:00:00 2001 From: Juergen Spitzmueller Date: Sun, 4 Mar 2018 20:12:27 +0100 Subject: [PATCH 064/121] tex2lyx: support qualified citation lists (biblatex) (cherry picked from commit 0915e814814ab26732b6dd13fc1740cfbf64b5b4) --- src/tex2lyx/Parser.cpp | 6 +- src/tex2lyx/Parser.h | 3 +- src/tex2lyx/TODO.txt | 11 --- src/tex2lyx/text.cpp | 176 ++++++++++++++++++++--------------------- 4 files changed, 92 insertions(+), 104 deletions(-) diff --git a/src/tex2lyx/Parser.cpp b/src/tex2lyx/Parser.cpp index ec63b77da8..35748b9769 100644 --- a/src/tex2lyx/Parser.cpp +++ b/src/tex2lyx/Parser.cpp @@ -533,11 +533,11 @@ string Parser::getArg(char left, char right, bool allow_escaping) } -string Parser::getFullOpt(bool keepws) +string Parser::getFullOpt(bool keepws, char left, char right) { - Arg arg = getFullArg('[', ']'); + Arg arg = getFullArg(left, right); if (arg.first) - return '[' + arg.second + ']'; + return left + arg.second + right; if (keepws) unskip_spaces(true); return string(); diff --git a/src/tex2lyx/Parser.h b/src/tex2lyx/Parser.h index cbdfcf7234..ca1edebfa2 100644 --- a/src/tex2lyx/Parser.h +++ b/src/tex2lyx/Parser.h @@ -240,7 +240,8 @@ public: * Like getOpt(), but distinguishes between a missing argument "" * and an empty argument "[]". */ - std::string getFullOpt(bool keepws = false); + std::string getFullOpt(bool keepws = false, + char left = '[', char right = ']'); /*! * \returns getArg('[', ']') including the brackets or the * empty string if there is no such argument. diff --git a/src/tex2lyx/TODO.txt b/src/tex2lyx/TODO.txt index e5488b5936..2ea4d8bd32 100644 --- a/src/tex2lyx/TODO.txt +++ b/src/tex2lyx/TODO.txt @@ -102,17 +102,6 @@ Format LaTeX feature LyX feature - cjkangle (angle brackets) \begin_inset Quotes k.. 526 Plural and capitalized refstyles InsetRef -531 Biblatex "qualified citation lists" - \cites(pre)(post)[pre1][post1]{key1}[pre2][post2]{key2}... - \begin_inset CommandInset citation - LatexCmd cite - after "post" - before "pre" - key "key1,key2..." - pretextlist "key1 pre1\tab key2 pre2..." - posttextlist "key1 post1\tab key2 post2..." - Same for: - \Cites, \textcites, \Textcites, \parencites, \Parencites, \smartcites, \Smartcites, \autocites, Autocites 533 Multibib support \begin{btUnit}...\end{btUnit} \multibib {none|part|chapter|section|subsection} (if a part, chapter, section etc. diff --git a/src/tex2lyx/text.cpp b/src/tex2lyx/text.cpp index 0e1290062b..b2dd0eb65c 100644 --- a/src/tex2lyx/text.cpp +++ b/src/tex2lyx/text.cpp @@ -191,7 +191,8 @@ char const * const known_jurabib_commands[] = { "cite", "citet", "citep", char const * const known_biblatex_commands[] = { "cite", "Cite", "textcite", "Textcite", "parencite", "Parencite", "citeauthor", "Citeauthor", "citeyear", "smartcite", "Smartcite", "footcite", "Footcite", "autocite", "Autocite", "citetitle", "fullcite", "footfullcite", -"supercite", 0 }; +"supercite", "cites", "Cites", "textcites", "Textcites", "parencites", "Parencites", +"smartcites", "Smartcites", "autocites", "Autocites", 0 }; // Whether we need to insert a bibtex inset in a comment bool need_commentbib = false; @@ -2144,17 +2145,17 @@ void parse_text_attributes(Parser & p, ostream & os, unsigned flags, bool outer, /// get the arguments of a natbib or jurabib citation command void get_cite_arguments(Parser & p, bool natbibOrder, - string & before, string & after) + string & before, string & after, bool const qualified = false) { // We need to distinguish "" and "[]", so we can't use p.getOpt(). // text before the citation before.clear(); // text after the citation - after = p.getFullOpt(); + after = qualified ? p.getFullOpt(false, '(', ')') : p.getFullOpt(); if (!after.empty()) { - before = p.getFullOpt(); + before = qualified ? p.getFullOpt(false, '(', ')') : p.getFullOpt(); if (natbibOrder && !before.empty()) swap(before, after); } @@ -3830,14 +3831,23 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, preamble.citeEngine("natbib"); } - else if (use_biblatex + else if ((use_biblatex && is_known(t.cs(), known_biblatex_commands) && ((t.cs() == "cite" || t.cs() == "citeauthor" || t.cs() == "Citeauthor" || t.cs() == "parencite" || t.cs() == "citetitle") - || p.next_token().asInput() != "*")) { + || p.next_token().asInput() != "*")) + || (use_biblatex_natbib + && (is_known(t.cs(), known_biblatex_commands) + || is_known(t.cs(), known_natbib_commands)) + && ((t.cs() == "cite" || t.cs() == "citet" || t.cs() == "Citet" + || t.cs() == "citep" || t.cs() == "Citep" || t.cs() == "citealt" + || t.cs() == "Citealt" || t.cs() == "citealp" || t.cs() == "Citealp" + || t.cs() == "citeauthor" || t.cs() == "Citeauthor" + || t.cs() == "parencite" || t.cs() == "citetitle") + || p.next_token().asInput() != "*"))){ context.check_layout(os); string command = t.cs(); if (p.next_token().asInput() == "*") { @@ -3845,11 +3855,15 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, p.get_token(); } + bool const qualified = suffixIs(command, "s"); + if (qualified) + command = rtrim(command, "s"); + // text before the citation string before; // text after the citation string after; - get_cite_arguments(p, true, before, after); + get_cite_arguments(p, true, before, after, qualified); // These use natbib cmd names in LyX // for inter-citeengine compativility @@ -3872,10 +3886,11 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, else if (command == "Smartcite") command = "Footcite"; - if (before.empty() && after == "[]") + string const emptyarg = qualified ? "()" : "[]"; + if (before.empty() && after == emptyarg) // avoid \cite[]{a} after.erase(); - else if (before == "[]" && after == "[]") { + else if (before == emptyarg && after == emptyarg) { // avoid \cite[][]{a} before.erase(); after.erase(); @@ -3891,94 +3906,77 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, before.erase(before.length() - 1, 1); before = convert_command_inset_arg(before); } + string keys, pretextlist, posttextlist; + if (qualified) { + map pres; + map posts; + vector lkeys; + // text before the citation + string lbefore; + // text after the citation + string lafter; + string lkey; + while (true) { + get_cite_arguments(p, true, lbefore, lafter); + // remove the brackets around after and before + if (!lafter.empty()) { + lafter.erase(0, 1); + lafter.erase(lafter.length() - 1, 1); + lafter = convert_command_inset_arg(lafter); + } + if (!lbefore.empty()) { + lbefore.erase(0, 1); + lbefore.erase(lbefore.length() - 1, 1); + lbefore = convert_command_inset_arg(lbefore); + } + if (lbefore.empty() && lafter == "[]") + // avoid \cite[]{a} + lafter.erase(); + else if (lbefore == "[]" && lafter == "[]") { + // avoid \cite[][]{a} + lbefore.erase(); + lafter.erase(); + } + lkey = p.getArg('{', '}'); + if (lkey.empty()) + break; + if (!lbefore.empty()) + pres.insert(make_pair(lkey, lbefore)); + if (!lafter.empty()) + posts.insert(make_pair(lkey, lafter)); + lkeys.push_back(lkey); + } + keys = convert_command_inset_arg(getStringFromVector(lkeys)); + for (auto const & ptl : pres) { + if (!pretextlist.empty()) + pretextlist += '\t'; + pretextlist += ptl.first + " " + ptl.second; + } + for (auto const & potl : posts) { + if (!posttextlist.empty()) + posttextlist += '\t'; + posttextlist += potl.first + " " + potl.second; + } + } else + keys = convert_command_inset_arg(p.verbatim_item()); begin_command_inset(os, "citation", command); os << "after " << '"' << after << '"' << "\n"; os << "before " << '"' << before << '"' << "\n"; os << "key \"" - << convert_command_inset_arg(p.verbatim_item()) - << "\"\n" - << "literal \"true\"\n"; + << keys + << "\"\n"; + if (!pretextlist.empty()) + os << "pretextlist " << '"' << pretextlist << '"' << "\n"; + if (!posttextlist.empty()) + os << "posttextlist " << '"' << posttextlist << '"' << "\n"; + os << "literal \"true\"\n"; end_inset(os); // Need to set the cite engine if biblatex is loaded by // the document class directly if (preamble.citeEngine() == "basic") - preamble.citeEngine("biblatex"); - } - - else if (use_biblatex_natbib - && (is_known(t.cs(), known_biblatex_commands) - || is_known(t.cs(), known_natbib_commands)) - && ((t.cs() == "cite" || t.cs() == "citet" || t.cs() == "Citet" - || t.cs() == "citep" || t.cs() == "Citep" || t.cs() == "citealt" - || t.cs() == "Citealt" || t.cs() == "citealp" || t.cs() == "Citealp" - || t.cs() == "citeauthor" || t.cs() == "Citeauthor" - || t.cs() == "parencite" || t.cs() == "citetitle") - || p.next_token().asInput() != "*")) { - context.check_layout(os); - string command = t.cs(); - if (p.next_token().asInput() == "*") { - command += '*'; - p.get_token(); - } - - // text before the citation - string before; - // text after the citation - string after; - get_cite_arguments(p, true, before, after); - - // These use natbib cmd names in LyX - // for inter-citeengine compativility - if (command == "citeyear") - command = "citebyear"; - else if (command == "cite*") - command = "citeyear"; - else if (command == "textcite") - command = "citet"; - else if (command == "Textcite") - command = "Citet"; - else if (command == "parencite") - command = "citep"; - else if (command == "Parencite") - command = "Citep"; - else if (command == "parencite*") - command = "citeyearpar"; - else if (command == "smartcite") - command = "footcite"; - else if (command == "Smartcite") - command = "Footcite"; - - if (before.empty() && after == "[]") - // avoid \cite[]{a} - after.erase(); - else if (before == "[]" && after == "[]") { - // avoid \cite[][]{a} - before.erase(); - after.erase(); - } - // remove the brackets around after and before - if (!after.empty()) { - after.erase(0, 1); - after.erase(after.length() - 1, 1); - after = convert_command_inset_arg(after); - } - if (!before.empty()) { - before.erase(0, 1); - before.erase(before.length() - 1, 1); - before = convert_command_inset_arg(before); - } - begin_command_inset(os, "citation", command); - os << "after " << '"' << after << '"' << "\n"; - os << "before " << '"' << before << '"' << "\n"; - os << "key \"" - << convert_command_inset_arg(p.verbatim_item()) - << "\"\n" - << "literal \"true\"\n"; - end_inset(os); - // Need to set the cite engine if biblatex is loaded by - // the document class directly - if (preamble.citeEngine() == "basic") - preamble.citeEngine("biblatex-natbib"); + use_biblatex_natbib ? + preamble.citeEngine("biblatex-natbib") + : preamble.citeEngine("biblatex"); } else if (use_jurabib && From 95d446eb4c0bd3b42874564ba7487d366bf6b1dc Mon Sep 17 00:00:00 2001 From: Juergen Spitzmueller Date: Mon, 5 Mar 2018 09:08:14 +0100 Subject: [PATCH 065/121] parse_text (tex2lyx): get rid of the monstrous if-then-else clause Rather than that, continue in the loop if a condition is met. This fixes tex2lyx for MINGW, which has a cluase-nesting threshold. Fixes: #9552 (cherry picked from commit b94bb37e5310b9007ed812c58460a5292820c534) --- src/tex2lyx/text.cpp | 639 +++++++++++++++++++++++++------------------ 1 file changed, 379 insertions(+), 260 deletions(-) diff --git a/src/tex2lyx/text.cpp b/src/tex2lyx/text.cpp index b2dd0eb65c..7c43a93aaf 100644 --- a/src/tex2lyx/text.cpp +++ b/src/tex2lyx/text.cpp @@ -2518,7 +2518,14 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, is_nonCJKJapanese = false; } + bool have_cycled = false; while (p.good()) { + // Leave hear only after at least one cycle + if (have_cycled && flags & FLAG_LEAVE) { + flags &= ~FLAG_LEAVE; + break; + } + Token const & t = p.get_token(); #ifdef FILEDEBUG debugToken(cerr, t, flags); @@ -2555,6 +2562,7 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, // // cat codes // + have_cycled = true; bool const starred = p.next_token().asInput() == "*"; string const starredname(starred ? (t.cs() + '*') : t.cs()); if (t.cat() == catMath) { @@ -2583,42 +2591,48 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, // output, but looks ugly in LyX. eat_whitespace(p, os, context, false); } + continue; } - else if (t.cat() == catSuper || t.cat() == catSub) + if (t.cat() == catSuper || t.cat() == catSub) { cerr << "catcode " << t << " illegal in text mode\n"; + continue; + } // Basic support for english quotes. This should be // extended to other quotes, but is not so easy (a // left english quote is the same as a right german // quote...) - else if (t.asInput() == "`" && p.next_token().asInput() == "`") { + if (t.asInput() == "`" && p.next_token().asInput() == "`") { context.check_layout(os); begin_inset(os, "Quotes "); os << "eld"; end_inset(os); p.get_token(); skip_braces(p); + continue; } - else if (t.asInput() == "'" && p.next_token().asInput() == "'") { + if (t.asInput() == "'" && p.next_token().asInput() == "'") { context.check_layout(os); begin_inset(os, "Quotes "); os << "erd"; end_inset(os); p.get_token(); skip_braces(p); + continue; } - else if (t.asInput() == ">" && p.next_token().asInput() == ">") { + if (t.asInput() == ">" && p.next_token().asInput() == ">") { context.check_layout(os); begin_inset(os, "Quotes "); os << "ald"; end_inset(os); p.get_token(); skip_braces(p); + continue; } - else if (t.asInput() == "<" + if (t.asInput() == "<" && p.next_token().asInput() == "<") { bool has_chunk = false; if (noweb_mode) { @@ -2639,16 +2653,19 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, p.get_token(); skip_braces(p); } + continue; } - else if (t.cat() == catSpace || (t.cat() == catNewline && ! p.isParagraph())) + if (t.cat() == catSpace || (t.cat() == catNewline && ! p.isParagraph())) { check_space(p, os, context); + continue; + } // babel shorthands (also used by polyglossia) // Since these can have different meanings for different languages // we import them as ERT (but they must be put in ERT to get output // verbatim). - else if (t.asInput() == "\"") { + if (t.asInput() == "\"") { string s = "\""; // These are known pairs. We put them together in // one ERT inset. In other cases (such as "a), only @@ -2668,9 +2685,10 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, p.get_token(); } output_ert_inset(os, s, context); + continue; } - else if (t.character() == '[' && noweb_mode && + if (t.character() == '[' && noweb_mode && p.next_token().character() == '[') { // These can contain underscores p.putback(); @@ -2681,14 +2699,16 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, cerr << "Warning: Inserting missing ']' in '" << s << "'." << endl; output_ert_inset(os, s, context); + continue; } - else if (t.cat() == catLetter) { + if (t.cat() == catLetter) { context.check_layout(os); os << t.cs(); + continue; } - else if (t.cat() == catOther || + if (t.cat() == catOther || t.cat() == catAlign || t.cat() == catParameter) { context.check_layout(os); @@ -2707,9 +2727,10 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, } else // This translates "&" to "\\&" which may be wrong... os << t.cs(); + continue; } - else if (p.isParagraph()) { + if (p.isParagraph()) { // In minted floating listings we will collect // everything into the caption, where multiple // paragraphs are forbidden. @@ -2721,9 +2742,10 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, } else os << ' '; eat_whitespace(p, os, context, true); + continue; } - else if (t.cat() == catActive) { + if (t.cat() == catActive) { context.check_layout(os); if (t.character() == '~') { if (context.layout->free_spacing) @@ -2734,9 +2756,10 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, } } else os << t.cs(); + continue; } - else if (t.cat() == catBegin) { + if (t.cat() == catBegin) { Token const next = p.next_token(); Token const end = p.next_next_token(); if (next.cat() == catEnd) { @@ -2860,24 +2883,28 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, output_ert_inset(os, "}", context); } } + continue; } - else if (t.cat() == catEnd) { + if (t.cat() == catEnd) { if (flags & FLAG_BRACE_LAST) { return; } cerr << "stray '}' in text\n"; output_ert_inset(os, "}", context); + continue; } - else if (t.cat() == catComment) + if (t.cat() == catComment) { parse_comment(p, os, t, context); + continue; + } // // control sequences // - else if (t.cs() == "(" || t.cs() == "[") { + if (t.cs() == "(" || t.cs() == "[") { bool const simple = t.cs() == "("; context.check_layout(os); begin_inset(os, "Formula"); @@ -2891,13 +2918,16 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, // output, but looks ugly in LyX. eat_whitespace(p, os, context, false); } + continue; } - else if (t.cs() == "begin") + if (t.cs() == "begin") { parse_environment(p, os, outer, last_env, context); + continue; + } - else if (t.cs() == "end") { + if (t.cs() == "end") { if (flags & FLAG_END) { // eat environment name string const name = p.getArg('{', '}'); @@ -2907,9 +2937,10 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, return; } p.error("found 'end' unexpectedly"); + continue; } - else if (t.cs() == "item") { + if (t.cs() == "item") { string s; bool const optarg = p.hasOpt(); if (optarg) { @@ -2968,9 +2999,10 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, eat_whitespace(p, os, context, false); } } + continue; } - else if (t.cs() == "bibitem") { + if (t.cs() == "bibitem") { context.set_item(); context.check_layout(os); eat_whitespace(p, os, context, false); @@ -2988,9 +3020,10 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, << "literal \"true\"\n"; end_inset(os); } + continue; } - else if (is_macro(p)) { + if (is_macro(p)) { // catch the case of \def\inputGnumericTable bool macro = true; if (t.cs() == "def") { @@ -3043,14 +3076,16 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, } if (macro) parse_macro(p, os, context); + continue; } - else if (t.cs() == "noindent") { + if (t.cs() == "noindent") { p.skip_spaces(); context.add_par_extra_stuff("\\noindent\n"); + continue; } - else if (t.cs() == "appendix") { + if (t.cs() == "appendix") { context.add_par_extra_stuff("\\start_of_appendix\n"); // We need to start a new paragraph. Otherwise the // appendix in 'bla\appendix\chapter{' would start @@ -3071,10 +3106,11 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, // empty paragraph, but that does not hurt, because // whitespace does not matter here. eat_whitespace(p, os, context, true); + continue; } // Must catch empty dates before findLayout is called below - else if (t.cs() == "date") { + if (t.cs() == "date") { eat_whitespace(p, os, context, false); p.pushPosition(); string const date = p.verbatim_item(); @@ -3103,11 +3139,12 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, "\\date{" + p.verbatim_item() + '}', context); } + continue; } // Starred section headings // Must attempt to parse "Section*" before "Section". - else if ((p.next_token().asInput() == "*") && + if ((p.next_token().asInput() == "*") && context.new_layout_allowed && (newlayout = findLayout(context.textclass, t.cs() + '*', true))) { // write the layout @@ -3119,10 +3156,11 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, set const & req = newlayout->requires(); for (set::const_iterator it = req.begin(); it != req.end(); ++it) preamble.registerAutomaticallyLoadedPackage(*it); + continue; } // Section headings and the like - else if (context.new_layout_allowed && + if (context.new_layout_allowed && (newlayout = findLayout(context.textclass, t.cs(), true))) { // write the layout output_command_layout(os, p, outer, context, newlayout); @@ -3132,9 +3170,10 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, set const & req = newlayout->requires(); for (set::const_iterator it = req.begin(); it != req.end(); ++it) preamble.registerAutomaticallyLoadedPackage(*it); + continue; } - else if (t.cs() == "subfloat") { + if (t.cs() == "subfloat") { // the syntax is \subfloat[list entry][sub caption]{content} // if it is a table of figure depends on the surrounding float // FIXME: second optional argument is not parsed @@ -3195,9 +3234,10 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, } else output_ert_inset(os, t.asInput() + "{" + p.verbatim_item() + '}', context); } + continue; } - else if (t.cs() == "includegraphics") { + if (t.cs() == "includegraphics") { bool const clip = p.next_token().asInput() == "*"; if (clip) p.get_token(); @@ -3357,9 +3397,10 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, // Check whether some option was given twice. end_inset(os); preamble.registerAutomaticallyLoadedPackage("graphicx"); + continue; } - else if (t.cs() == "footnote" || + if (t.cs() == "footnote" || (t.cs() == "thanks" && context.layout->intitle)) { p.skip_spaces(); context.check_layout(os); @@ -3367,24 +3408,27 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, os << "status collapsed\n\n"; parse_text_in_inset(p, os, FLAG_ITEM, false, context); end_inset(os); + continue; } - else if (t.cs() == "marginpar") { + if (t.cs() == "marginpar") { p.skip_spaces(); context.check_layout(os); begin_inset(os, "Marginal\n"); os << "status collapsed\n\n"; parse_text_in_inset(p, os, FLAG_ITEM, false, context); end_inset(os); + continue; } - else if (t.cs() == "lstinline" || t.cs() == "mintinline") { + if (t.cs() == "lstinline" || t.cs() == "mintinline") { bool const use_minted = t.cs() == "mintinline"; p.skip_spaces(); parse_listings(p, os, context, true, use_minted); + continue; } - else if (t.cs() == "ensuremath") { + if (t.cs() == "ensuremath") { p.skip_spaces(); context.check_layout(os); string const s = p.verbatim_item(); @@ -3394,6 +3438,7 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, else output_ert_inset(os, "\\ensuremath{" + s + "}", context); + continue; } else if (t.cs() == "makeindex" || t.cs() == "maketitle") { @@ -3402,9 +3447,10 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, skip_spaces_braces(p); } else output_ert_inset(os, t.asInput(), context); + continue; } - else if (t.cs() == "tableofcontents" + if (t.cs() == "tableofcontents" || t.cs() == "lstlistoflistings" || t.cs() == "listoflistings") { string name = t.cs(); @@ -3420,9 +3466,10 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, else preamble.registerAutomaticallyLoadedPackage("listings"); } + continue; } - else if (t.cs() == "listoffigures" || t.cs() == "listoftables") { + if (t.cs() == "listoffigures" || t.cs() == "listoftables") { context.check_layout(os); if (t.cs() == "listoffigures") begin_inset(os, "FloatList figure\n"); @@ -3430,9 +3477,10 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, begin_inset(os, "FloatList table\n"); end_inset(os); skip_spaces_braces(p); + continue; } - else if (t.cs() == "listof") { + if (t.cs() == "listof") { p.skip_spaces(true); string const name = p.get_token().cs(); if (context.textclass.floats().typeExist(name)) { @@ -3443,24 +3491,31 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, p.get_token(); // swallow second arg } else output_ert_inset(os, "\\listof{" + name + "}", context); + continue; } - else if ((where = is_known(t.cs(), known_text_font_families))) + if ((where = is_known(t.cs(), known_text_font_families))) { parse_text_attributes(p, os, FLAG_ITEM, outer, context, "\\family", context.font.family, known_coded_font_families[where - known_text_font_families]); + continue; + } - else if ((where = is_known(t.cs(), known_text_font_series))) + if ((where = is_known(t.cs(), known_text_font_series))) { parse_text_attributes(p, os, FLAG_ITEM, outer, context, "\\series", context.font.series, known_coded_font_series[where - known_text_font_series]); + continue; + } - else if ((where = is_known(t.cs(), known_text_font_shapes))) + if ((where = is_known(t.cs(), known_text_font_shapes))) { parse_text_attributes(p, os, FLAG_ITEM, outer, context, "\\shape", context.font.shape, known_coded_font_shapes[where - known_text_font_shapes]); + continue; + } - else if (t.cs() == "textnormal" || t.cs() == "normalfont") { + if (t.cs() == "textnormal" || t.cs() == "normalfont") { context.check_layout(os); TeXFont oldFont = context.font; context.font.init(); @@ -3474,9 +3529,10 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, context.font = oldFont; } else eat_whitespace(p, os, context, false); + continue; } - else if (t.cs() == "textcolor") { + if (t.cs() == "textcolor") { // scheme is \textcolor{color name}{text} string const color = p.verbatim_item(); // we support the predefined colors of the color and the xcolor package @@ -3502,9 +3558,10 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, } else // for custom defined colors output_ert_inset(os, t.asInput() + "{" + color + "}", context); + continue; } - else if (t.cs() == "underbar" || t.cs() == "uline") { + if (t.cs() == "underbar" || t.cs() == "uline") { // \underbar is not 100% correct (LyX outputs \uline // of ulem.sty). The difference is that \ulem allows // line breaks, and \underbar does not. @@ -3517,18 +3574,20 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, context.check_layout(os); os << "\n\\bar default\n"; preamble.registerAutomaticallyLoadedPackage("ulem"); + continue; } - else if (t.cs() == "sout") { + if (t.cs() == "sout") { context.check_layout(os); os << "\n\\strikeout on\n"; parse_text_snippet(p, os, FLAG_ITEM, outer, context); context.check_layout(os); os << "\n\\strikeout default\n"; preamble.registerAutomaticallyLoadedPackage("ulem"); + continue; } - else if (t.cs() == "uuline" || t.cs() == "uwave" + if (t.cs() == "uuline" || t.cs() == "uwave" || t.cs() == "emph" || t.cs() == "noun" || t.cs() == "xout") { context.check_layout(os); @@ -3538,9 +3597,10 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, os << "\n\\" << t.cs() << " default\n"; if (t.cs() == "uuline" || t.cs() == "uwave" || t.cs() == "xout") preamble.registerAutomaticallyLoadedPackage("ulem"); + continue; } - else if (t.cs() == "lyxadded" || t.cs() == "lyxdeleted") { + if (t.cs() == "lyxadded" || t.cs() == "lyxdeleted") { context.check_layout(os); string name = p.getArg('{', '}'); string localtime = p.getArg('{', '}'); @@ -3580,9 +3640,10 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, preamble.registerAutomaticallyLoadedPackage("xcolor"); } } + continue; } - else if (t.cs() == "textipa") { + if (t.cs() == "textipa") { context.check_layout(os); begin_inset(os, "IPA\n"); bool merging_hyphens_allowed = context.merging_hyphens_allowed; @@ -3592,25 +3653,27 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, end_inset(os); preamble.registerAutomaticallyLoadedPackage("tipa"); preamble.registerAutomaticallyLoadedPackage("tipx"); + continue; } - else if (t.cs() == "texttoptiebar" || t.cs() == "textbottomtiebar") { + if (t.cs() == "texttoptiebar" || t.cs() == "textbottomtiebar") { context.check_layout(os); begin_inset(os, "IPADeco " + t.cs().substr(4) + "\n"); os << "status open\n"; parse_text_in_inset(p, os, FLAG_ITEM, outer, context); end_inset(os); p.skip_spaces(); + continue; } - else if (t.cs() == "textvertline") { + if (t.cs() == "textvertline") { // FIXME: This is not correct, \textvertline is higher than | os << "|"; skip_braces(p); continue; } - else if (t.cs() == "tone" ) { + if (t.cs() == "tone" ) { context.check_layout(os); // register the tone package preamble.registerAutomaticallyLoadedPackage("tone"); @@ -3638,9 +3701,10 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, } else // we did not find a non-ert version output_ert_inset(os, command, context); + continue; } - else if (t.cs() == "phantom" || t.cs() == "hphantom" || + if (t.cs() == "phantom" || t.cs() == "hphantom" || t.cs() == "vphantom") { context.check_layout(os); if (t.cs() == "phantom") @@ -3653,9 +3717,10 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, parse_text_in_inset(p, os, FLAG_ITEM, outer, context, "Phantom"); end_inset(os); + continue; } - else if (t.cs() == "href") { + if (t.cs() == "href") { context.check_layout(os); string target = convert_command_inset_arg(p.verbatim_item()); string name = convert_command_inset_arg(p.verbatim_item()); @@ -3678,9 +3743,10 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, os << "literal \"true\"\n"; end_inset(os); skip_spaces_braces(p); + continue; } - else if (t.cs() == "lyxline") { + if (t.cs() == "lyxline") { // swallow size argument (it is not used anyway) p.getArg('{', '}'); if (!context.atParagraphStart()) { @@ -3705,9 +3771,10 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, "width \"100line%\"\n" "height \"1pt\"\n"; end_inset(os); + continue; } - else if (t.cs() == "rule") { + if (t.cs() == "rule") { string const offset = (p.hasOpt() ? p.getArg('[', ']') : string()); string const width = p.getArg('{', '}'); string const thickness = p.getArg('{', '}'); @@ -3718,14 +3785,15 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, os << "width \"" << translate_len(width) << "\"\n" "height \"" << translate_len(thickness) << "\"\n"; end_inset(os); + continue; } // handle refstyle first to catch \eqref which can also occur // without refstyle. Only recognize these commands if // refstyle.sty was found in the preamble (otherwise \eqref // and user defined ref commands could be misdetected). - else if ((where = is_known(t.cs(), known_refstyle_commands)) && - preamble.refstyle()) { + if ((where = is_known(t.cs(), known_refstyle_commands)) + && preamble.refstyle()) { context.check_layout(os); begin_command_inset(os, "ref", "formatted"); os << "reference \""; @@ -3738,11 +3806,12 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, os << "noprefix \"false\"\n"; end_inset(os); preamble.registerAutomaticallyLoadedPackage("refstyle"); + continue; } // if refstyle is used, we must not convert \prettyref to a // formatted reference, since that would result in a refstyle command. - else if ((where = is_known(t.cs(), known_ref_commands)) && + if ((where = is_known(t.cs(), known_ref_commands)) && (t.cs() != "prettyref" || !preamble.refstyle())) { string const opt = p.getOpt(); if (opt.empty()) { @@ -3765,9 +3834,10 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, output_ert_inset(os, t.asInput() + '[' + opt + "]{" + p.verbatim_item() + '}', context); } + continue; } - else if (use_natbib && + if (use_natbib && is_known(t.cs(), known_natbib_commands) && ((t.cs() != "citefullauthor" && t.cs() != "citeyear" && @@ -3829,9 +3899,10 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, // the document class directly if (preamble.citeEngine() == "basic") preamble.citeEngine("natbib"); + continue; } - else if ((use_biblatex + if ((use_biblatex && is_known(t.cs(), known_biblatex_commands) && ((t.cs() == "cite" || t.cs() == "citeauthor" @@ -3977,9 +4048,10 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, use_biblatex_natbib ? preamble.citeEngine("biblatex-natbib") : preamble.citeEngine("biblatex"); + continue; } - else if (use_jurabib && + if (use_jurabib && is_known(t.cs(), known_jurabib_commands) && (t.cs() == "cite" || p.next_token().asInput() != "*")) { context.check_layout(os); @@ -4032,9 +4104,10 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, // the document class directly if (preamble.citeEngine() == "basic") preamble.citeEngine("jurabib"); + continue; } - else if (t.cs() == "cite" + if (t.cs() == "cite" || t.cs() == "nocite") { context.check_layout(os); string after = convert_command_inset_arg(p.getArg('[', ']')); @@ -4049,10 +4122,11 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, end_inset(os); } else if (t.cs() == "nocite") btprint = key; + continue; } - else if (t.cs() == "index" || - (t.cs() == "sindex" && preamble.use_indices() == "true")) { + if (t.cs() == "index" || + (t.cs() == "sindex" && preamble.use_indices() == "true")) { context.check_layout(os); string const arg = (t.cs() == "sindex" && p.hasOpt()) ? p.getArg('[', ']') : ""; @@ -4063,9 +4137,10 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, end_inset(os); if (kind != "idx") preamble.registerAutomaticallyLoadedPackage("splitidx"); + continue; } - else if (t.cs() == "nomenclature") { + if (t.cs() == "nomenclature") { context.check_layout(os); begin_command_inset(os, "nomenclature", "nomenclature"); string prefix = convert_command_inset_arg(p.getArg('[', ']')); @@ -4079,18 +4154,20 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, << "literal \"true\"\n"; end_inset(os); preamble.registerAutomaticallyLoadedPackage("nomencl"); + continue; } - else if (t.cs() == "label") { + if (t.cs() == "label") { context.check_layout(os); begin_command_inset(os, "label", "label"); os << "name \"" << convert_command_inset_arg(p.verbatim_item()) << "\"\n"; end_inset(os); + continue; } - else if (t.cs() == "lyxmintcaption") { + if (t.cs() == "lyxmintcaption") { string const pos = p.getArg('[', ']'); if (pos == "t") { string const caption = @@ -4102,9 +4179,10 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, // so simply skip it. parse_text_snippet(p, FLAG_ITEM, false, context); } + continue; } - else if (t.cs() == "printindex" || t.cs() == "printsubindex") { + if (t.cs() == "printindex" || t.cs() == "printsubindex") { context.check_layout(os); string commandname = t.cs(); bool star = false; @@ -4127,9 +4205,10 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, preamble.registerAutomaticallyLoadedPackage("makeidx"); if (preamble.use_indices() == "true") preamble.registerAutomaticallyLoadedPackage("splitidx"); + continue; } - else if (t.cs() == "printnomenclature") { + if (t.cs() == "printnomenclature") { string width = ""; string width_type = ""; context.check_layout(os); @@ -4154,9 +4233,10 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, end_inset(os); skip_spaces_braces(p); preamble.registerAutomaticallyLoadedPackage("nomencl"); + continue; } - else if ((t.cs() == "textsuperscript" || t.cs() == "textsubscript")) { + if ((t.cs() == "textsuperscript" || t.cs() == "textsubscript")) { context.check_layout(os); begin_inset(os, "script "); os << t.cs().substr(4) << '\n'; @@ -4165,9 +4245,10 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, end_inset(os); if (t.cs() == "textsubscript") preamble.registerAutomaticallyLoadedPackage("subscript"); + continue; } - else if ((where = is_known(t.cs(), known_quotes))) { + if ((where = is_known(t.cs(), known_quotes))) { context.check_layout(os); begin_inset(os, "Quotes "); os << known_coded_quotes[where - known_quotes]; @@ -4177,18 +4258,20 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, // {} pair. eat_whitespace(p, os, context, false); skip_braces(p); + continue; } - else if ((where = is_known(t.cs(), known_sizes)) && + if ((where = is_known(t.cs(), known_sizes)) && context.new_layout_allowed) { context.check_layout(os); TeXFont const oldFont = context.font; context.font.size = known_coded_sizes[where - known_sizes]; output_font_change(os, oldFont, context.font); eat_whitespace(p, os, context, false); + continue; } - else if ((where = is_known(t.cs(), known_font_families)) && + if ((where = is_known(t.cs(), known_font_families)) && context.new_layout_allowed) { context.check_layout(os); TeXFont const oldFont = context.font; @@ -4196,9 +4279,10 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, known_coded_font_families[where - known_font_families]; output_font_change(os, oldFont, context.font); eat_whitespace(p, os, context, false); + continue; } - else if ((where = is_known(t.cs(), known_font_series)) && + if ((where = is_known(t.cs(), known_font_series)) && context.new_layout_allowed) { context.check_layout(os); TeXFont const oldFont = context.font; @@ -4206,9 +4290,10 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, known_coded_font_series[where - known_font_series]; output_font_change(os, oldFont, context.font); eat_whitespace(p, os, context, false); + continue; } - else if ((where = is_known(t.cs(), known_font_shapes)) && + if ((where = is_known(t.cs(), known_font_shapes)) && context.new_layout_allowed) { context.check_layout(os); TeXFont const oldFont = context.font; @@ -4216,8 +4301,9 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, known_coded_font_shapes[where - known_font_shapes]; output_font_change(os, oldFont, context.font); eat_whitespace(p, os, context, false); + continue; } - else if ((where = is_known(t.cs(), known_old_font_families)) && + if ((where = is_known(t.cs(), known_old_font_families)) && context.new_layout_allowed) { context.check_layout(os); TeXFont const oldFont = context.font; @@ -4227,9 +4313,10 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, known_coded_font_families[where - known_old_font_families]; output_font_change(os, oldFont, context.font); eat_whitespace(p, os, context, false); + continue; } - else if ((where = is_known(t.cs(), known_old_font_series)) && + if ((where = is_known(t.cs(), known_old_font_series)) && context.new_layout_allowed) { context.check_layout(os); TeXFont const oldFont = context.font; @@ -4239,9 +4326,10 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, known_coded_font_series[where - known_old_font_series]; output_font_change(os, oldFont, context.font); eat_whitespace(p, os, context, false); + continue; } - else if ((where = is_known(t.cs(), known_old_font_shapes)) && + if ((where = is_known(t.cs(), known_old_font_shapes)) && context.new_layout_allowed) { context.check_layout(os); TeXFont const oldFont = context.font; @@ -4251,24 +4339,27 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, known_coded_font_shapes[where - known_old_font_shapes]; output_font_change(os, oldFont, context.font); eat_whitespace(p, os, context, false); + continue; } - else if (t.cs() == "selectlanguage") { + if (t.cs() == "selectlanguage") { context.check_layout(os); // save the language for the case that a // \foreignlanguage is used context.font.language = babel2lyx(p.verbatim_item()); os << "\n\\lang " << context.font.language << "\n"; + continue; } - else if (t.cs() == "foreignlanguage") { + if (t.cs() == "foreignlanguage") { string const lang = babel2lyx(p.verbatim_item()); parse_text_attributes(p, os, FLAG_ITEM, outer, context, "\\lang", context.font.language, lang); + continue; } - else if (prefixIs(t.cs(), "text") && preamble.usePolyglossia() + if (prefixIs(t.cs(), "text") && preamble.usePolyglossia() && is_known(t.cs().substr(4), preamble.polyglossia_languages)) { // scheme is \textLANGUAGE{text} where LANGUAGE is in polyglossia_languages[] string lang; @@ -4296,18 +4387,20 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, context, "\\lang", context.font.language, lang); } + continue; } - else if (t.cs() == "inputencoding") { + if (t.cs() == "inputencoding") { // nothing to write here string const enc = subst(p.verbatim_item(), "\n", " "); p.setEncoding(enc, Encoding::inputenc); + continue; } - else if (is_known(t.cs(), known_special_chars) || - (t.cs() == "protect" && - p.next_token().cat() == catEscape && - is_known(p.next_token().cs(), known_special_protect_chars))) { + if (is_known(t.cs(), known_special_chars) || + (t.cs() == "protect" && + p.next_token().cat() == catEscape && + is_known(p.next_token().cs(), known_special_protect_chars))) { // LyX sometimes puts a \protect in front, so we have to ignore it where = is_known( t.cs() == "protect" ? p.get_token().cs() : t.cs(), @@ -4315,9 +4408,10 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, context.check_layout(os); os << known_coded_special_chars[where - known_special_chars]; skip_spaces_braces(p); + continue; } - else if ((t.cs() == "nobreakdash" && p.next_token().asInput() == "-") || + if ((t.cs() == "nobreakdash" && p.next_token().asInput() == "-") || (t.cs() == "protect" && p.next_token().asInput() == "\\nobreakdash" && p.next_next_token().asInput() == "-") || (t.cs() == "@" && p.next_token().asInput() == ".")) { @@ -4330,15 +4424,17 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, else os << "\\SpecialChar endofsentence\n"; p.get_token(); + continue; } - else if (t.cs() == "textquotedbl") { + if (t.cs() == "textquotedbl") { context.check_layout(os); os << "\""; skip_braces(p); + continue; } - else if (t.cs() == "_" || t.cs() == "&" || t.cs() == "#" + if (t.cs() == "_" || t.cs() == "&" || t.cs() == "#" || t.cs() == "$" || t.cs() == "{" || t.cs() == "}" || t.cs() == "%" || t.cs() == "-") { context.check_layout(os); @@ -4346,9 +4442,10 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, os << "\\SpecialChar softhyphen\n"; else os << t.cs(); + continue; } - else if (t.cs() == "char") { + if (t.cs() == "char") { context.check_layout(os); if (p.next_token().character() == '`') { p.get_token(); @@ -4362,9 +4459,10 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, } else { output_ert_inset(os, "\\char", context); } + continue; } - else if (t.cs() == "verb") { + if (t.cs() == "verb") { context.check_layout(os); // set catcodes to verbatim early, just in case. p.setCatcodes(VERBATIM_CATCODES); @@ -4375,15 +4473,18 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, + arg.second + delim, context); else cerr << "invalid \\verb command. Skipping" << endl; + continue; } // Problem: \= creates a tabstop inside the tabbing environment // and else an accent. In the latter case we really would want // \={o} instead of \= o. - else if (t.cs() == "=" && (flags & FLAG_TABBING)) + if (t.cs() == "=" && (flags & FLAG_TABBING)) { output_ert_inset(os, t.asInput(), context); + continue; + } - else if (t.cs() == "\\") { + if (t.cs() == "\\") { context.check_layout(os); if (p.hasOpt()) output_ert_inset(os, "\\\\" + p.getOpt(), context); @@ -4398,19 +4499,21 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, begin_inset(os, "Newline newline"); end_inset(os); } + continue; } - else if (t.cs() == "newline" || - (t.cs() == "linebreak" && !p.hasOpt())) { + if (t.cs() == "newline" || + (t.cs() == "linebreak" && !p.hasOpt())) { context.check_layout(os); begin_inset(os, "Newline "); os << t.cs(); end_inset(os); skip_spaces_braces(p); + continue; } - else if (t.cs() == "input" || t.cs() == "include" - || t.cs() == "verbatiminput") { + if (t.cs() == "input" || t.cs() == "include" + || t.cs() == "verbatiminput") { string name = t.cs(); if (t.cs() == "verbatiminput" && p.next_token().asInput() == "*") @@ -4527,9 +4630,10 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, preamble.registerAutomaticallyLoadedPackage("verbatim"); } end_inset(os); + continue; } - else if (t.cs() == "bibliographystyle") { + if (t.cs() == "bibliographystyle") { // store new bibliographystyle bibliographystyle = p.verbatim_item(); // If any other command than \bibliography, \addcontentsline @@ -4569,16 +4673,18 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, "\\bibliographystyle{" + bibliographystyle + '}', context); } + continue; } - else if (t.cs() == "phantomsection") { + if (t.cs() == "phantomsection") { // we only support this if it occurs between // \bibliographystyle and \bibliography if (bibliographystyle.empty()) output_ert_inset(os, "\\phantomsection", context); + continue; } - else if (t.cs() == "addcontentsline") { + if (t.cs() == "addcontentsline") { context.check_layout(os); // get the 3 arguments of \addcontentsline string const one = p.getArg('{', '}'); @@ -4590,6 +4696,7 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, "\\addcontentsline{" + one + "}{" + two + "}{"+ three + '}', context); } + continue; } else if (t.cs() == "bibliography") { @@ -4621,9 +4728,10 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, } os << "options " << '"' << BibOpts << '"' << "\n"; end_inset(os); + continue; } - else if (t.cs() == "printbibliography") { + if (t.cs() == "printbibliography") { context.check_layout(os); string BibOpts; string bbloptions = p.hasOpt() ? p.getArg('[', ']') : string(); @@ -4661,9 +4769,10 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, os << "biblatexopts " << '"' << bbloptions << '"' << "\n"; end_inset(os); need_commentbib = false; + continue; } - else if (t.cs() == "bibbysection") { + if (t.cs() == "bibbysection") { context.check_layout(os); string BibOpts; string bbloptions = p.hasOpt() ? p.getArg('[', ']') : string(); @@ -4690,9 +4799,10 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, os << "biblatexopts " << '"' << bbloptions << '"' << "\n"; end_inset(os); need_commentbib = false; + continue; } - else if (t.cs() == "parbox") { + if (t.cs() == "parbox") { // Test whether this is an outer box of a shaded box p.pushPosition(); // swallow arguments @@ -4720,14 +4830,17 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, } else parse_box(p, os, 0, FLAG_ITEM, outer, context, "", "", t.cs(), "", ""); + continue; } - else if (t.cs() == "fbox" || t.cs() == "mbox" || - t.cs() == "ovalbox" || t.cs() == "Ovalbox" || - t.cs() == "shadowbox" || t.cs() == "doublebox") + if (t.cs() == "fbox" || t.cs() == "mbox" || + t.cs() == "ovalbox" || t.cs() == "Ovalbox" || + t.cs() == "shadowbox" || t.cs() == "doublebox") { parse_outer_box(p, os, FLAG_ITEM, outer, context, t.cs(), ""); + continue; + } - else if (t.cs() == "fcolorbox" || t.cs() == "colorbox") { + if (t.cs() == "fcolorbox" || t.cs() == "colorbox") { string backgroundcolor; preamble.registerAutomaticallyLoadedPackage("xcolor"); if (t.cs() == "fcolorbox") { @@ -4738,15 +4851,16 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, backgroundcolor = p.getArg('{', '}'); parse_box(p, os, 0, 0, outer, context, "", "", "", "", backgroundcolor); } + continue; } // FIXME: due to the compiler limit of "if" nestings // the code for the alignment was put here // put them in their own if if this is fixed - else if (t.cs() == "fboxrule" || t.cs() == "fboxsep" - || t.cs() == "shadowsize" - || t.cs() == "raggedleft" || t.cs() == "centering" - || t.cs() == "raggedright") { + if (t.cs() == "fboxrule" || t.cs() == "fboxsep" + || t.cs() == "shadowsize" + || t.cs() == "raggedleft" || t.cs() == "centering" + || t.cs() == "raggedright") { if (t.cs() == "fboxrule") fboxrule = ""; if (t.cs() == "fboxsep") @@ -4769,11 +4883,12 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, } else { output_ert_inset(os, t.asInput(), context); } + continue; } //\framebox() is part of the picture environment and different from \framebox{} //\framebox{} will be parsed by parse_outer_box - else if (t.cs() == "framebox") { + if (t.cs() == "framebox") { if (p.next_token().character() == '(') { //the syntax is: \framebox(x,y)[position]{content} string arg = t.asInput(); @@ -4790,11 +4905,12 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, parse_outer_box(p, os, FLAG_ITEM, outer, context, t.cs(), special); } + continue; } //\makebox() is part of the picture environment and different from \makebox{} //\makebox{} will be parsed by parse_box - else if (t.cs() == "makebox") { + if (t.cs() == "makebox") { if (p.next_token().character() == '(') { //the syntax is: \makebox(x,y)[position]{content} string arg = t.asInput(); @@ -4808,20 +4924,22 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, //the syntax is: \makebox[width][position]{content} parse_box(p, os, 0, FLAG_ITEM, outer, context, "", "", t.cs(), "", ""); + continue; } - else if (t.cs() == "smallskip" || - t.cs() == "medskip" || - t.cs() == "bigskip" || - t.cs() == "vfill") { + if (t.cs() == "smallskip" || + t.cs() == "medskip" || + t.cs() == "bigskip" || + t.cs() == "vfill") { context.check_layout(os); begin_inset(os, "VSpace "); os << t.cs(); end_inset(os); skip_spaces_braces(p); + continue; } - else if ((where = is_known(t.cs(), known_spaces))) { + if ((where = is_known(t.cs(), known_spaces))) { context.check_layout(os); begin_inset(os, "space "); os << '\\' << known_coded_spaces[where - known_spaces] @@ -4838,20 +4956,22 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, // remove the braces after "\\,", too. if (t.cs() != " ") skip_braces(p); + continue; } - else if (t.cs() == "newpage" || - (t.cs() == "pagebreak" && !p.hasOpt()) || - t.cs() == "clearpage" || - t.cs() == "cleardoublepage") { + if (t.cs() == "newpage" || + (t.cs() == "pagebreak" && !p.hasOpt()) || + t.cs() == "clearpage" || + t.cs() == "cleardoublepage") { context.check_layout(os); begin_inset(os, "Newpage "); os << t.cs(); end_inset(os); skip_spaces_braces(p); + continue; } - else if (t.cs() == "DeclareRobustCommand" || + if (t.cs() == "DeclareRobustCommand" || t.cs() == "DeclareRobustCommandx" || t.cs() == "newcommand" || t.cs() == "newcommandx" || @@ -4889,9 +5009,10 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, os << "\n" << ert; end_inset(os); } + continue; } - else if (t.cs() == "let" && p.next_token().asInput() != "*") { + if (t.cs() == "let" && p.next_token().asInput() != "*") { // let could be handled by parse_command(), // but we need to call add_known_command() here. string ert = t.asInput(); @@ -4920,9 +5041,10 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, if (it != known_commands.end()) known_commands[t.asInput()] = it->second; output_ert_inset(os, ert, context); + continue; } - else if (t.cs() == "hspace" || t.cs() == "vspace") { + if (t.cs() == "hspace" || t.cs() == "vspace") { if (starred) p.get_token(); string name = t.asInput(); @@ -5056,10 +5178,11 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, } else output_ert_inset(os, name + '{' + length + '}', context); } + continue; } // The single '=' is meant here. - else if ((newinsetlayout = findInsetLayout(context.textclass, starredname, true))) { + if ((newinsetlayout = findInsetLayout(context.textclass, starredname, true))) { if (starred) p.get_token(); p.skip_spaces(); @@ -5099,9 +5222,10 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, // we collect everything into the caption. if (minted_float.empty()) end_inset(os); + continue; } - else if (t.cs() == "includepdf") { + if (t.cs() == "includepdf") { p.skip_spaces(); string const arg = p.getArg('[', ']'); map opts; @@ -5171,9 +5295,10 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, end_inset(os); context.check_layout(os); registerExternalTemplatePackages("PDFPages"); + continue; } - else if (t.cs() == "loadgame") { + if (t.cs() == "loadgame") { p.skip_spaces(); string name = normalize_filename(p.verbatim_item()); string const path = getMasterFilePath(true); @@ -5206,149 +5331,143 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, if (p.get_token().asInput() == "showboard") p.get_token(); registerExternalTemplatePackages("ChessDiagram"); + continue; } - else { - // try to see whether the string is in unicodesymbols - // Only use text mode commands, since we are in text mode here, - // and math commands may be invalid (bug 6797) - string name = t.asInput(); - // handle the dingbats, cyrillic and greek - if (name == "\\ding" || name == "\\textcyr" || - (name == "\\textgreek" && !preamble.usePolyglossia())) - name = name + '{' + p.getArg('{', '}') + '}'; - // handle the ifsym characters - else if (name == "\\textifsymbol") { - string const optif = p.getFullOpt(); - string const argif = p.getArg('{', '}'); - name = name + optif + '{' + argif + '}'; - } - // handle the \ascii characters - // the case of \ascii within braces, as LyX outputs it, is already - // handled for t.cat() == catBegin - else if (name == "\\ascii") { - // the code is "\asci\xxx" - name = "{" + name + p.get_token().asInput() + "}"; + // try to see whether the string is in unicodesymbols + // Only use text mode commands, since we are in text mode here, + // and math commands may be invalid (bug 6797) + string name = t.asInput(); + // handle the dingbats, cyrillic and greek + if (name == "\\ding" || name == "\\textcyr" || + (name == "\\textgreek" && !preamble.usePolyglossia())) + name = name + '{' + p.getArg('{', '}') + '}'; + // handle the ifsym characters + else if (name == "\\textifsymbol") { + string const optif = p.getFullOpt(); + string const argif = p.getArg('{', '}'); + name = name + optif + '{' + argif + '}'; + } + // handle the \ascii characters + // the case of \ascii within braces, as LyX outputs it, is already + // handled for t.cat() == catBegin + else if (name == "\\ascii") { + // the code is "\asci\xxx" + name = "{" + name + p.get_token().asInput() + "}"; + skip_braces(p); + } + // handle some TIPA special characters + else if (preamble.isPackageUsed("tipa")) { + if (name == "\\s") { + // fromLaTeXCommand() does not yet + // recognize tipa short cuts + name = "\\textsyllabic"; + } else if (name == "\\=" && + p.next_token().asInput() == "*") { + // fromLaTeXCommand() does not yet + // recognize tipa short cuts + p.get_token(); + name = "\\textsubbar"; + } else if (name == "\\textdoublevertline") { + // FIXME: This is not correct, + // \textvertline is higher than \textbardbl + name = "\\textbardbl"; skip_braces(p); - } - // handle some TIPA special characters - else if (preamble.isPackageUsed("tipa")) { - if (name == "\\s") { - // fromLaTeXCommand() does not yet - // recognize tipa short cuts - name = "\\textsyllabic"; - } else if (name == "\\=" && - p.next_token().asInput() == "*") { - // fromLaTeXCommand() does not yet - // recognize tipa short cuts - p.get_token(); - name = "\\textsubbar"; - } else if (name == "\\textdoublevertline") { - // FIXME: This is not correct, - // \textvertline is higher than \textbardbl - name = "\\textbardbl"; + } else if (name == "\\!" ) { + if (p.next_token().asInput() == "b") { + p.get_token(); // eat 'b' + name = "\\texthtb"; + skip_braces(p); + } else if (p.next_token().asInput() == "d") { + p.get_token(); + name = "\\texthtd"; + skip_braces(p); + } else if (p.next_token().asInput() == "g") { + p.get_token(); + name = "\\texthtg"; + skip_braces(p); + } else if (p.next_token().asInput() == "G") { + p.get_token(); + name = "\\texthtscg"; + skip_braces(p); + } else if (p.next_token().asInput() == "j") { + p.get_token(); + name = "\\texthtbardotlessj"; + skip_braces(p); + } else if (p.next_token().asInput() == "o") { + p.get_token(); + name = "\\textbullseye"; skip_braces(p); - } else if (name == "\\!" ) { - if (p.next_token().asInput() == "b") { - p.get_token(); // eat 'b' - name = "\\texthtb"; - skip_braces(p); - } else if (p.next_token().asInput() == "d") { - p.get_token(); - name = "\\texthtd"; - skip_braces(p); - } else if (p.next_token().asInput() == "g") { - p.get_token(); - name = "\\texthtg"; - skip_braces(p); - } else if (p.next_token().asInput() == "G") { - p.get_token(); - name = "\\texthtscg"; - skip_braces(p); - } else if (p.next_token().asInput() == "j") { - p.get_token(); - name = "\\texthtbardotlessj"; - skip_braces(p); - } else if (p.next_token().asInput() == "o") { - p.get_token(); - name = "\\textbullseye"; - skip_braces(p); - } - } else if (name == "\\*" ) { - if (p.next_token().asInput() == "k") { - p.get_token(); - name = "\\textturnk"; - skip_braces(p); - } else if (p.next_token().asInput() == "r") { - p.get_token(); // eat 'b' - name = "\\textturnr"; - skip_braces(p); - } else if (p.next_token().asInput() == "t") { - p.get_token(); - name = "\\textturnt"; - skip_braces(p); - } else if (p.next_token().asInput() == "w") { - p.get_token(); - name = "\\textturnw"; - skip_braces(p); - } } - } - if ((name.size() == 2 && - contains("\"'.=^`bcdHkrtuv~", name[1]) && - p.next_token().asInput() != "*") || - is_known(name.substr(1), known_tipa_marks)) { - // name is a command that corresponds to a - // combining character in unicodesymbols. - // Append the argument, fromLaTeXCommand() - // will either convert it to a single - // character or a combining sequence. - name += '{' + p.verbatim_item() + '}'; - } - // now get the character from unicodesymbols - bool termination; - docstring rem; - set req; - docstring s = normalize_c(encodings.fromLaTeXCommand(from_utf8(name), - Encodings::TEXT_CMD, termination, rem, &req)); - if (!s.empty()) { - context.check_layout(os); - os << to_utf8(s); - if (!rem.empty()) - output_ert_inset(os, to_utf8(rem), context); - if (termination) - skip_spaces_braces(p); - for (set::const_iterator it = req.begin(); it != req.end(); ++it) - preamble.registerAutomaticallyLoadedPackage(*it); - } - //cerr << "#: " << t << " mode: " << mode << endl; - // heuristic: read up to next non-nested space - /* - string s = t.asInput(); - string z = p.verbatim_item(); - while (p.good() && z != " " && !z.empty()) { - //cerr << "read: " << z << endl; - s += z; - z = p.verbatim_item(); - } - cerr << "found ERT: " << s << endl; - output_ert_inset(os, s + ' ', context); - */ - else { - if (t.asInput() == name && - p.next_token().asInput() == "*") { - // Starred commands like \vspace*{} - p.get_token(); // Eat '*' - name += '*'; + } else if (name == "\\*" ) { + if (p.next_token().asInput() == "k") { + p.get_token(); + name = "\\textturnk"; + skip_braces(p); + } else if (p.next_token().asInput() == "r") { + p.get_token(); // eat 'b' + name = "\\textturnr"; + skip_braces(p); + } else if (p.next_token().asInput() == "t") { + p.get_token(); + name = "\\textturnt"; + skip_braces(p); + } else if (p.next_token().asInput() == "w") { + p.get_token(); + name = "\\textturnw"; + skip_braces(p); } - if (!parse_command(name, p, os, outer, context)) - output_ert_inset(os, name, context); } } - - if (flags & FLAG_LEAVE) { - flags &= ~FLAG_LEAVE; - break; + if ((name.size() == 2 && + contains("\"'.=^`bcdHkrtuv~", name[1]) && + p.next_token().asInput() != "*") || + is_known(name.substr(1), known_tipa_marks)) { + // name is a command that corresponds to a + // combining character in unicodesymbols. + // Append the argument, fromLaTeXCommand() + // will either convert it to a single + // character or a combining sequence. + name += '{' + p.verbatim_item() + '}'; + } + // now get the character from unicodesymbols + bool termination; + docstring rem; + set req; + docstring s = normalize_c(encodings.fromLaTeXCommand(from_utf8(name), + Encodings::TEXT_CMD, termination, rem, &req)); + if (!s.empty()) { + context.check_layout(os); + os << to_utf8(s); + if (!rem.empty()) + output_ert_inset(os, to_utf8(rem), context); + if (termination) + skip_spaces_braces(p); + for (set::const_iterator it = req.begin(); it != req.end(); ++it) + preamble.registerAutomaticallyLoadedPackage(*it); + } + //cerr << "#: " << t << " mode: " << mode << endl; + // heuristic: read up to next non-nested space + /* + string s = t.asInput(); + string z = p.verbatim_item(); + while (p.good() && z != " " && !z.empty()) { + //cerr << "read: " << z << endl; + s += z; + z = p.verbatim_item(); + } + cerr << "found ERT: " << s << endl; + output_ert_inset(os, s + ' ', context); + */ + else { + if (t.asInput() == name && + p.next_token().asInput() == "*") { + // Starred commands like \vspace*{} + p.get_token(); // Eat '*' + name += '*'; + } + if (!parse_command(name, p, os, outer, context)) + output_ert_inset(os, name, context); } } } From 5f359e27b06b3290707ae1fc327629a1e8339ff1 Mon Sep 17 00:00:00 2001 From: Juergen Spitzmueller Date: Mon, 5 Mar 2018 14:57:16 +0100 Subject: [PATCH 066/121] Small update of TODO (cherry picked from commit 4bc379ea67ea632ac13c12abd639f6b3f6b25a45) --- src/tex2lyx/TODO.txt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/tex2lyx/TODO.txt b/src/tex2lyx/TODO.txt index 2ea4d8bd32..63cd21e576 100644 --- a/src/tex2lyx/TODO.txt +++ b/src/tex2lyx/TODO.txt @@ -24,7 +24,6 @@ Format LaTeX feature LyX feature is just a string or if the file should be included and as what type) 254 esint.sty \use_esint 267 XeTeX utf8 encoding -270 \alert, \structure (beamer) layout 281 ? modules 293 ? InsetInfo 322 ? local layout @@ -69,7 +68,7 @@ Format LaTeX feature LyX feature \onslide text ... \end{overprint} 455 beamer frametitle command \begin_layout FrameTitle - \frametitle[short}{long} + \frametitle[short]{long} 456 memoir: \epigraph{text}{source} layout Epigraph, InsetArgument 457 automatic stackrel loading \use_package stackrel 459 beamer: \begin{frame}, \begin_layout Frame From a1cdc1e723a23abded37029cfee725f83492c115 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20St=C3=B6hr?= Date: Mon, 5 Mar 2018 17:37:50 +0100 Subject: [PATCH 067/121] tex2lyx/text.cpp: fix a typo (cherry picked from commit a30972a39c10647ffcb7eab5382f250331db7a8b) --- src/tex2lyx/text.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tex2lyx/text.cpp b/src/tex2lyx/text.cpp index 7c43a93aaf..6c938571e1 100644 --- a/src/tex2lyx/text.cpp +++ b/src/tex2lyx/text.cpp @@ -2520,7 +2520,7 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, bool have_cycled = false; while (p.good()) { - // Leave hear only after at least one cycle + // Leave here only after at least one cycle if (have_cycled && flags & FLAG_LEAVE) { flags &= ~FLAG_LEAVE; break; From 150fb89e22742dcf1f61500b498bc9e7e2a7702c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20St=C3=B6hr?= Date: Tue, 6 Mar 2018 13:52:42 +0100 Subject: [PATCH 068/121] status.23x: mention the new biblatex support in tex2lyx --- status.23x | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/status.23x b/status.23x index 3698b0648a..7d0cb287a2 100644 --- a/status.23x +++ b/status.23x @@ -21,6 +21,10 @@ What's new * TEX2LYX IMPROVEMENTS +- support for most commands provided by the biblatex package + +- support biblatex's qualified citation lists: + \cites(pre)(post)[pre1][post1]{key1}[pre2][post2]{key2}... * USER INTERFACE From 566f3688859b6343369dcda35a3d8663d4167127 Mon Sep 17 00:00:00 2001 From: Juergen Spitzmueller Date: Tue, 6 Mar 2018 17:31:19 +0100 Subject: [PATCH 069/121] Remove duplicate entries. --- status.23x | 4 ---- 1 file changed, 4 deletions(-) diff --git a/status.23x b/status.23x index 7d0cb287a2..3698b0648a 100644 --- a/status.23x +++ b/status.23x @@ -21,10 +21,6 @@ What's new * TEX2LYX IMPROVEMENTS -- support for most commands provided by the biblatex package - -- support biblatex's qualified citation lists: - \cites(pre)(post)[pre1][post1]{key1}[pre2][post2]{key2}... * USER INTERFACE From 94fe1261619b591f0c1bab825bd56059a5609a80 Mon Sep 17 00:00:00 2001 From: Juergen Spitzmueller Date: Tue, 6 Mar 2018 10:35:55 +0100 Subject: [PATCH 070/121] tex2lyx: fix subfloat import Fixes: #10385 (cherry picked from commit 1dcb2a09766335aecbe3c8599d09358e135d699c) --- src/tex2lyx/text.cpp | 33 ++++++++++++++++----------------- status.23x | 2 ++ 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/src/tex2lyx/text.cpp b/src/tex2lyx/text.cpp index 6c938571e1..5fd4f0ab91 100644 --- a/src/tex2lyx/text.cpp +++ b/src/tex2lyx/text.cpp @@ -3176,7 +3176,6 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, if (t.cs() == "subfloat") { // the syntax is \subfloat[list entry][sub caption]{content} // if it is a table of figure depends on the surrounding float - // FIXME: second optional argument is not parsed p.skip_spaces(); // do nothing if there is no outer float if (!float_type.empty()) { @@ -3195,6 +3194,12 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, caption = parse_text_snippet(p, FLAG_BRACK_LAST, outer, context); has_caption = true; } + // In case we have two optional args, the second is the caption. + if (p.next_token().cat() != catEscape && + p.next_token().character() == '[') { + p.get_token(); // eat '[' + caption = parse_text_snippet(p, FLAG_BRACK_LAST, outer, context); + } // the content parse_text_in_inset(p, os, FLAG_ITEM, outer, context); // the caption comes always as the last @@ -3208,31 +3213,25 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, newcontext.check_layout(os); os << caption << "\n"; newcontext.check_end_layout(os); - // We don't need really a new paragraph, but - // we must make sure that the next item gets a \begin_layout. - //newcontext.new_paragraph(os); end_inset(os); p.skip_spaces(); + // close the layout we opened + os << "\n\\end_layout"; } - // We don't need really a new paragraph, but - // we must make sure that the next item gets a \begin_layout. - if (has_caption) - context.new_paragraph(os); end_inset(os); p.skip_spaces(); - context.check_end_layout(os); - // close the layout we opened - if (has_caption) - os << "\n\\end_layout\n"; } else { // if the float type is not supported or there is no surrounding float // output it as ERT + string opt_arg1; + string opt_arg2; if (p.hasOpt()) { - string opt_arg = convert_command_inset_arg(p.getArg('[', ']')); - output_ert_inset(os, t.asInput() + '[' + opt_arg + - "]{" + p.verbatim_item() + '}', context); - } else - output_ert_inset(os, t.asInput() + "{" + p.verbatim_item() + '}', context); + opt_arg1 = convert_command_inset_arg(p.getFullOpt()); + if (p.hasOpt()) + opt_arg2 = convert_command_inset_arg(p.getFullOpt()); + } + output_ert_inset(os, t.asInput() + opt_arg1 + opt_arg2 + + "{" + p.verbatim_item() + '}', context); } continue; } diff --git a/status.23x b/status.23x index 3698b0648a..e828faa997 100644 --- a/status.23x +++ b/status.23x @@ -97,6 +97,8 @@ What's new * TEX2LYX +- Fix import of subfloats without caption (bug 10385). + - Import straight quotations marks (e.g. babel shorthands) as ERT (bug 75). - Consider options passed via \PassOptionsToPackage. From afeb5acb0fc958a1fb65f910ea15bf1899c175c7 Mon Sep 17 00:00:00 2001 From: Juergen Spitzmueller Date: Tue, 6 Mar 2018 15:31:43 +0100 Subject: [PATCH 071/121] Fix local polyglossia switch for Arabic We need to lowercase the language again (it's \begin{Arabic}, but \textarabic) Fixes: #11057. (cherry picked from commit 27584f5f7033f6abe127e66b4f5114663e043157) --- src/output_latex.cpp | 30 ++++++++++++++++++++---------- status.23x | 2 ++ 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/src/output_latex.cpp b/src/output_latex.cpp index 67f9bdd08c..fa890f5b3c 100644 --- a/src/output_latex.cpp +++ b/src/output_latex.cpp @@ -142,11 +142,16 @@ string const getPolyglossiaEnvName(Language const * lang) string const getPolyglossiaBegin(string const & lang_begin_command, - string const & lang, string const & opts) + string const & lang, string const & opts, + bool const localswitch = false) { string result; - if (!lang.empty()) - result = subst(lang_begin_command, "$$lang", lang); + if (!lang.empty()) { + // we need to revert the upcasing done in getPolyglossiaEnvName() + // in case we have a local polyglossia command (\textarabic). + string language = localswitch ? ascii_lowercase(lang) : lang; + result = subst(lang_begin_command, "$$lang", language); + } string options = opts.empty() ? string() : "[" + opts + "]"; result = subst(result, "$$opts", options); @@ -905,7 +910,9 @@ void TeXOnePar(Buffer const & buf, && (par_lang != openLanguageName(state) || localswitch) && !par_lang.empty()) { string bc = use_polyglossia ? - getPolyglossiaBegin(lang_begin_command, par_lang, par_language->polyglossiaOpts()) + getPolyglossiaBegin(lang_begin_command, par_lang, + par_language->polyglossiaOpts(), + localswitch) : subst(lang_begin_command, "$$lang", par_lang); os << bc; os << lang_command_termination; @@ -964,11 +971,13 @@ void TeXOnePar(Buffer const & buf, if (runparams.encoding->package() == Encoding::CJK && par_lang != openLanguageName(state) && !par_lang.empty()) { - os << from_ascii(subst( - lang_begin_command, - "$$lang", - par_lang)) - << lang_command_termination; + string bc = use_polyglossia ? + getPolyglossiaBegin(lang_begin_command, par_lang, + par_language->polyglossiaOpts(), + localswitch) + : subst(lang_begin_command, "$$lang", par_lang); + os << bc + << lang_command_termination; if (using_begin_end) pushLanguageName(par_lang, localswitch); } @@ -1135,7 +1144,8 @@ void TeXOnePar(Buffer const & buf, && current_lang != openLanguageName(state)) { string bc = use_polyglossia ? getPolyglossiaBegin(lang_begin_command, current_lang, - current_language->polyglossiaOpts()) + current_language->polyglossiaOpts(), + localswitch) : subst(lang_begin_command, "$$lang", current_lang); os << bc; pending_newline = !localswitch; diff --git a/status.23x b/status.23x index e828faa997..715c252ea0 100644 --- a/status.23x +++ b/status.23x @@ -60,6 +60,8 @@ What's new - Do not embrace numbers in \beginL ... \endL with polyglossia in Right- to-Left languages, since bidi handles the numbers automatically. +- Fix polyglossia language switches for Arabic (bug 11057). + * LYX2LYX From 30cb99503f21c123976f968d61484632d93353e4 Mon Sep 17 00:00:00 2001 From: Juergen Spitzmueller Date: Tue, 6 Mar 2018 17:54:32 +0100 Subject: [PATCH 072/121] tex2lyx: support alignment pseudo-environments. Fixes: #7857 (cherry picked from commit 7a22ce7c09f54ca70f30dde05c3f77c478195e45) --- src/tex2lyx/text.cpp | 14 ++++++++++---- status.23x | 3 +++ 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/tex2lyx/text.cpp b/src/tex2lyx/text.cpp index 5fd4f0ab91..914b42c84b 100644 --- a/src/tex2lyx/text.cpp +++ b/src/tex2lyx/text.cpp @@ -1896,12 +1896,18 @@ void parse_environment(Parser & p, ostream & os, bool outer, // Alignment and spacing settings // FIXME (bug xxxx): These settings can span multiple paragraphs and // therefore are totally broken! - // Note that \centering, raggedright, and raggedleft cannot be handled, as + // Note that \centering, \raggedright, and \raggedleft cannot be handled, as // they are commands not environments. They are furthermore switches that // can be ended by another switches, but also by commands like \footnote or // \parbox. So the only safe way is to leave them untouched. + // However, we support the pseudo-environments + // \begin{centering} ... \end{centering} + // \begin{raggedright} ... \end{raggedright} + // \begin{raggedleft} ... \end{raggedleft} + // since they are used by LyX in floats (for spacing reasons) else if (name == "center" || name == "centering" || - name == "flushleft" || name == "flushright" || + name == "flushleft" || name == "raggedright" || + name == "flushright" || name == "raggedleft" || name == "singlespace" || name == "onehalfspace" || name == "doublespace" || name == "spacing") { eat_whitespace(p, os, parent_context, false); @@ -1910,9 +1916,9 @@ void parse_environment(Parser & p, ostream & os, bool outer, parent_context.check_end_layout(os); parent_context.new_paragraph(os); } - if (name == "flushleft") + if (name == "flushleft" || name == "raggedright") parent_context.add_extra_stuff("\\align left\n"); - else if (name == "flushright") + else if (name == "flushright" || name == "raggedleft") parent_context.add_extra_stuff("\\align right\n"); else if (name == "center" || name == "centering") parent_context.add_extra_stuff("\\align center\n"); diff --git a/status.23x b/status.23x index 715c252ea0..ed12ee85d9 100644 --- a/status.23x +++ b/status.23x @@ -107,6 +107,9 @@ What's new - Add support for biblatex. +- Add support for alignment pseudo-environments as used inside floats + (bug 7857). + * ADVANCED FIND AND REPLACE From e9470e7d64117171a48c2cc3426c63856667c6d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20St=C3=B6hr?= Date: Tue, 6 Mar 2018 22:34:21 +0100 Subject: [PATCH 073/121] status.23x: correct sorting tex2lyx biblatex support is an improvement not a bugfix. At least in the past we sorted new tex2lyx features this way. --- status.23x | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/status.23x b/status.23x index ed12ee85d9..b13eaf517f 100644 --- a/status.23x +++ b/status.23x @@ -21,6 +21,7 @@ What's new * TEX2LYX IMPROVEMENTS +- Add support for biblatex. * USER INTERFACE @@ -105,8 +106,6 @@ What's new - Consider options passed via \PassOptionsToPackage. -- Add support for biblatex. - - Add support for alignment pseudo-environments as used inside floats (bug 7857). From 42dd5f5cfadb65f20280a3ad04ffc72a05780b4a Mon Sep 17 00:00:00 2001 From: Juergen Spitzmueller Date: Fri, 9 Mar 2018 13:30:52 +0100 Subject: [PATCH 074/121] tex2lyx: chapterbib support (cherry picked from commit af6933c06f603beca3d8684f56217243cbff1f94) --- src/tex2lyx/Preamble.cpp | 3 +++ src/tex2lyx/TODO.txt | 11 ++++------- status.23x | 2 ++ 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/tex2lyx/Preamble.cpp b/src/tex2lyx/Preamble.cpp index f86576ce3c..48dc8d69b6 100644 --- a/src/tex2lyx/Preamble.cpp +++ b/src/tex2lyx/Preamble.cpp @@ -1100,6 +1100,9 @@ void Preamble::handle_package(Parser &p, string const & name, else if (name == "bibtopic") h_use_bibtopic = "true"; + else if (name == "chapterbib") + h_multibib = "child"; + else if (name == "hyperref") handle_hyperref(options); diff --git a/src/tex2lyx/TODO.txt b/src/tex2lyx/TODO.txt index 63cd21e576..fc4bb994c7 100644 --- a/src/tex2lyx/TODO.txt +++ b/src/tex2lyx/TODO.txt @@ -32,6 +32,9 @@ Format LaTeX feature LyX feature 332 ? InsetGraphics groupId 343 ? \use_default_options 358 custom bibtex command \bibtex_command + Maybe via the + % !BIB program = + comment understood by some TeX editors 358 custom makeindex command \index_command 363 horizontal longtable alignment InsetTabular 364 branch file name suffix \filename_suffix @@ -55,8 +58,6 @@ Format LaTeX feature LyX feature 443 unicode-math.sty InsetMath* 445 URW Classico LaTeX font \font_sans uop \renewcommand{\sffamily}{uop} -446 Optional and required arguments InsetArgument - now numbered by order 448 451 beamer overlay arguments InsetArgument \command, \begin{env} @@ -69,7 +70,6 @@ Format LaTeX feature LyX feature \end{overprint} 455 beamer frametitle command \begin_layout FrameTitle \frametitle[short]{long} -456 memoir: \epigraph{text}{source} layout Epigraph, InsetArgument 457 automatic stackrel loading \use_package stackrel 459 beamer: \begin{frame}, \begin_layout Frame \begin{frame}[plain], \begin_layout PlainFrame @@ -99,14 +99,11 @@ Format LaTeX feature LyX feature 523 CJK Quote Styles InsetQuote - cjk (corner brackets) \begin_inset Quotes j.. - cjkangle (angle brackets) \begin_inset Quotes k.. -526 - Plural and capitalized refstyles InsetRef +526 Plural and capitalized refstyles InsetRef 533 Multibib support \begin{btUnit}...\end{btUnit} \multibib {none|part|chapter|section|subsection} (if a part, chapter, section etc. follows the \begin...) -534 Chapterbib support - \usepackage{chapterbib} \multibib child diff --git a/status.23x b/status.23x index b13eaf517f..d77a58e14d 100644 --- a/status.23x +++ b/status.23x @@ -23,6 +23,8 @@ What's new - Add support for biblatex. +- Add support for chapterbib. + * USER INTERFACE From 0f33720d29e330cb5180cdf45e01ba822e89a994 Mon Sep 17 00:00:00 2001 From: Juergen Spitzmueller Date: Fri, 9 Mar 2018 17:27:55 +0100 Subject: [PATCH 075/121] tex2lyx: support for \includeonly (cherry picked from commit 15fd17d83fb2b98d1ff226a79353e42f6e0247d4) --- src/tex2lyx/Preamble.cpp | 38 +++++++ src/tex2lyx/Preamble.h | 1 + src/tex2lyx/TODO.txt | 2 - src/tex2lyx/tex2lyx.h | 7 ++ src/tex2lyx/text.cpp | 212 +++++++++++++++++++-------------------- status.23x | 2 + 6 files changed, 154 insertions(+), 108 deletions(-) diff --git a/src/tex2lyx/Preamble.cpp b/src/tex2lyx/Preamble.cpp index 48dc8d69b6..78293bfad6 100644 --- a/src/tex2lyx/Preamble.cpp +++ b/src/tex2lyx/Preamble.cpp @@ -173,6 +173,11 @@ const char * const known_basic_color_codes[] = {"#000000", "#0000ff", "#964B00", const char * const known_if_3arg_commands[] = {"@ifundefined", "IfFileExists", 0}; +/*! + * Known file extensions for TeX files as used by \\includeonly + */ +char const * const known_tex_extensions[] = {"tex", 0}; + /// packages that work only in xetex /// polyglossia is handled separately const char * const known_xetex_packages[] = {"arabxetex", "fixlatvian", @@ -1252,6 +1257,12 @@ bool Preamble::writeLyXHeader(ostream & os, bool subdoc, string const & outfiled os << *it << '\n'; os << "\\end_modules\n"; } + if (!h_includeonlys.empty()) { + os << "\\begin_includeonly\n"; + for (auto const & iofile : h_includeonlys) + os << iofile << '\n'; + os << "\\end_includeonly\n"; + } os << "\\maintain_unincluded_children " << h_maintain_unincluded_children << "\n" << "\\language " << h_language << "\n" << "\\language_package " << h_language_package << "\n" @@ -2040,6 +2051,33 @@ void Preamble::parse(Parser & p, string const & forceclass, } } + if (t.cs() == "includeonly") { + vector includeonlys = getVectorFromString(p.getArg('{', '}')); + for (auto & iofile : includeonlys) { + string filename(normalize_filename(iofile)); + string const path = getMasterFilePath(true); + // We want to preserve relative/absolute filenames, + // therefore path is only used for testing + if (!makeAbsPath(filename, path).exists()) { + // The file extension is probably missing. + // Now try to find it out. + string const tex_name = + find_file(filename, path, + known_tex_extensions); + if (!tex_name.empty()) + filename = tex_name; + } + string outname; + if (makeAbsPath(filename, path).exists()) + fix_child_filename(filename); + else + cerr << "Warning: Could not find included file '" + << filename << "'." << endl; + outname = changeExtension(filename, "lyx"); + h_includeonlys.push_back(outname); + } + } + else if (is_known(t.cs(), known_if_3arg_commands)) { // prevent misparsing of \usepackage if it is used // as an argument (see e.g. our own output of diff --git a/src/tex2lyx/Preamble.h b/src/tex2lyx/Preamble.h index 074a85c613..9c70dca62a 100644 --- a/src/tex2lyx/Preamble.h +++ b/src/tex2lyx/Preamble.h @@ -223,6 +223,7 @@ private: std::map h_use_packages; std::string h_use_default_options; std::string h_use_hyperref; + std::vector h_includeonlys; bool h_use_refstyle; bool h_use_minted; diff --git a/src/tex2lyx/TODO.txt b/src/tex2lyx/TODO.txt index fc4bb994c7..8f8313378d 100644 --- a/src/tex2lyx/TODO.txt +++ b/src/tex2lyx/TODO.txt @@ -39,8 +39,6 @@ Format LaTeX feature LyX feature 363 horizontal longtable alignment InsetTabular 364 branch file name suffix \filename_suffix 371 automatic mhchem loading \use_mhchem -375 \includeonly \{begin,end}_includeonly -376 update .aux of unincluded children \maintain_unincluded_children 377 multirow.sty InsetTabular 378 revision info InsetInfo 380 ? InsetPreview diff --git a/src/tex2lyx/tex2lyx.h b/src/tex2lyx/tex2lyx.h index ff8185653f..c830b0531f 100644 --- a/src/tex2lyx/tex2lyx.h +++ b/src/tex2lyx/tex2lyx.h @@ -51,6 +51,13 @@ void parse_text(Parser & p, std::ostream & os, unsigned flags, bool outer, Context & context); void check_comment_bib(std::ostream & os, Context & context); +void fix_child_filename(std::string & name); + +std::string const normalize_filename(std::string const & name); + +std::string find_file(std::string const & name, std::string const & path, + char const * const * extensions); + /*! * Parses a subdocument, usually useful in insets (whence the name). * diff --git a/src/tex2lyx/text.cpp b/src/tex2lyx/text.cpp index 914b42c84b..285a818aa2 100644 --- a/src/tex2lyx/text.cpp +++ b/src/tex2lyx/text.cpp @@ -482,22 +482,6 @@ void translate_box_len(string const & length, string & value, string & unit, str } -/*! - * Find a file with basename \p name in path \p path and an extension - * in \p extensions. - */ -string find_file(string const & name, string const & path, - char const * const * extensions) -{ - for (char const * const * what = extensions; *what; ++what) { - string const trial = addExtension(name, *what); - if (makeAbsPath(trial, path).exists()) - return trial; - } - return string(); -} - - void begin_inset(ostream & os, string const & name) { os << "\n\\begin_inset " << name; @@ -2168,96 +2152,6 @@ void get_cite_arguments(Parser & p, bool natbibOrder, } -/// Convert filenames with TeX macros and/or quotes to something LyX -/// can understand -string const normalize_filename(string const & name) -{ - Parser p(name); - ostringstream os; - while (p.good()) { - Token const & t = p.get_token(); - if (t.cat() != catEscape) - os << t.asInput(); - else if (t.cs() == "lyxdot") { - // This is used by LyX for simple dots in relative - // names - os << '.'; - p.skip_spaces(); - } else if (t.cs() == "space") { - os << ' '; - p.skip_spaces(); - } else if (t.cs() == "string") { - // Convert \string" to " and \string~ to ~ - Token const & n = p.next_token(); - if (n.asInput() != "\"" && n.asInput() != "~") - os << t.asInput(); - } else - os << t.asInput(); - } - // Strip quotes. This is a bit complicated (see latex_path()). - string full = os.str(); - if (!full.empty() && full[0] == '"') { - string base = removeExtension(full); - string ext = getExtension(full); - if (!base.empty() && base[base.length()-1] == '"') - // "a b" - // "a b".tex - return addExtension(trim(base, "\""), ext); - if (full[full.length()-1] == '"') - // "a b.c" - // "a b.c".tex - return trim(full, "\""); - } - return full; -} - - -/// Convert \p name from TeX convention (relative to master file) to LyX -/// convention (relative to .lyx file) if it is relative -void fix_child_filename(string & name) -{ - string const absMasterTeX = getMasterFilePath(true); - bool const isabs = FileName::isAbsolute(name); - // convert from "relative to .tex master" to absolute original path - if (!isabs) - name = makeAbsPath(name, absMasterTeX).absFileName(); - bool copyfile = copyFiles(); - string const absParentLyX = getParentFilePath(false); - string abs = name; - if (copyfile) { - // convert from absolute original path to "relative to master file" - string const rel = to_utf8(makeRelPath(from_utf8(name), - from_utf8(absMasterTeX))); - // re-interpret "relative to .tex file" as "relative to .lyx file" - // (is different if the master .lyx file resides in a - // different path than the master .tex file) - string const absMasterLyX = getMasterFilePath(false); - abs = makeAbsPath(rel, absMasterLyX).absFileName(); - // Do not copy if the new path is impossible to create. Example: - // absMasterTeX = "/foo/bar/" - // absMasterLyX = "/bar/" - // name = "/baz.eps" => new absolute name would be "/../baz.eps" - if (contains(name, "/../")) - copyfile = false; - } - if (copyfile) { - if (isabs) - name = abs; - else { - // convert from absolute original path to - // "relative to .lyx file" - name = to_utf8(makeRelPath(from_utf8(abs), - from_utf8(absParentLyX))); - } - } - else if (!isabs) { - // convert from absolute original path to "relative to .lyx file" - name = to_utf8(makeRelPath(from_utf8(name), - from_utf8(absParentLyX))); - } -} - - void copy_file(FileName const & src, string dstname) { if (!copyFiles()) @@ -2482,6 +2376,112 @@ void registerExternalTemplatePackages(string const & name) } // anonymous namespace +/*! + * Find a file with basename \p name in path \p path and an extension + * in \p extensions. + */ +string find_file(string const & name, string const & path, + char const * const * extensions) +{ + for (char const * const * what = extensions; *what; ++what) { + string const trial = addExtension(name, *what); + if (makeAbsPath(trial, path).exists()) + return trial; + } + return string(); +} + + +/// Convert filenames with TeX macros and/or quotes to something LyX +/// can understand +string const normalize_filename(string const & name) +{ + Parser p(name); + ostringstream os; + while (p.good()) { + Token const & t = p.get_token(); + if (t.cat() != catEscape) + os << t.asInput(); + else if (t.cs() == "lyxdot") { + // This is used by LyX for simple dots in relative + // names + os << '.'; + p.skip_spaces(); + } else if (t.cs() == "space") { + os << ' '; + p.skip_spaces(); + } else if (t.cs() == "string") { + // Convert \string" to " and \string~ to ~ + Token const & n = p.next_token(); + if (n.asInput() != "\"" && n.asInput() != "~") + os << t.asInput(); + } else + os << t.asInput(); + } + // Strip quotes. This is a bit complicated (see latex_path()). + string full = os.str(); + if (!full.empty() && full[0] == '"') { + string base = removeExtension(full); + string ext = getExtension(full); + if (!base.empty() && base[base.length()-1] == '"') + // "a b" + // "a b".tex + return addExtension(trim(base, "\""), ext); + if (full[full.length()-1] == '"') + // "a b.c" + // "a b.c".tex + return trim(full, "\""); + } + return full; +} + + +/// Convert \p name from TeX convention (relative to master file) to LyX +/// convention (relative to .lyx file) if it is relative +void fix_child_filename(string & name) +{ + string const absMasterTeX = getMasterFilePath(true); + bool const isabs = FileName::isAbsolute(name); + // convert from "relative to .tex master" to absolute original path + if (!isabs) + name = makeAbsPath(name, absMasterTeX).absFileName(); + bool copyfile = copyFiles(); + string const absParentLyX = getParentFilePath(false); + string abs = name; + if (copyfile) { + // convert from absolute original path to "relative to master file" + string const rel = to_utf8(makeRelPath(from_utf8(name), + from_utf8(absMasterTeX))); + // re-interpret "relative to .tex file" as "relative to .lyx file" + // (is different if the master .lyx file resides in a + // different path than the master .tex file) + string const absMasterLyX = getMasterFilePath(false); + abs = makeAbsPath(rel, absMasterLyX).absFileName(); + // Do not copy if the new path is impossible to create. Example: + // absMasterTeX = "/foo/bar/" + // absMasterLyX = "/bar/" + // name = "/baz.eps" => new absolute name would be "/../baz.eps" + if (contains(name, "/../")) + copyfile = false; + } + if (copyfile) { + if (isabs) + name = abs; + else { + // convert from absolute original path to + // "relative to .lyx file" + name = to_utf8(makeRelPath(from_utf8(abs), + from_utf8(absParentLyX))); + } + } + else if (!isabs) { + // convert from absolute original path to "relative to .lyx file" + name = to_utf8(makeRelPath(from_utf8(name), + from_utf8(absParentLyX))); + } +} + + void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, Context & context) { diff --git a/status.23x b/status.23x index d77a58e14d..73a43d82fc 100644 --- a/status.23x +++ b/status.23x @@ -25,6 +25,8 @@ What's new - Add support for chapterbib. +- Add support for \includeonly. + * USER INTERFACE From 91ce18388ef3d60573cc6fc155ae5904d0981759 Mon Sep 17 00:00:00 2001 From: Juergen Spitzmueller Date: Sat, 10 Mar 2018 14:22:51 +0100 Subject: [PATCH 076/121] Amend 15fd17d83fb2 (cherry picked from commit b2ccdae22864ba72675b43d070022ae8fea18238) --- src/tex2lyx/Preamble.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tex2lyx/Preamble.cpp b/src/tex2lyx/Preamble.cpp index 78293bfad6..8565d59df3 100644 --- a/src/tex2lyx/Preamble.cpp +++ b/src/tex2lyx/Preamble.cpp @@ -2051,7 +2051,7 @@ void Preamble::parse(Parser & p, string const & forceclass, } } - if (t.cs() == "includeonly") { + else if (t.cs() == "includeonly") { vector includeonlys = getVectorFromString(p.getArg('{', '}')); for (auto & iofile : includeonlys) { string filename(normalize_filename(iofile)); From 5fc0dafac33f6244054d61f558fceead5b396932 Mon Sep 17 00:00:00 2001 From: Juergen Spitzmueller Date: Sat, 10 Mar 2018 15:00:30 +0100 Subject: [PATCH 077/121] tex2lyx: get rid of another large if-else if chain. (cherry picked from commit 11e4a24e6edbd1f69b60a194b31ac2d7c4dd5034) --- src/tex2lyx/Preamble.cpp | 153 ++++++++++++++++++++++++++------------- 1 file changed, 102 insertions(+), 51 deletions(-) diff --git a/src/tex2lyx/Preamble.cpp b/src/tex2lyx/Preamble.cpp index 8565d59df3..4ad6bad25e 100644 --- a/src/tex2lyx/Preamble.cpp +++ b/src/tex2lyx/Preamble.cpp @@ -1451,14 +1451,18 @@ void Preamble::parse(Parser & p, string const & forceclass, t.cat() == catBegin || t.cat() == catEnd || t.cat() == catAlign || - t.cat() == catParameter)) + t.cat() == catParameter)) { h_preamble << t.cs(); + continue; + } - else if (!in_lyx_preamble && - (t.cat() == catSpace || t.cat() == catNewline)) + if (!in_lyx_preamble && + (t.cat() == catSpace || t.cat() == catNewline)) { h_preamble << t.asInput(); + continue; + } - else if (t.cat() == catComment) { + if (t.cat() == catComment) { static regex const islyxfile("%% LyX .* created this file"); static regex const usercommands("User specified LaTeX commands"); @@ -1483,18 +1487,22 @@ void Preamble::parse(Parser & p, string const & forceclass, in_lyx_preamble = false; else if (!in_lyx_preamble) h_preamble << t.asInput(); + continue; } - else if (t.cs() == "PassOptionsToPackage") { + if (t.cs() == "PassOptionsToPackage") { string const poptions = p.getArg('{', '}'); string const package = p.verbatim_item(); extra_package_options_.insert(make_pair(package, poptions)); + continue; } - else if (t.cs() == "pagestyle") + if (t.cs() == "pagestyle") { h_paperpagestyle = p.verbatim_item(); + continue; + } - else if (t.cs() == "setdefaultlanguage") { + if (t.cs() == "setdefaultlanguage") { xetex = true; // We don't yet care about non-language variant options // because LyX doesn't support this yet, see bug #8214 @@ -1517,22 +1525,25 @@ void Preamble::parse(Parser & p, string const & forceclass, h_language = p.verbatim_item(); //finally translate the poyglossia name to a LyX name h_language = polyglossia2lyx(h_language); + continue; } - else if (t.cs() == "setotherlanguage") { + if (t.cs() == "setotherlanguage") { // We don't yet care about the option because LyX doesn't // support this yet, see bug #8214 p.hasOpt() ? p.getOpt() : string(); p.verbatim_item(); + continue; } - else if (t.cs() == "setmainfont") { + if (t.cs() == "setmainfont") { // we don't care about the option p.hasOpt() ? p.getOpt() : string(); h_font_roman[1] = p.getArg('{', '}'); + continue; } - else if (t.cs() == "setsansfont" || t.cs() == "setmonofont") { + if (t.cs() == "setsansfont" || t.cs() == "setmonofont") { // LyX currently only supports the scale option string scale; if (p.hasOpt()) { @@ -1556,6 +1567,7 @@ void Preamble::parse(Parser & p, string const & forceclass, h_font_tt_scale[1] = scale; h_font_typewriter[1] = p.getArg('{', '}'); } + continue; } else if (t.cs() == "date") { @@ -1566,7 +1578,7 @@ void Preamble::parse(Parser & p, string const & forceclass, h_preamble << t.asInput() << '{' << argument << '}'; } - else if (t.cs() == "color") { + if (t.cs() == "color") { string const space = (p.hasOpt() ? p.getOpt() : string()); string argument = p.getArg('{', '}'); @@ -1587,9 +1599,10 @@ void Preamble::parse(Parser & p, string const & forceclass, // is parsed before this h_fontcolor = ""; } + continue; } - else if (t.cs() == "pagecolor") { + if (t.cs() == "pagecolor") { string argument = p.getArg('{', '}'); // check the case that a standard color is used if (is_known(argument, known_basic_colors)) { @@ -1604,24 +1617,28 @@ void Preamble::parse(Parser & p, string const & forceclass, // is parsed before this h_backgroundcolor = ""; } + continue; } - else if (t.cs() == "makeatletter") { + if (t.cs() == "makeatletter") { // LyX takes care of this p.setCatcode('@', catLetter); + continue; } - else if (t.cs() == "makeatother") { + if (t.cs() == "makeatother") { // LyX takes care of this p.setCatcode('@', catOther); + continue; } - else if (t.cs() == "makeindex") { + if (t.cs() == "makeindex") { // LyX will re-add this if a print index command is found p.skip_spaces(); + continue; } - else if (t.cs() == "newindex") { + if (t.cs() == "newindex") { string const indexname = p.getArg('[', ']'); string const shortcut = p.verbatim_item(); if (!indexname.empty()) @@ -1631,17 +1648,21 @@ void Preamble::parse(Parser & p, string const & forceclass, h_shortcut[index_number] = shortcut; index_number += 1; p.skip_spaces(); + continue; } - else if (t.cs() == "addbibresource") + if (t.cs() == "addbibresource") { biblatex_bibliographies.push_back(removeExtension(p.getArg('{', '}'))); + continue; + } - else if (t.cs() == "bibliography") { + if (t.cs() == "bibliography") { vector bibs = getVectorFromString(p.getArg('{', '}')); biblatex_bibliographies.insert(biblatex_bibliographies.end(), bibs.begin(), bibs.end()); + continue; } - else if (t.cs() == "RS@ifundefined") { + if (t.cs() == "RS@ifundefined") { string const name = p.verbatim_item(); string const body1 = p.verbatim_item(); string const body2 = p.verbatim_item(); @@ -1657,9 +1678,10 @@ void Preamble::parse(Parser & p, string const & forceclass, << '{' << body2 << '}'; h_preamble << ss.str(); } + continue; } - else if (t.cs() == "AtBeginDocument") { + if (t.cs() == "AtBeginDocument") { string const name = p.verbatim_item(); // only non-lyxspecific stuff if (in_lyx_preamble && @@ -1685,15 +1707,16 @@ void Preamble::parse(Parser & p, string const & forceclass, ss << '{' << name << '}'; h_preamble << ss.str(); } + continue; } - else if (t.cs() == "newcommand" || t.cs() == "newcommandx" - || t.cs() == "renewcommand" || t.cs() == "renewcommandx" - || t.cs() == "providecommand" || t.cs() == "providecommandx" - || t.cs() == "DeclareRobustCommand" - || t.cs() == "DeclareRobustCommandx" - || t.cs() == "ProvideTextCommandDefault" - || t.cs() == "DeclareMathAccent") { + if (t.cs() == "newcommand" || t.cs() == "newcommandx" + || t.cs() == "renewcommand" || t.cs() == "renewcommandx" + || t.cs() == "providecommand" || t.cs() == "providecommandx" + || t.cs() == "DeclareRobustCommand" + || t.cs() == "DeclareRobustCommandx" + || t.cs() == "ProvideTextCommandDefault" + || t.cs() == "DeclareMathAccent") { bool star = false; if (p.next_token().character() == '*') { p.get_token(); @@ -1762,9 +1785,10 @@ void Preamble::parse(Parser & p, string const & forceclass, } // restore the in_lyx_preamble setting in_lyx_preamble = was_in_lyx_preamble; + continue; } - else if (t.cs() == "documentclass") { + if (t.cs() == "documentclass") { vector::iterator it; vector opts = split_options(p.getArg('[', ']')); handle_opt(opts, known_fontsizes, h_paperfontsize); @@ -1835,9 +1859,10 @@ void Preamble::parse(Parser & p, string const & forceclass, // different name in LyX than in LaTeX h_textclass = p.getArg('{', '}'); p.skip_spaces(); + continue; } - else if (t.cs() == "usepackage") { + if (t.cs() == "usepackage") { string const options = p.getArg('[', ']'); string const name = p.getArg('{', '}'); vector vecnames; @@ -1847,9 +1872,10 @@ void Preamble::parse(Parser & p, string const & forceclass, for (; it != end; ++it) handle_package(p, trimSpaceAndEol(*it), options, in_lyx_preamble, detectEncoding); + continue; } - else if (t.cs() == "inputencoding") { + if (t.cs() == "inputencoding") { string const encoding = p.getArg('{','}'); Encoding const * const enc = encodings.fromLaTeXName( encoding, Encoding::inputenc, true); @@ -1862,9 +1888,10 @@ void Preamble::parse(Parser & p, string const & forceclass, h_inputencoding = enc->name(); p.setEncoding(enc->iconvName()); } + continue; } - else if (t.cs() == "newenvironment") { + if (t.cs() == "newenvironment") { string const name = p.getArg('{', '}'); string const opt1 = p.getFullOpt(); string const opt2 = p.getFullOpt(); @@ -1877,10 +1904,10 @@ void Preamble::parse(Parser & p, string const & forceclass, } add_known_environment(name, opt1, !opt2.empty(), from_utf8(beg), from_utf8(end)); - + continue; } - else if (t.cs() == "newtheorem") { + if (t.cs() == "newtheorem") { bool star = false; if (p.next_token().character() == '*') { p.get_token(); @@ -1900,9 +1927,10 @@ void Preamble::parse(Parser & p, string const & forceclass, if (!in_lyx_preamble) h_preamble << complete; + continue; } - else if (t.cs() == "def") { + if (t.cs() == "def") { string name = p.get_token().cs(); // In fact, name may be more than the name: // In the test case of bug 8116 @@ -1913,9 +1941,10 @@ void Preamble::parse(Parser & p, string const & forceclass, if (!in_lyx_preamble) h_preamble << "\\def\\" << name << '{' << p.verbatim_item() << "}"; + continue; } - else if (t.cs() == "newcolumntype") { + if (t.cs() == "newcolumntype") { string const name = p.getArg('{', '}'); trimSpaceAndEol(name); int nargs = 0; @@ -1929,9 +1958,10 @@ void Preamble::parse(Parser & p, string const & forceclass, if (nargs) h_preamble << "[" << nargs << "]"; h_preamble << "{" << p.verbatim_item() << "}"; + continue; } - else if (t.cs() == "setcounter") { + if (t.cs() == "setcounter") { string const name = p.getArg('{', '}'); string const content = p.getArg('{', '}'); if (name == "secnumdepth") @@ -1940,9 +1970,10 @@ void Preamble::parse(Parser & p, string const & forceclass, h_tocdepth = content; else h_preamble << "\\setcounter{" << name << "}{" << content << "}"; + continue; } - else if (t.cs() == "setlength") { + if (t.cs() == "setlength") { string const name = p.verbatim_item(); string const content = p.verbatim_item(); // the paragraphs are only not indented when \parindent is set to zero @@ -1964,18 +1995,25 @@ void Preamble::parse(Parser & p, string const & forceclass, h_mathindentation = translate_len(content); } else h_preamble << "\\setlength{" << name << "}{" << content << "}"; + continue; } - else if (t.cs() == "onehalfspacing") + if (t.cs() == "onehalfspacing") { h_spacing = "onehalf"; + continue; + } - else if (t.cs() == "doublespacing") + if (t.cs() == "doublespacing") { h_spacing = "double"; + continue; + } - else if (t.cs() == "setstretch") + if (t.cs() == "setstretch") { h_spacing = "other " + p.verbatim_item(); + continue; + } - else if (t.cs() == "synctex") { + if (t.cs() == "synctex") { // the scheme is \synctex=value // where value can only be "1" or "-1" h_output_sync = "1"; @@ -1986,21 +2024,24 @@ void Preamble::parse(Parser & p, string const & forceclass, if (value == "-") value += p.get_token().asInput(); h_output_sync_macro = "\\synctex=" + value; + continue; } - else if (t.cs() == "begin") { + if (t.cs() == "begin") { string const name = p.getArg('{', '}'); if (name == "document") break; h_preamble << "\\begin{" << name << "}"; + continue; } - else if (t.cs() == "geometry") { + if (t.cs() == "geometry") { vector opts = split_options(p.getArg('{', '}')); handle_geometry(opts); + continue; } - else if (t.cs() == "definecolor") { + if (t.cs() == "definecolor") { string const color = p.getArg('{', '}'); string const space = p.getArg('{', '}'); string const value = p.getArg('{', '}'); @@ -2021,12 +2062,15 @@ void Preamble::parse(Parser & p, string const & forceclass, << "}{" << space << "}{" << value << '}'; } + continue; } - else if (t.cs() == "bibliographystyle") + if (t.cs() == "bibliographystyle") { h_biblio_style = p.verbatim_item(); + continue; + } - else if (t.cs() == "jurabibsetup") { + if (t.cs() == "jurabibsetup") { // FIXME p.getArg('{', '}') is most probably wrong (it // does not handle nested braces). // Use p.verbatim_item() instead. @@ -2038,9 +2082,10 @@ void Preamble::parse(Parser & p, string const & forceclass, h_preamble << "\\jurabibsetup{" << join(jurabibsetup, ",") << '}'; } + continue; } - else if (t.cs() == "hypersetup") { + if (t.cs() == "hypersetup") { vector hypersetup = split_options(p.verbatim_item()); // add hypersetup to the hyperref package options @@ -2049,9 +2094,10 @@ void Preamble::parse(Parser & p, string const & forceclass, h_preamble << "\\hypersetup{" << join(hypersetup, ",") << '}'; } + continue; } - else if (t.cs() == "includeonly") { + if (t.cs() == "includeonly") { vector includeonlys = getVectorFromString(p.getArg('{', '}')); for (auto & iofile : includeonlys) { string filename(normalize_filename(iofile)); @@ -2076,9 +2122,10 @@ void Preamble::parse(Parser & p, string const & forceclass, outname = changeExtension(filename, "lyx"); h_includeonlys.push_back(outname); } + continue; } - else if (is_known(t.cs(), known_if_3arg_commands)) { + if (is_known(t.cs(), known_if_3arg_commands)) { // prevent misparsing of \usepackage if it is used // as an argument (see e.g. our own output of // \@ifundefined above) @@ -2115,18 +2162,22 @@ void Preamble::parse(Parser & p, string const & forceclass, << '{' << arg2 << '}' << '{' << arg3 << '}'; } + continue; } - else if (is_known(t.cs(), known_if_commands)) { + if (is_known(t.cs(), known_if_commands)) { // must not parse anything in conditional code, since // LyX would output the parsed contents unconditionally if (!in_lyx_preamble) h_preamble << t.asInput(); handle_if(p, in_lyx_preamble); + continue; } - else if (!t.cs().empty() && !in_lyx_preamble) + if (!t.cs().empty() && !in_lyx_preamble) { h_preamble << '\\' << t.cs(); + continue; + } } // remove the whitespace From f183686505c150e335559056f1e3da4eb30af0f9 Mon Sep 17 00:00:00 2001 From: Juergen Spitzmueller Date: Sun, 11 Mar 2018 11:12:42 +0100 Subject: [PATCH 078/121] tex2lyx: support for URW Classico, MinionPro and the new Libertine fonts. (cherry picked from commit a3836d990926dfd8e7e35b266274c372c72206ce) --- src/tex2lyx/Preamble.cpp | 43 +++++++++++++++++++++++++++------------- src/tex2lyx/TODO.txt | 4 ---- status.23x | 2 ++ 3 files changed, 31 insertions(+), 18 deletions(-) diff --git a/src/tex2lyx/Preamble.cpp b/src/tex2lyx/Preamble.cpp index 4ad6bad25e..e0a5de32d6 100644 --- a/src/tex2lyx/Preamble.cpp +++ b/src/tex2lyx/Preamble.cpp @@ -126,17 +126,18 @@ char const * const known_fontsizes[] = { "10pt", "11pt", "12pt", 0 }; const char * const known_roman_fonts[] = { "ae", "beraserif", "bookman", "ccfonts", "chancery", "charter", "cmr", "cochineal", "crimson", "fourier", -"garamondx", "libertine", "libertine-type1", "lmodern", "mathdesign", "mathpazo", -"mathptmx", "newcent", "NotoSerif-TLF", "tgbonum", "tgchorus", "tgpagella", "tgschola", -"tgtermes", "utopia", 0}; +"garamondx", "libertine", "libertineRoman", "libertine-type1", "lmodern", "mathdesign", +"mathpazo", "mathptmx", "MinionPro", "newcent", "NotoSerif-TLF", "tgbonum", "tgchorus", +"tgpagella", "tgschola", "tgtermes", "utopia", 0 }; -const char * const known_sans_fonts[] = { "avant", "berasans", "biolinum-type1", -"cmbr", "cmss", "helvet", "iwona", "iwonac", "iwonal", "iwonalc", "kurier", -"kurierc", "kurierl", "kurierlc", "lmss", "NotoSans-TLF", "tgadventor", "tgheros", 0}; +const char * const known_sans_fonts[] = { "avant", "berasans", "biolinum", +"biolinum-type1", "cmbr", "cmss", "helvet", "iwona", "iwonac", "iwonal", "iwonalc", +"kurier", "kurierc", "kurierl", "kurierlc", "lmss", "NotoSans-TLF", +"tgadventor", "tgheros", "uop", 0 }; const char * const known_typewriter_fonts[] = { "beramono", "cmtl", "cmtt", -"courier", "lmtt", "luximono", "fourier", "libertineMono-type1", "lmodern", -"mathpazo", "mathptmx", "newcent", "NotoMono-TLF", "tgcursor", "txtt", 0}; +"courier", "lmtt", "luximono", "fourier", "libertineMono", "libertineMono-type1", "lmodern", +"mathpazo", "mathptmx", "newcent", "NotoMono-TLF", "tgcursor", "txtt", 0 }; const char * const known_math_fonts[] = { "eulervm", "newtxmath", 0}; @@ -733,22 +734,37 @@ void Preamble::handle_package(Parser &p, string const & name, h_font_roman[0] = "libertine"; // this automatically invokes biolinum h_font_sans[0] = "biolinum"; + // as well as libertineMono + h_font_typewriter[0] = "libertine-mono"; if (opts == "osf") h_font_osf = "true"; else if (opts == "lining") h_font_osf = "false"; } - if (name == "libertine-type1") { + if (name == "libertineRoman" || name == "libertine-type1") { h_font_roman[0] = "libertine"; - // NOTE: contrary to libertine.sty, libertine-type1 - // does not automatically invoke biolinum + // NOTE: contrary to libertine.sty, libertineRoman + // and libertine-type1 do not automatically invoke + // biolinum and libertineMono if (opts == "lining") h_font_osf = "false"; else if (opts == "osf") h_font_osf = "true"; } + if (name == "MinionPro") { + h_font_roman[0] = "minionpro"; + if (opts.find("lf") != string::npos) + h_font_osf = "false"; + else + h_font_osf = "true"; + if (opts.find("onlytext") != string::npos) + h_font_math[0] = "default"; + else + h_font_math[0] = "auto"; + } + if (name == "mathdesign") { if (opts.find("charter") != string::npos) h_font_roman[0] = "md-charter"; @@ -807,7 +823,7 @@ void Preamble::handle_package(Parser &p, string const & name, } } - if (name == "biolinum-type1") { + if (name == "biolinum" || name == "biolinum-type1") { h_font_sans[0] = "biolinum"; // biolinum can have several options, e.g. [osf,scaled=0.97] string::size_type pos = opts.find("osf"); @@ -828,9 +844,8 @@ void Preamble::handle_package(Parser &p, string const & name, } } - if (name == "libertineMono-type1") { + if (name == "libertineMono" || name == "libertineMono-type1") h_font_typewriter[0] = "libertine-mono"; - } // font uses old-style figure if (name == "eco") diff --git a/src/tex2lyx/TODO.txt b/src/tex2lyx/TODO.txt index 8f8313378d..767bccf867 100644 --- a/src/tex2lyx/TODO.txt +++ b/src/tex2lyx/TODO.txt @@ -51,11 +51,7 @@ Format LaTeX feature LyX feature 411 support for polyglossia \language_package (the cases of no package, of babel and of custom package is supported) 415 automatic undertilde loading \use_package undertilde 438 \t*{ } InsetTIPA -439 MinionPro.sty \font_roman, \font_osf -440 MinionPro.sty, \font_math 443 unicode-math.sty InsetMath* -445 URW Classico LaTeX font \font_sans uop - \renewcommand{\sffamily}{uop} 448 451 beamer overlay arguments InsetArgument \command, \begin{env} diff --git a/status.23x b/status.23x index 73a43d82fc..ea89b77751 100644 --- a/status.23x +++ b/status.23x @@ -27,6 +27,8 @@ What's new - Add support for \includeonly. +- Add support for URW Classico, MinionPro and the new Libertine fonts. + * USER INTERFACE From bd876d816330b56ad1e6dd62302e52f7462ffc08 Mon Sep 17 00:00:00 2001 From: Juergen Spitzmueller Date: Thu, 8 Mar 2018 15:00:33 +0100 Subject: [PATCH 079/121] tex2lyx: towards proper support of "literal"/"latexified" inset commands We now report whether the attempt to recode the macros to glyphs succeeded. If yes, we set "literate" to false, if not to true. Also, do not attempt to recode for non-latexifying fields. Fixes: #9563 (cherry picked from commit 6659304f7f8b57f12a1bf453a11ea359c83a7d14) --- src/tex2lyx/text.cpp | 212 +++++++++++++++++++++++++++++++------------ 1 file changed, 153 insertions(+), 59 deletions(-) diff --git a/src/tex2lyx/text.cpp b/src/tex2lyx/text.cpp index 285a818aa2..2d9bf4b2b0 100644 --- a/src/tex2lyx/text.cpp +++ b/src/tex2lyx/text.cpp @@ -518,8 +518,12 @@ bool skip_braces(Parser & p) /// replace LaTeX commands in \p s from the unicodesymbols file with their /// unicode points -docstring convert_unicodesymbols(docstring s) +pair convert_unicodesymbols(docstring s) { + bool res = true; + int const nchars_escape = 8; + static char_type const chars_escape[nchars_escape] = { + '&', '_', '$', '%', '#', '^', '{', '}'}; odocstringstream os; for (size_t i = 0; i < s.size();) { if (s[i] != '\\') { @@ -540,24 +544,42 @@ docstring convert_unicodesymbols(docstring s) s = rem; if (s.empty() || s[0] != '\\') i = 0; - else + else { + res = false; + for (int k = 0; k < nchars_escape; k++) + if (prefixIs(s, from_ascii("\\") + chars_escape[k])) + res = true; i = 1; + } } - return os.str(); + return make_pair(res, os.str()); } /// try to convert \p s to a valid InsetCommand argument -string convert_command_inset_arg(string s) +/// return whether this succeeded. If not, these command insets +/// get the "literate" flag. +pair convert_latexed_command_inset_arg(string s) { - if (isAscii(s)) + bool success = false; + if (isAscii(s)) { // since we don't know the input encoding we can't use from_utf8 - s = to_utf8(convert_unicodesymbols(from_ascii(s))); + pair res = convert_unicodesymbols(from_ascii(s)); + success = res.first; + s = to_utf8(res.second); + } + // LyX cannot handle newlines in a latex command + return make_pair(success, subst(s, "\n", " ")); +} + +/// try to convert \p s to a valid InsetCommand argument +/// without trying to recode macros. +string convert_literate_command_inset_arg(string s) +{ // LyX cannot handle newlines in a latex command return subst(s, "\n", " "); } - void output_ert(ostream & os, string const & s, Context & context) { context.check_layout(os); @@ -3012,20 +3034,17 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, context.set_item(); context.check_layout(os); eat_whitespace(p, os, context, false); - string label = convert_command_inset_arg(p.verbatimOption()); - string key = convert_command_inset_arg(p.verbatim_item()); - if (contains(label, '\\') || contains(key, '\\')) { - // LyX can't handle LaTeX commands in labels or keys - output_ert_inset(os, t.asInput() + '[' + label + - "]{" + p.verbatim_item() + '}', - context); - } else { - begin_command_inset(os, "bibitem", "bibitem"); - os << "label \"" << label << "\"\n" - << "key \"" << key << "\"\n" - << "literal \"true\"\n"; - end_inset(os); - } + string label = p.verbatimOption(); + pair lbl = convert_latexed_command_inset_arg(label); + bool const literal = !lbl.first; + label = literal ? subst(label, "\n", " ") : lbl.second; + string lit = literal ? "\"true\"" : "\"false\""; + string key = convert_literate_command_inset_arg(p.verbatim_item()); + begin_command_inset(os, "bibitem", "bibitem"); + os << "label \"" << label << "\"\n" + << "key \"" << key << "\"\n" + << "literal " << lit << "\n"; + end_inset(os); continue; } @@ -3232,9 +3251,9 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, string opt_arg1; string opt_arg2; if (p.hasOpt()) { - opt_arg1 = convert_command_inset_arg(p.getFullOpt()); + opt_arg1 = convert_literate_command_inset_arg(p.getFullOpt()); if (p.hasOpt()) - opt_arg2 = convert_command_inset_arg(p.getFullOpt()); + opt_arg2 = convert_literate_command_inset_arg(p.getFullOpt()); } output_ert_inset(os, t.asInput() + opt_arg1 + opt_arg2 + "{" + p.verbatim_item() + '}', context); @@ -3727,8 +3746,12 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, if (t.cs() == "href") { context.check_layout(os); - string target = convert_command_inset_arg(p.verbatim_item()); - string name = convert_command_inset_arg(p.verbatim_item()); + string target = convert_literate_command_inset_arg(p.verbatim_item()); + string name = p.verbatim_item(); + pair nm = convert_latexed_command_inset_arg(name); + bool const literal = !nm.first; + name = literal ? subst(name, "\n", " ") : nm.second; + string lit = literal ? "\"true\"" : "\"false\""; string type; size_t i = target.find(':'); if (i != string::npos) { @@ -3745,7 +3768,7 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, os << "target \"" << target << "\"\n"; if (type == "mailto:" || type == "file:") os << "type \"" << type << "\"\n"; - os << "literal \"true\"\n"; + os << "literal " << lit << "\n"; end_inset(os); skip_spaces_braces(p); continue; @@ -3804,7 +3827,7 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, os << "reference \""; os << known_refstyle_prefixes[where - known_refstyle_commands] << ":"; - os << convert_command_inset_arg(p.verbatim_item()) + os << convert_literate_command_inset_arg(p.verbatim_item()) << "\"\n"; os << "plural \"false\"\n"; os << "caps \"false\"\n"; @@ -3824,7 +3847,7 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, begin_command_inset(os, "ref", known_coded_ref_commands[where - known_ref_commands]); os << "reference \"" - << convert_command_inset_arg(p.verbatim_item()) + << convert_literate_command_inset_arg(p.verbatim_item()) << "\"\n"; os << "plural \"false\"\n"; os << "caps \"false\"\n"; @@ -3881,24 +3904,34 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, before.erase(); after.erase(); } + bool literal = false; + pair aft; + pair bef; // remove the brackets around after and before if (!after.empty()) { after.erase(0, 1); after.erase(after.length() - 1, 1); - after = convert_command_inset_arg(after); + aft = convert_latexed_command_inset_arg(after); + literal = !aft.first; + after = literal ? subst(after, "\n", " ") : aft.second; } if (!before.empty()) { before.erase(0, 1); before.erase(before.length() - 1, 1); - before = convert_command_inset_arg(before); + bef = convert_latexed_command_inset_arg(after); + literal |= !bef.first; + before = literal ? subst(before, "\n", " ") : bef.second; + if (literal && !after.empty()) + after = subst(after, "\n", " "); } + string lit = literal ? "\"true\"" : "\"false\""; begin_command_inset(os, "citation", command); os << "after " << '"' << after << '"' << "\n"; os << "before " << '"' << before << '"' << "\n"; os << "key \"" - << convert_command_inset_arg(p.verbatim_item()) + << convert_literate_command_inset_arg(p.verbatim_item()) << "\"\n" - << "literal \"true\"\n"; + << "literal " << lit << "\n"; end_inset(os); // Need to set the cite engine if natbib is loaded by // the document class directly @@ -3971,58 +4004,83 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, before.erase(); after.erase(); } + bool literal = false; + pair aft; + pair bef; // remove the brackets around after and before if (!after.empty()) { after.erase(0, 1); after.erase(after.length() - 1, 1); - after = convert_command_inset_arg(after); + aft = convert_latexed_command_inset_arg(after); + literal = !aft.first; + after = literal ? subst(after, "\n", " ") : aft.second; } if (!before.empty()) { before.erase(0, 1); before.erase(before.length() - 1, 1); - before = convert_command_inset_arg(before); + bef = convert_latexed_command_inset_arg(after); + literal |= !bef.first; + before = literal ? subst(before, "\n", " ") : bef.second; } string keys, pretextlist, posttextlist; if (qualified) { - map pres; - map posts; + map pres, posts, preslit, postslit; vector lkeys; // text before the citation - string lbefore; + string lbefore, lbeforelit; // text after the citation - string lafter; - string lkey; + string lafter, lafterlit; + string lkey; + pair laft, lbef; while (true) { get_cite_arguments(p, true, lbefore, lafter); // remove the brackets around after and before if (!lafter.empty()) { lafter.erase(0, 1); lafter.erase(lafter.length() - 1, 1); - lafter = convert_command_inset_arg(lafter); + laft = convert_latexed_command_inset_arg(lafter); + literal |= !laft.first; + lafter = laft.second; + lafterlit = subst(lbefore, "\n", " "); } if (!lbefore.empty()) { lbefore.erase(0, 1); lbefore.erase(lbefore.length() - 1, 1); - lbefore = convert_command_inset_arg(lbefore); + lbef = convert_latexed_command_inset_arg(lbefore); + literal |= !lbef.first; + lbefore = lbef.second; + lbeforelit = subst(lbefore, "\n", " "); } - if (lbefore.empty() && lafter == "[]") + if (lbefore.empty() && lafter == "[]") { // avoid \cite[]{a} lafter.erase(); + lafterlit.erase(); + } else if (lbefore == "[]" && lafter == "[]") { // avoid \cite[][]{a} lbefore.erase(); lafter.erase(); + lbeforelit.erase(); + lafterlit.erase(); } lkey = p.getArg('{', '}'); if (lkey.empty()) break; - if (!lbefore.empty()) + if (!lbefore.empty()) { pres.insert(make_pair(lkey, lbefore)); - if (!lafter.empty()) + preslit.insert(make_pair(lkey, lbeforelit)); + } + if (!lafter.empty()) { posts.insert(make_pair(lkey, lafter)); + postslit.insert(make_pair(lkey, lafterlit)); + } lkeys.push_back(lkey); } - keys = convert_command_inset_arg(getStringFromVector(lkeys)); + keys = convert_literate_command_inset_arg(getStringFromVector(lkeys)); + if (literal) { + pres = preslit; + posts = postslit; + } for (auto const & ptl : pres) { if (!pretextlist.empty()) pretextlist += '\t'; @@ -4034,7 +4092,14 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, posttextlist += potl.first + " " + potl.second; } } else - keys = convert_command_inset_arg(p.verbatim_item()); + keys = convert_literate_command_inset_arg(p.verbatim_item()); + if (literal) { + if (!after.empty()) + after = subst(after, "\n", " "); + if (!before.empty()) + before = subst(after, "\n", " "); + } + string lit = literal ? "\"true\"" : "\"false\""; begin_command_inset(os, "citation", command); os << "after " << '"' << after << '"' << "\n"; os << "before " << '"' << before << '"' << "\n"; @@ -4045,7 +4110,7 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, os << "pretextlist " << '"' << pretextlist << '"' << "\n"; if (!posttextlist.empty()) os << "posttextlist " << '"' << posttextlist << '"' << "\n"; - os << "literal \"true\"\n"; + os << "literal " << lit << "\n"; end_inset(os); // Need to set the cite engine if biblatex is loaded by // the document class directly @@ -4091,19 +4156,32 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, "package options if you used an\n" "earlier jurabib version." << endl; } + bool literal = false; + pair aft; + pair bef; + // remove the brackets around after and before if (!after.empty()) { after.erase(0, 1); after.erase(after.length() - 1, 1); + aft = convert_latexed_command_inset_arg(after); + literal = !aft.first; + after = literal ? subst(after, "\n", " ") : aft.second; } if (!before.empty()) { before.erase(0, 1); before.erase(before.length() - 1, 1); + bef = convert_latexed_command_inset_arg(after); + literal |= !bef.first; + before = literal ? subst(before, "\n", " ") : bef.second; + if (literal && !after.empty()) + after = subst(after, "\n", " "); } + string lit = literal ? "\"true\"" : "\"false\""; begin_command_inset(os, "citation", command); os << "after " << '"' << after << "\"\n" << "before " << '"' << before << "\"\n" << "key " << '"' << citation << "\"\n" - << "literal \"true\"\n"; + << "literal " << lit << "\n"; end_inset(os); // Need to set the cite engine if jurabib is loaded by // the document class directly @@ -4115,15 +4193,19 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, if (t.cs() == "cite" || t.cs() == "nocite") { context.check_layout(os); - string after = convert_command_inset_arg(p.getArg('[', ']')); - string key = convert_command_inset_arg(p.verbatim_item()); + string after = p.getArg('[', ']'); + pair aft = convert_latexed_command_inset_arg(after); + bool const literal = !aft.first; + after = literal ? subst(after, "\n", " ") : aft.second; + string lit = literal ? "\"true\"" : "\"false\""; + string key = convert_literate_command_inset_arg(p.verbatim_item()); // store the case that it is "\nocite{*}" to use it later for // the BibTeX inset if (key != "*") { begin_command_inset(os, "citation", t.cs()); os << "after " << '"' << after << "\"\n" << "key " << '"' << key << "\"\n" - << "literal \"true\"\n"; + << "literal " << lit << "\n"; end_inset(os); } else if (t.cs() == "nocite") btprint = key; @@ -4148,15 +4230,27 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, if (t.cs() == "nomenclature") { context.check_layout(os); begin_command_inset(os, "nomenclature", "nomenclature"); - string prefix = convert_command_inset_arg(p.getArg('[', ']')); + string prefix = convert_literate_command_inset_arg(p.getArg('[', ']')); if (!prefix.empty()) os << "prefix " << '"' << prefix << '"' << "\n"; - os << "symbol " << '"' - << convert_command_inset_arg(p.verbatim_item()); + string symbol = p.verbatim_item(); + pair sym = convert_latexed_command_inset_arg(symbol); + bool literal = !sym.first; + string description = p.verbatim_item(); + pair desc = convert_latexed_command_inset_arg(description); + literal |= !desc.first; + if (literal) { + symbol = subst(symbol, "\n", " "); + description = subst(description, "\n", " "); + } else { + symbol = sym.second; + description = desc.second; + } + string lit = literal ? "\"true\"" : "\"false\""; + os << "symbol " << '"' << symbol; os << "\"\ndescription \"" - << convert_command_inset_arg(p.verbatim_item()) - << "\"\n" - << "literal \"true\"\n"; + << description << "\"\n" + << "literal " << lit << "\n"; end_inset(os); preamble.registerAutomaticallyLoadedPackage("nomencl"); continue; @@ -4166,7 +4260,7 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, context.check_layout(os); begin_command_inset(os, "label", "label"); os << "name \"" - << convert_command_inset_arg(p.verbatim_item()) + << convert_literate_command_inset_arg(p.verbatim_item()) << "\"\n"; end_inset(os); continue; @@ -4229,7 +4323,7 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, // via \settowidth{\nomlabelwidth}{***} cannot be supported // because the user could have set anything, not only the width // of the longest label (which would be width_type = "auto") - string label = convert_command_inset_arg(p.getArg('{', '}')); + string label = convert_literate_command_inset_arg(p.getArg('{', '}')); if (label.empty() && width_type.empty()) width_type = "none"; os << "set_width \"" << width_type << "\"\n"; From ce2e1554908785d7accba292985017fb961b1450 Mon Sep 17 00:00:00 2001 From: Juergen Spitzmueller Date: Fri, 9 Mar 2018 12:29:07 +0100 Subject: [PATCH 080/121] Fix copy and paste error in 6659304f7f8b (cherry picked from commit 0513622fd0ce600cbf283f6afdbde9841d46a546) --- src/tex2lyx/text.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/tex2lyx/text.cpp b/src/tex2lyx/text.cpp index 2d9bf4b2b0..c5d7ce21d0 100644 --- a/src/tex2lyx/text.cpp +++ b/src/tex2lyx/text.cpp @@ -3918,7 +3918,7 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, if (!before.empty()) { before.erase(0, 1); before.erase(before.length() - 1, 1); - bef = convert_latexed_command_inset_arg(after); + bef = convert_latexed_command_inset_arg(before); literal |= !bef.first; before = literal ? subst(before, "\n", " ") : bef.second; if (literal && !after.empty()) @@ -4018,7 +4018,7 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, if (!before.empty()) { before.erase(0, 1); before.erase(before.length() - 1, 1); - bef = convert_latexed_command_inset_arg(after); + bef = convert_latexed_command_inset_arg(before); literal |= !bef.first; before = literal ? subst(before, "\n", " ") : bef.second; } @@ -4170,7 +4170,7 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, if (!before.empty()) { before.erase(0, 1); before.erase(before.length() - 1, 1); - bef = convert_latexed_command_inset_arg(after); + bef = convert_latexed_command_inset_arg(before); literal |= !bef.first; before = literal ? subst(before, "\n", " ") : bef.second; if (literal && !after.empty()) From 590185d3ef903714090c0461d4e1c427679a2833 Mon Sep 17 00:00:00 2001 From: Juergen Spitzmueller Date: Fri, 9 Mar 2018 13:14:13 +0100 Subject: [PATCH 081/121] tex2lyx: honor grouping in optional arguments. E.g., \cite[{a literal ] character}]{key} (cherry picked from commit cba38881d6b9fa3ff5dd0ebe50239fc384309082) --- src/tex2lyx/Parser.cpp | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/tex2lyx/Parser.cpp b/src/tex2lyx/Parser.cpp index 35748b9769..6e29623b96 100644 --- a/src/tex2lyx/Parser.cpp +++ b/src/tex2lyx/Parser.cpp @@ -494,6 +494,7 @@ Parser::Arg Parser::getFullArg(char left, char right, bool allow_escaping) if (! good()) return make_pair(false, string()); + int group_level = 0; string result; Token t = get_token(); @@ -504,6 +505,15 @@ Parser::Arg Parser::getFullArg(char left, char right, bool allow_escaping) } else { while (good()) { t = get_token(); + // honor grouping + if (left != '{' && t.cat() == catBegin) { + ++group_level; + continue; + } + if (left != '{' && t.cat() == catEnd) { + --group_level; + continue; + } // Ignore comments if (t.cat() == catComment) { if (!t.cs().empty()) @@ -511,13 +521,15 @@ Parser::Arg Parser::getFullArg(char left, char right, bool allow_escaping) continue; } if (allow_escaping) { - if (t.cat() != catEscape && t.character() == right) + if (t.cat() != catEscape && t.character() == right + && group_level == 0) break; } else { if (t.character() == right) { if (t.cat() == catEscape) result += '\\'; - break; + if (group_level == 0) + break; } } result += t.asInput(); From 624a6642e93367d52a4a94f295b0036701ebdec5 Mon Sep 17 00:00:00 2001 From: Juergen Spitzmueller Date: Sat, 10 Mar 2018 14:58:55 +0100 Subject: [PATCH 082/121] tex2lyx: make nested CJK parsing slightly less dumb. Fixes: #9562 (cherry picked from commit 0f4c9027056a6f4f771382e9ebfc7940274bf5c0) --- src/tex2lyx/text.cpp | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/tex2lyx/text.cpp b/src/tex2lyx/text.cpp index c5d7ce21d0..4f7f5a73d7 100644 --- a/src/tex2lyx/text.cpp +++ b/src/tex2lyx/text.cpp @@ -343,6 +343,10 @@ bool minted_float_has_caption = false; // The caption for non-floating minted listings string minted_nonfloat_caption = ""; +// Characters that have to be escaped by \\ in LaTeX +char const * const known_escaped_chars[] = { + "&", "_", "$", "%", "#", "^", "{", "}"}; + /// splits "x=z, y=b" into a map and an ordered keyword vector void split_map(string const & s, map & res, vector & keys) @@ -521,9 +525,6 @@ bool skip_braces(Parser & p) pair convert_unicodesymbols(docstring s) { bool res = true; - int const nchars_escape = 8; - static char_type const chars_escape[nchars_escape] = { - '&', '_', '$', '%', '#', '^', '{', '}'}; odocstringstream os; for (size_t i = 0; i < s.size();) { if (s[i] != '\\') { @@ -546,8 +547,8 @@ pair convert_unicodesymbols(docstring s) i = 0; else { res = false; - for (int k = 0; k < nchars_escape; k++) - if (prefixIs(s, from_ascii("\\") + chars_escape[k])) + for (auto const & c : known_escaped_chars) + if (prefixIs(s, from_ascii("\\") + c)) res = true; i = 1; } @@ -1719,10 +1720,10 @@ void parse_environment(Parser & p, ostream & os, bool outer, // things like comments are completely wrong. string const s = p.plainEnvironment("CJK"); for (string::const_iterator it = s.begin(), et = s.end(); it != et; ++it) { - if (*it == '\\') - output_ert_inset(os, "\\", parent_context); - else if (*it == '$') - output_ert_inset(os, "$", parent_context); + string snip; + snip += *it; + if (snip == "\\" || is_known(snip, known_escaped_chars)) + output_ert_inset(os, snip, parent_context); else if (*it == '\n' && it + 1 != et && s.begin() + 1 != it) os << "\n "; else From 8f69f7af01629b04256a1abadaafeaf430edf5a3 Mon Sep 17 00:00:00 2001 From: Juergen Spitzmueller Date: Sun, 11 Mar 2018 18:33:45 +0100 Subject: [PATCH 083/121] Status updates. --- status.23x | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/status.23x b/status.23x index ea89b77751..2cd3d67222 100644 --- a/status.23x +++ b/status.23x @@ -29,6 +29,9 @@ What's new - Add support for URW Classico, MinionPro and the new Libertine fonts. +- Implement better parsing of some command options (via "literate" + function of some insets) (bug 9563). + * USER INTERFACE @@ -115,6 +118,8 @@ What's new - Add support for alignment pseudo-environments as used inside floats (bug 7857). +- Fix parsing issue in nested CJK (bug 9562). + * ADVANCED FIND AND REPLACE From 64981aa48c309690d64185065c2aaf9e1820a0c9 Mon Sep 17 00:00:00 2001 From: Juergen Spitzmueller Date: Sun, 11 Mar 2018 19:31:19 +0100 Subject: [PATCH 084/121] update tex2lyx tests. --- .../test/box-color-size-space-align.lyx.lyx | 42 +++++++++++- src/tex2lyx/test/test-insets-basic.lyx.lyx | 66 ++++++++++++++++++- src/tex2lyx/test/test-insets.lyx.lyx | 66 ++++++++++++++++++- src/tex2lyx/test/test-structure.lyx.lyx | 3 - 4 files changed, 167 insertions(+), 10 deletions(-) diff --git a/src/tex2lyx/test/box-color-size-space-align.lyx.lyx b/src/tex2lyx/test/box-color-size-space-align.lyx.lyx index 30a2b15551..b6926c7eab 100644 --- a/src/tex2lyx/test/box-color-size-space-align.lyx.lyx +++ b/src/tex2lyx/test/box-color-size-space-align.lyx.lyx @@ -2878,7 +2878,47 @@ Characters \begin_layout Standard \size normal -from package "ascii" and "ifsym": ®↨◻◼◙ +from package +\begin_inset ERT +status collapsed + +\begin_layout Plain Layout +" +\end_layout + +\end_inset + +ascii +\begin_inset ERT +status collapsed + +\begin_layout Plain Layout +" +\end_layout + +\end_inset + + and +\begin_inset ERT +status collapsed + +\begin_layout Plain Layout +" +\end_layout + +\end_inset + +ifsym +\begin_inset ERT +status collapsed + +\begin_layout Plain Layout +" +\end_layout + +\end_inset + +: ®↨◻◼◙ \end_layout \begin_layout Standard diff --git a/src/tex2lyx/test/test-insets-basic.lyx.lyx b/src/tex2lyx/test/test-insets-basic.lyx.lyx index 3e29da2602..4d7a58ac0b 100644 --- a/src/tex2lyx/test/test-insets-basic.lyx.lyx +++ b/src/tex2lyx/test/test-insets-basic.lyx.lyx @@ -7063,7 +7063,27 @@ literal "true" \end_layout \begin_layout Standard -index "idx": +index +\begin_inset ERT +status collapsed + +\begin_layout Plain Layout +" +\end_layout + +\end_inset + +idx +\begin_inset ERT +status collapsed + +\begin_layout Plain Layout +" +\end_layout + +\end_inset + +: \end_layout \begin_layout Standard @@ -7079,7 +7099,27 @@ literal "true" \end_layout \begin_layout Standard -index "new": +index +\begin_inset ERT +status collapsed + +\begin_layout Plain Layout +" +\end_layout + +\end_inset + +new +\begin_inset ERT +status collapsed + +\begin_layout Plain Layout +" +\end_layout + +\end_inset + +: \end_layout \begin_layout Standard @@ -7095,7 +7135,27 @@ literal "true" \end_layout \begin_layout Standard -subindex "new": +subindex +\begin_inset ERT +status collapsed + +\begin_layout Plain Layout +" +\end_layout + +\end_inset + +new +\begin_inset ERT +status collapsed + +\begin_layout Plain Layout +" +\end_layout + +\end_inset + +: \end_layout \begin_layout Standard diff --git a/src/tex2lyx/test/test-insets.lyx.lyx b/src/tex2lyx/test/test-insets.lyx.lyx index 0aa2ee886a..60f7d40491 100644 --- a/src/tex2lyx/test/test-insets.lyx.lyx +++ b/src/tex2lyx/test/test-insets.lyx.lyx @@ -7516,7 +7516,27 @@ literal "true" \end_layout \begin_layout Standard -index "idx": +index +\begin_inset ERT +status collapsed + +\begin_layout Plain Layout +" +\end_layout + +\end_inset + +idx +\begin_inset ERT +status collapsed + +\begin_layout Plain Layout +" +\end_layout + +\end_inset + +: \end_layout \begin_layout Standard @@ -7532,7 +7552,27 @@ literal "true" \end_layout \begin_layout Standard -index "new": +index +\begin_inset ERT +status collapsed + +\begin_layout Plain Layout +" +\end_layout + +\end_inset + +new +\begin_inset ERT +status collapsed + +\begin_layout Plain Layout +" +\end_layout + +\end_inset + +: \end_layout \begin_layout Standard @@ -7548,7 +7588,27 @@ literal "true" \end_layout \begin_layout Standard -subindex "new": +subindex +\begin_inset ERT +status collapsed + +\begin_layout Plain Layout +" +\end_layout + +\end_inset + +new +\begin_inset ERT +status collapsed + +\begin_layout Plain Layout +" +\end_layout + +\end_inset + +: \end_layout \begin_layout Standard diff --git a/src/tex2lyx/test/test-structure.lyx.lyx b/src/tex2lyx/test/test-structure.lyx.lyx index b1cb6808a8..76f9c89d2a 100644 --- a/src/tex2lyx/test/test-structure.lyx.lyx +++ b/src/tex2lyx/test/test-structure.lyx.lyx @@ -604,7 +604,6 @@ klöä \end_layout - \end_inset @@ -651,7 +650,6 @@ te%st \end_layout - \end_inset @@ -686,7 +684,6 @@ subfigure 2ö \end_layout - \end_inset From bbaf2b6a29fb507e9174ee66919cf2ac40aa8a02 Mon Sep 17 00:00:00 2001 From: Juergen Spitzmueller Date: Sun, 11 Mar 2018 19:49:28 +0100 Subject: [PATCH 085/121] amend 11e4a24e6edbd1f (cherry picked from commit 386d9953e83a35dcc3b0f173faa92d9e9fc16f0f) --- src/tex2lyx/Preamble.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/tex2lyx/Preamble.cpp b/src/tex2lyx/Preamble.cpp index e0a5de32d6..1b9d5096f4 100644 --- a/src/tex2lyx/Preamble.cpp +++ b/src/tex2lyx/Preamble.cpp @@ -1585,12 +1585,13 @@ void Preamble::parse(Parser & p, string const & forceclass, continue; } - else if (t.cs() == "date") { + if (t.cs() == "date") { string argument = p.getArg('{', '}'); if (argument.empty()) h_suppress_date = "true"; else h_preamble << t.asInput() << '{' << argument << '}'; + continue; } if (t.cs() == "color") { From fff6d35cffcc414ca510714ec739e5fff56367c6 Mon Sep 17 00:00:00 2001 From: Juergen Spitzmueller Date: Sun, 11 Mar 2018 19:56:04 +0100 Subject: [PATCH 086/121] update tex2lyx tests once more. --- src/tex2lyx/test/CJK.lyx.lyx | 22 ++++++- src/tex2lyx/test/test-insets-basic.lyx.lyx | 72 ++++++++++---------- src/tex2lyx/test/test-insets.lyx.lyx | 76 +++++++++++----------- src/tex2lyx/test/test-structure.lyx.lyx | 4 +- 4 files changed, 97 insertions(+), 77 deletions(-) diff --git a/src/tex2lyx/test/CJK.lyx.lyx b/src/tex2lyx/test/CJK.lyx.lyx index 59d3729c3a..c31cba4459 100644 --- a/src/tex2lyx/test/CJK.lyx.lyx +++ b/src/tex2lyx/test/CJK.lyx.lyx @@ -143,7 +143,27 @@ status collapsed \end_inset -texttt{hei} mapping, +texttt +\begin_inset ERT +status collapsed + +\begin_layout Plain Layout +{ +\end_layout + +\end_inset + +hei +\begin_inset ERT +status collapsed + +\begin_layout Plain Layout +} +\end_layout + +\end_inset + + mapping, and the first mapping is empty. \begin_inset ERT status collapsed diff --git a/src/tex2lyx/test/test-insets-basic.lyx.lyx b/src/tex2lyx/test/test-insets-basic.lyx.lyx index 4d7a58ac0b..3c2698d6d2 100644 --- a/src/tex2lyx/test/test-insets-basic.lyx.lyx +++ b/src/tex2lyx/test/test-insets-basic.lyx.lyx @@ -375,7 +375,7 @@ LatexCommand citep after "after" before "" key "article-crossref" -literal "true" +literal "false" \end_inset @@ -387,7 +387,7 @@ LatexCommand citep after "after" before "" key "whole-set,article-crossref" -literal "true" +literal "false" \end_inset @@ -407,7 +407,7 @@ LatexCommand citet after "after" before "before" key "article-crossref" -literal "true" +literal "false" \end_inset @@ -419,7 +419,7 @@ LatexCommand citet* after "after" before "before" key "article-crossref" -literal "true" +literal "false" \end_inset @@ -431,7 +431,7 @@ LatexCommand Citet after "after" before "before" key "article-crossref" -literal "true" +literal "false" \end_inset @@ -443,7 +443,7 @@ LatexCommand Citet* after "after" before "before" key "article-crossref" -literal "true" +literal "false" \end_inset @@ -459,7 +459,7 @@ LatexCommand citep after "after" before "before" key "article-crossref" -literal "true" +literal "false" \end_inset @@ -471,7 +471,7 @@ LatexCommand citep* after "after" before "before" key "article-crossref" -literal "true" +literal "false" \end_inset @@ -483,7 +483,7 @@ LatexCommand Citep after "after" before "before" key "article-crossref" -literal "true" +literal "false" \end_inset @@ -495,7 +495,7 @@ LatexCommand Citep* after "after" before "before" key "article-crossref" -literal "true" +literal "false" \end_inset @@ -511,7 +511,7 @@ LatexCommand citealt after "after" before "before" key "article-crossref" -literal "true" +literal "false" \end_inset @@ -523,7 +523,7 @@ LatexCommand citealt* after "after" before "before" key "article-crossref" -literal "true" +literal "false" \end_inset @@ -535,7 +535,7 @@ LatexCommand Citealt after "after" before "before" key "article-crossref" -literal "true" +literal "false" \end_inset @@ -547,7 +547,7 @@ LatexCommand Citealt* after "after" before "before" key "article-crossref" -literal "true" +literal "false" \end_inset @@ -563,7 +563,7 @@ LatexCommand citealp after "after" before "before" key "article-crossref" -literal "true" +literal "false" \end_inset @@ -575,7 +575,7 @@ LatexCommand citealp* after "after" before "before" key "article-crossref" -literal "true" +literal "false" \end_inset @@ -587,7 +587,7 @@ LatexCommand Citep after "after" before "before" key "article-crossref" -literal "true" +literal "false" \end_inset @@ -599,7 +599,7 @@ LatexCommand Citealp* after "after" before "before" key "article-crossref" -literal "true" +literal "false" \end_inset @@ -615,7 +615,7 @@ LatexCommand citeauthor after "after" before "before" key "article-crossref" -literal "true" +literal "false" \end_inset @@ -627,7 +627,7 @@ LatexCommand citeauthor* after "after" before "before" key "article-crossref" -literal "true" +literal "false" \end_inset @@ -639,7 +639,7 @@ LatexCommand Citeauthor after "after" before "before" key "article-crossref" -literal "true" +literal "false" \end_inset @@ -651,7 +651,7 @@ LatexCommand Citeauthor* after "after" before "before" key "article-crossref" -literal "true" +literal "false" \end_inset @@ -667,7 +667,7 @@ LatexCommand citeyear after "after" before "before" key "article-crossref" -literal "true" +literal "false" \end_inset @@ -683,7 +683,7 @@ LatexCommand citeyearpar after "after" before "before" key "article-crossref" -literal "true" +literal "false" \end_inset @@ -698,7 +698,7 @@ nocite: LatexCommand nocite after "" key "article-crossref" -literal "true" +literal "false" \end_inset @@ -775,7 +775,7 @@ LatexCommand citet after "" before "" key "gur+04" -literal "true" +literal "false" \end_inset @@ -788,7 +788,7 @@ literal "true" LatexCommand bibitem label "Möstl et~al.(2010)" key "Mostl2010" -literal "true" +literal "false" \end_inset @@ -811,7 +811,7 @@ A. 2004, ApJ, 604, 632 LatexCommand bibitem label "{{Gürkan et~al.}(2004)}" key "gur+04" -literal "true" +literal "false" \end_inset @@ -954,7 +954,7 @@ LatexCommand nomenclature prefix "www" symbol "URL" description "uniform resource locator" -literal "true" +literal "false" \end_inset @@ -977,7 +977,7 @@ http://www.lyx.org LatexCommand nomenclature symbol "URL2" description "uniform resource locator" -literal "true" +literal "false" \end_inset @@ -1003,7 +1003,7 @@ link: \begin_inset CommandInset href LatexCommand href target "www.test.test" -literal "true" +literal "false" \end_inset @@ -1015,7 +1015,7 @@ link2: \begin_inset CommandInset href LatexCommand href target "http://www.test.test" -literal "true" +literal "false" \end_inset @@ -1029,7 +1029,7 @@ LatexCommand href name "name" target "www.test.test" type "mailto:" -literal "true" +literal "false" \end_inset @@ -1042,7 +1042,7 @@ file: LatexCommand href target "www.test.test" type "file:" -literal "true" +literal "false" \end_inset @@ -1054,7 +1054,7 @@ ftp: \begin_inset CommandInset href LatexCommand href target "ftp://www.test.test" -literal "true" +literal "false" \end_inset @@ -1067,7 +1067,7 @@ ftp2: LatexCommand href name "www.test.test" target "ftp://www.test.test" -literal "true" +literal "false" \end_inset diff --git a/src/tex2lyx/test/test-insets.lyx.lyx b/src/tex2lyx/test/test-insets.lyx.lyx index 60f7d40491..7997f9231f 100644 --- a/src/tex2lyx/test/test-insets.lyx.lyx +++ b/src/tex2lyx/test/test-insets.lyx.lyx @@ -355,7 +355,7 @@ LatexCommand citep after "after" before "" key "article-crossref" -literal "true" +literal "false" \end_inset @@ -367,7 +367,7 @@ LatexCommand citep after "after" before "" key "whole-set,article-crossref" -literal "true" +literal "false" \end_inset @@ -387,7 +387,7 @@ LatexCommand citet after "after" before "before" key "article-crossref" -literal "true" +literal "false" \end_inset @@ -399,7 +399,7 @@ LatexCommand citet* after "after" before "before" key "article-crossref" -literal "true" +literal "false" \end_inset @@ -411,7 +411,7 @@ LatexCommand Citet after "after" before "before" key "article-crossref" -literal "true" +literal "false" \end_inset @@ -423,7 +423,7 @@ LatexCommand Citet* after "after" before "before" key "article-crossref" -literal "true" +literal "false" \end_inset @@ -439,7 +439,7 @@ LatexCommand citep after "after" before "before" key "article-crossref" -literal "true" +literal "false" \end_inset @@ -451,7 +451,7 @@ LatexCommand citep* after "after" before "before" key "article-crossref" -literal "true" +literal "false" \end_inset @@ -463,7 +463,7 @@ LatexCommand Citep after "after" before "before" key "article-crossref" -literal "true" +literal "false" \end_inset @@ -475,7 +475,7 @@ LatexCommand Citep* after "after" before "before" key "article-crossref" -literal "true" +literal "false" \end_inset @@ -491,7 +491,7 @@ LatexCommand citealt after "after" before "before" key "article-crossref" -literal "true" +literal "false" \end_inset @@ -503,7 +503,7 @@ LatexCommand citealt* after "after" before "before" key "article-crossref" -literal "true" +literal "false" \end_inset @@ -515,7 +515,7 @@ LatexCommand Citealt after "after" before "before" key "article-crossref" -literal "true" +literal "false" \end_inset @@ -527,7 +527,7 @@ LatexCommand Citealt* after "after" before "before" key "article-crossref" -literal "true" +literal "false" \end_inset @@ -543,7 +543,7 @@ LatexCommand citealp after "after" before "before" key "article-crossref" -literal "true" +literal "false" \end_inset @@ -555,7 +555,7 @@ LatexCommand citealp* after "after" before "before" key "article-crossref" -literal "true" +literal "false" \end_inset @@ -567,7 +567,7 @@ LatexCommand Citep after "after" before "before" key "article-crossref" -literal "true" +literal "false" \end_inset @@ -579,7 +579,7 @@ LatexCommand Citealp* after "after" before "before" key "article-crossref" -literal "true" +literal "false" \end_inset @@ -595,7 +595,7 @@ LatexCommand citeauthor after "after" before "before" key "article-crossref" -literal "true" +literal "false" \end_inset @@ -607,7 +607,7 @@ LatexCommand citeauthor* after "after" before "before" key "article-crossref" -literal "true" +literal "false" \end_inset @@ -619,7 +619,7 @@ LatexCommand Citeauthor after "after" before "before" key "article-crossref" -literal "true" +literal "false" \end_inset @@ -631,7 +631,7 @@ LatexCommand Citeauthor* after "after" before "before" key "article-crossref" -literal "true" +literal "false" \end_inset @@ -647,7 +647,7 @@ LatexCommand citeyear after "after" before "before" key "article-crossref" -literal "true" +literal "false" \end_inset @@ -663,7 +663,7 @@ LatexCommand citeyearpar after "after" before "before" key "article-crossref" -literal "true" +literal "false" \end_inset @@ -678,7 +678,7 @@ nocite: LatexCommand nocite after "" key "article-crossref" -literal "true" +literal "false" \end_inset @@ -755,7 +755,7 @@ LatexCommand citet after "" before "" key "gur+04" -literal "true" +literal "false" \end_inset @@ -768,7 +768,7 @@ literal "true" LatexCommand bibitem label "Möstl et~al.(2010)" key "Mostl2010" -literal "true" +literal "false" \end_inset @@ -791,7 +791,7 @@ A. 2004, ApJ, 604, 632 LatexCommand bibitem label "{{Gürkan et~al.}(2004)}" key "gur+04" -literal "true" +literal "false" \end_inset @@ -987,7 +987,7 @@ LatexCommand nomenclature prefix "www" symbol "URL" description "uniform resource locator" -literal "true" +literal "false" \end_inset @@ -1010,7 +1010,7 @@ http://www.lyx.org LatexCommand nomenclature symbol "URL2" description "uniform resource locator" -literal "true" +literal "false" \end_inset @@ -1036,7 +1036,7 @@ link: \begin_inset CommandInset href LatexCommand href target "www.test.test" -literal "true" +literal "false" \end_inset @@ -1048,7 +1048,7 @@ link2: \begin_inset CommandInset href LatexCommand href target "http://www.test.test" -literal "true" +literal "false" \end_inset @@ -1062,7 +1062,7 @@ LatexCommand href name "name" target "www.test.test" type "mailto:" -literal "true" +literal "false" \end_inset @@ -1075,7 +1075,7 @@ file: LatexCommand href target "www.test.test" type "file:" -literal "true" +literal "false" \end_inset @@ -1087,7 +1087,7 @@ ftp: \begin_inset CommandInset href LatexCommand href target "ftp://www.test.test" -literal "true" +literal "false" \end_inset @@ -1100,7 +1100,7 @@ ftp2: LatexCommand href name "www.test.test" target "ftp://www.test.test" -literal "true" +literal "false" \end_inset @@ -1113,7 +1113,7 @@ parser test (stupid, but valid): LatexCommand href name "}" target "http://www.test.test" -literal "true" +literal "false" \end_inset @@ -1126,7 +1126,7 @@ parser test (escaped): LatexCommand href name "a brace } and another one { and something" target "http://www.test.test" -literal "true" +literal "false" \end_inset diff --git a/src/tex2lyx/test/test-structure.lyx.lyx b/src/tex2lyx/test/test-structure.lyx.lyx index 76f9c89d2a..52f4e11882 100644 --- a/src/tex2lyx/test/test-structure.lyx.lyx +++ b/src/tex2lyx/test/test-structure.lyx.lyx @@ -1100,7 +1100,7 @@ and bibliography: LatexCommand bibitem label "" key "FOO" -literal "true" +literal "false" \end_inset @@ -1117,7 +1117,7 @@ The Foo Book LatexCommand bibitem label "" key "FO2" -literal "true" +literal "false" \end_inset From 59449063dfba5f29fe46b8f497ce5d5dffc9b99a Mon Sep 17 00:00:00 2001 From: Juergen Spitzmueller Date: Sun, 11 Mar 2018 11:46:37 +0100 Subject: [PATCH 087/121] tex2lyx: support tipa \t*{} macro. (cherry picked from commit cc6f2dae8219b40cd8602f70110926296403a0f7) --- src/tex2lyx/TODO.txt | 1 - src/tex2lyx/text.cpp | 9 +++++++-- status.23x | 2 ++ 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/tex2lyx/TODO.txt b/src/tex2lyx/TODO.txt index 767bccf867..b2ba6bb395 100644 --- a/src/tex2lyx/TODO.txt +++ b/src/tex2lyx/TODO.txt @@ -50,7 +50,6 @@ Format LaTeX feature LyX feature 407 vertical offset for multirows InsetTabular 411 support for polyglossia \language_package (the cases of no package, of babel and of custom package is supported) 415 automatic undertilde loading \use_package undertilde -438 \t*{ } InsetTIPA 443 unicode-math.sty InsetMath* 448 451 beamer overlay arguments InsetArgument diff --git a/src/tex2lyx/text.cpp b/src/tex2lyx/text.cpp index 4f7f5a73d7..b67f4a78b7 100644 --- a/src/tex2lyx/text.cpp +++ b/src/tex2lyx/text.cpp @@ -3681,9 +3681,14 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, continue; } - if (t.cs() == "texttoptiebar" || t.cs() == "textbottomtiebar") { + if ((preamble.isPackageUsed("tipa") && t.cs() == "t" && p.next_token().asInput() == "*") + || t.cs() == "texttoptiebar" || t.cs() == "textbottomtiebar") { context.check_layout(os); - begin_inset(os, "IPADeco " + t.cs().substr(4) + "\n"); + if (t.cs() == "t") + // swallow star + p.get_token(); + string const type = (t.cs() == "t") ? "bottomtiebar" : t.cs().substr(4); + begin_inset(os, "IPADeco " + type + "\n"); os << "status open\n"; parse_text_in_inset(p, os, FLAG_ITEM, outer, context); end_inset(os); diff --git a/status.23x b/status.23x index 2cd3d67222..4f909307ae 100644 --- a/status.23x +++ b/status.23x @@ -29,6 +29,8 @@ What's new - Add support for URW Classico, MinionPro and the new Libertine fonts. +- Add support for the \t*{} (bottomtiebar) macro of TIPA. + - Implement better parsing of some command options (via "literate" function of some insets) (bug 9563). From d263ca052948061bd3e38377197052805075cabb Mon Sep 17 00:00:00 2001 From: Juergen Spitzmueller Date: Sun, 11 Mar 2018 18:04:23 +0100 Subject: [PATCH 088/121] tex2lyx: update quote handling * Consider new quote styles * Consider changed quote styles * Try to be a bit smarter with ambiguous quotation marks (cherry picked from commit 8184f08f4af6efea6d1499e3f8c8d3c20ebb1b97) --- src/tex2lyx/Preamble.cpp | 108 +++++++++++------- src/tex2lyx/Preamble.h | 2 + src/tex2lyx/TODO.txt | 17 --- src/tex2lyx/test/CJK.lyx.lyx | 2 +- src/tex2lyx/test/CJKutf8.lyx.lyx | 2 +- src/tex2lyx/test/XeTeX-polyglossia.lyx.lyx | 2 +- src/tex2lyx/text.cpp | 124 ++++++++++++++++----- status.23x | 6 + 8 files changed, 178 insertions(+), 85 deletions(-) diff --git a/src/tex2lyx/Preamble.cpp b/src/tex2lyx/Preamble.cpp index 1b9d5096f4..26824ddcd2 100644 --- a/src/tex2lyx/Preamble.cpp +++ b/src/tex2lyx/Preamble.cpp @@ -88,35 +88,51 @@ const char * const known_coded_languages[] = {"french", "afrikaans", "albanian", "vietnamese", "welsh", 0}; +/// languages with british quotes (.lyx names) +const char * const known_british_quotes_languages[] = {"british", "welsh", 0}; + +/// languages with cjk quotes (.lyx names) +const char * const known_cjk_quotes_languages[] = {"chinese-traditional", +"japanese", "japanese-cjk", 0}; + +/// languages with cjk-angle quotes (.lyx names) +const char * const known_cjkangle_quotes_languages[] = {"korean", 0}; + /// languages with danish quotes (.lyx names) const char * const known_danish_quotes_languages[] = {"danish", 0}; /// languages with english quotes (.lyx names) const char * const known_english_quotes_languages[] = {"american", "australian", "bahasa", "bahasam", "brazilian", "canadian", "chinese-simplified", "english", -"esperanto", "hebrew", "irish", "korean", "newzealand", "portuguese", "scottish", -"thai", 0}; +"esperanto", "farsi", "interlingua", "irish", "newzealand", "scottish", +"thai", "turkish", "vietnamese", 0}; /// languages with french quotes (.lyx names) -const char * const known_french_quotes_languages[] = {"albanian", -"arabic_arabi", "arabic_arabtex", "asturian", "basque", "canadien", "catalan", -"french", "friulan", "galician", "greek", "italian", "norsk", "nynorsk", -"piedmontese", "polutonikogreek", "russian", "spanish", "spanish-mexico", -"turkish", "turkmen", "ukrainian", "vietnamese", 0}; +const char * const known_french_quotes_languages[] = {"ancientgreek", +"arabic_arabi", "arabic_arabtex", "asturian", "belarusian", "breton", +"canadien", "catalan", "french", "friulan", "galician", "italian", "occitan", +"piedmontese", "portuguese", "spanish", "spanish-mexico", 0}; /// languages with german quotes (.lyx names) const char * const known_german_quotes_languages[] = {"austrian", "bulgarian", -"czech", "german", "georgian", "icelandic", "lithuanian", "lowersorbian", "macedonian", -"naustrian", "ngerman", "romansh", "serbian", "serbian-latin", "slovak", "slovene", +"czech", "estonian", "georgian", "german", "icelandic", "latvian", "lithuanian", +"lowersorbian", "macedonian", "naustrian", "ngerman", "romansh", "slovak", "slovene", "uppersorbian", 0}; /// languages with polish quotes (.lyx names) const char * const known_polish_quotes_languages[] = {"afrikaans", "bosnian", "croatian", -"dutch", "estonian", "magyar", "polish", "romanian", 0}; +"dutch", "magyar", "polish", "romanian", "serbian", "serbian-latin", 0}; + +/// languages with russian quotes (.lyx names) +const char * const known_russian_quotes_languages[] = {"russian", "ukrainian", 0}; /// languages with swedish quotes (.lyx names) -const char * const known_swedish_quotes_languages[] = {"finnish", -"swedish", 0}; +const char * const known_swedish_quotes_languages[] = {"finnish", "swedish", 0}; + +/// languages with swiss quotes (.lyx names) +const char * const known_swiss_quotes_languages[] = {"albanian", +"armenian", "basque", "german-ch", "german-ch-old", +"norsk", "nynorsk", "turkmen", "ukrainian", "vietnamese", 0}; /// known language packages from the times before babel const char * const known_old_language_packages[] = {"french", "frenchle", @@ -1188,33 +1204,6 @@ void Preamble::handle_if(Parser & p, bool in_lyx_preamble) bool Preamble::writeLyXHeader(ostream & os, bool subdoc, string const & outfiledir) { - // set the quote language - // LyX only knows the following quotes languages: - // english, swedish, german, polish, french and danish - // (quotes for "japanese" and "chinese-traditional" are missing because - // they wouldn't be useful: https://www.lyx.org/trac/ticket/6383) - // conversion list taken from - // https://en.wikipedia.org/wiki/Quotation_mark,_non-English_usage - // (quotes for kazakh and interlingua are unknown) - // danish - if (is_known(h_language, known_danish_quotes_languages)) - h_quotes_style = "danish"; - // french - else if (is_known(h_language, known_french_quotes_languages)) - h_quotes_style = "french"; - // german - else if (is_known(h_language, known_german_quotes_languages)) - h_quotes_style = "german"; - // polish - else if (is_known(h_language, known_polish_quotes_languages)) - h_quotes_style = "polish"; - // swedish - else if (is_known(h_language, known_swedish_quotes_languages)) - h_quotes_style = "swedish"; - //english - else if (is_known(h_language, known_english_quotes_languages)) - h_quotes_style = "english"; - if (contains(h_float_placement, "H")) registerAutomaticallyLoadedPackage("float"); if (h_spacing != "single" && h_spacing != "default") @@ -2239,6 +2228,47 @@ void Preamble::parse(Parser & p, string const & forceclass, h_options += ',' + lyx2babel(default_language); } } + + // Finally, set the quote style. + // LyX knows the following quotes styles: + // british, cjk, cjkangle, danish, english, french, german, + // polish, russian, swedish and swiss + // conversion list taken from + // https://en.wikipedia.org/wiki/Quotation_mark,_non-English_usage + // (quotes for kazakh are unknown) + // british + if (is_known(h_language, known_british_quotes_languages)) + h_quotes_style = "british"; + // cjk + else if (is_known(h_language, known_cjk_quotes_languages)) + h_quotes_style = "cjk"; + // cjkangle + else if (is_known(h_language, known_cjkangle_quotes_languages)) + h_quotes_style = "cjkangle"; + // danish + else if (is_known(h_language, known_danish_quotes_languages)) + h_quotes_style = "danish"; + // french + else if (is_known(h_language, known_french_quotes_languages)) + h_quotes_style = "french"; + // german + else if (is_known(h_language, known_german_quotes_languages)) + h_quotes_style = "german"; + // polish + else if (is_known(h_language, known_polish_quotes_languages)) + h_quotes_style = "polish"; + // russian + else if (is_known(h_language, known_russian_quotes_languages)) + h_quotes_style = "russian"; + // swedish + else if (is_known(h_language, known_swedish_quotes_languages)) + h_quotes_style = "swedish"; + // swiss + else if (is_known(h_language, known_swiss_quotes_languages)) + h_quotes_style = "swiss"; + // english + else if (is_known(h_language, known_english_quotes_languages)) + h_quotes_style = "english"; } diff --git a/src/tex2lyx/Preamble.h b/src/tex2lyx/Preamble.h index 9c70dca62a..0d3ff0113f 100644 --- a/src/tex2lyx/Preamble.h +++ b/src/tex2lyx/Preamble.h @@ -54,6 +54,8 @@ public: std::string docLanguage() const { return h_language; } /// The language of text which is not explicitly marked std::string defaultLanguage() const { return default_language; } + /// The quotation marks style + std::string quotesStyle() const { return h_quotes_style; } /// bool usePolyglossia() const; /// diff --git a/src/tex2lyx/TODO.txt b/src/tex2lyx/TODO.txt index b2ba6bb395..9588691285 100644 --- a/src/tex2lyx/TODO.txt +++ b/src/tex2lyx/TODO.txt @@ -75,23 +75,6 @@ Format LaTeX feature LyX feature \twocolumn[]{}{} Layout Twocolumn, InsetArgument \item[]<> InsetArgument \begin{enumerate|itemize|...}[] InsetArgument -520 Plain InsetQuote Style: - \textquotesingle \begin_inset Quotes qls, \begin_inset Quotes qrs - \textquotedbl \begin_inset Quotes qld, \begin_inset Quotes qrd -521 New Quote Styles InsetQuote - - british \begin_inset Quotes b.. - - swiss \begin_inset Quotes c.. - - swedishg \begin_inset Quotes w.. - - frenchin \begin_inset Quotes i.. - - russian \begin_inset Quotes r.. - Change default behavior \begin_inset Quotes f.. - of French quote style: - - Inner quotes are now ``...''. - - Former french style is now - called "swiss" -523 CJK Quote Styles InsetQuote - - cjk (corner brackets) \begin_inset Quotes j.. - - cjkangle (angle brackets) \begin_inset Quotes k.. 526 Plural and capitalized refstyles InsetRef 533 Multibib support \begin{btUnit}...\end{btUnit} \multibib {none|part|chapter|section|subsection} diff --git a/src/tex2lyx/test/CJK.lyx.lyx b/src/tex2lyx/test/CJK.lyx.lyx index c31cba4459..2ec5f9c0a5 100644 --- a/src/tex2lyx/test/CJK.lyx.lyx +++ b/src/tex2lyx/test/CJK.lyx.lyx @@ -74,7 +74,7 @@ \paragraph_indentation default \is_math_indent 0 \math_numbering_side default -\quotes_style english +\quotes_style cjk \dynamic_quotes 0 \papercolumns 1 \papersides 1 diff --git a/src/tex2lyx/test/CJKutf8.lyx.lyx b/src/tex2lyx/test/CJKutf8.lyx.lyx index 7eeec41b14..a3a6856e47 100644 --- a/src/tex2lyx/test/CJKutf8.lyx.lyx +++ b/src/tex2lyx/test/CJKutf8.lyx.lyx @@ -74,7 +74,7 @@ \paragraph_indentation default \is_math_indent 0 \math_numbering_side default -\quotes_style english +\quotes_style cjk \dynamic_quotes 0 \papercolumns 1 \papersides 1 diff --git a/src/tex2lyx/test/XeTeX-polyglossia.lyx.lyx b/src/tex2lyx/test/XeTeX-polyglossia.lyx.lyx index fac9a9573a..6938846714 100644 --- a/src/tex2lyx/test/XeTeX-polyglossia.lyx.lyx +++ b/src/tex2lyx/test/XeTeX-polyglossia.lyx.lyx @@ -73,7 +73,7 @@ \paragraph_indentation default \is_math_indent 0 \math_numbering_side default -\quotes_style english +\quotes_style british \dynamic_quotes 0 \papercolumns 1 \papersides 1 diff --git a/src/tex2lyx/text.cpp b/src/tex2lyx/text.cpp index b67f4a78b7..b81b866005 100644 --- a/src/tex2lyx/text.cpp +++ b/src/tex2lyx/text.cpp @@ -201,13 +201,14 @@ bool need_commentbib = false; char const * const known_quotes[] = { "dq", "guillemotleft", "flqq", "og", "guillemotright", "frqq", "fg", "glq", "glqq", "textquoteleft", "grq", "grqq", "quotedblbase", "textquotedblleft", "quotesinglbase", "textquoteright", "flq", -"guilsinglleft", "frq", "guilsinglright", 0}; +"guilsinglleft", "frq", "guilsinglright", "textquotedblright", "textquotesingle", +"textquotedbl", 0}; /// the same as known_quotes with .lyx names -char const * const known_coded_quotes[] = { "prd", "ard", "ard", "ard", -"ald", "ald", "ald", "gls", "gld", "els", "els", "grd", -"gld", "grd", "gls", "ers", "fls", -"fls", "frs", "frs", 0}; +char const * const known_coded_quotes[] = { "qrd", "ard", "ard", "ard", +"ald", "ald", "ald", "gls", "gld", "els", "els", "eld", +"gld", "eld", "gls", "ers", "ars", +"ars", "als", "als", "erd", "qrs", "qrd", 0}; /// LaTeX names for font sizes char const * const known_sizes[] = { "tiny", "scriptsize", "footnotesize", @@ -446,6 +447,78 @@ bool translate_len(string const & length, string & valstring, string & unit) return true; } + +/// If we have ambiguous quotation marks, make a smart guess +/// based on main quote style +string guessQuoteStyle(string in, bool const opening) +{ + string res = in; + if (prefixIs(in, "qr")) {// straight quote + if (!opening) + res = subst(res, "r", "l"); + } else if (in == "eld") {// `` + if (preamble.quotesStyle() == "german") + res = "grd"; + else if (preamble.quotesStyle() == "british") + res = "bls"; + else if (preamble.quotesStyle() == "french") + res = "fls"; + else if (preamble.quotesStyle() == "russian") + res = "rrs"; + } else if (in == "erd") {// '' + if (preamble.quotesStyle() == "polish") + res = "prd"; + else if (preamble.quotesStyle() == "british") + res = "brs"; + else if (preamble.quotesStyle() == "french") + res = "frs"; + else if (preamble.quotesStyle() == "swedish") + res = opening ? "sld" : "srd"; + } else if (in == "els") {// ` + if (preamble.quotesStyle() == "german") + res = "grs"; + else if (preamble.quotesStyle() == "british") + res = "bld"; + } else if (in == "ers") {// ' + if (preamble.quotesStyle() == "polish") + res = "prs"; + else if (preamble.quotesStyle() == "british") + res = "brd"; + else if (preamble.quotesStyle() == "swedish") + res = opening ? "sls" : "srs"; + } else if (in == "ard") {// >> + if (preamble.quotesStyle() == "swiss") + res = "cld"; + else if (preamble.quotesStyle() == "french") + res = "fld"; + else if (preamble.quotesStyle() == "russian") + res = "rld"; + } else if (in == "ald") {// << + if (preamble.quotesStyle() == "swiss") + res = "crd"; + else if (preamble.quotesStyle() == "french") + res = "frd"; + else if (preamble.quotesStyle() == "russian") + res = "rrd"; + } else if (in == "ars") {// > + if (preamble.quotesStyle() == "swiss") + res = "cls"; + } else if (in == "als") {// < + if (preamble.quotesStyle() == "swiss") + res = "crs"; + } else if (in == "gld") {// ,, + if (preamble.quotesStyle() == "polish") + res = "pld"; + else if (preamble.quotesStyle() == "russian") + res = "rls"; + } else if (in == "gls") {// , + if (preamble.quotesStyle() == "polish") + res = "pls"; + } + return res; +} + + } // namespace @@ -2628,14 +2701,17 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, continue; } - // Basic support for english quotes. This should be - // extended to other quotes, but is not so easy (a - // left english quote is the same as a right german - // quote...) + // Basic support for quotes. We try to disambiguate + // quotes from the context (e.g., a left english quote is + // the same as a right german quote...). + // Try to make a smart guess about the side + Token const prev = p.prev_token(); + bool const opening = (prev.cat() != catSpace && prev.character() != 0 + && prev.character() != '\n' && prev.character() != '~'); if (t.asInput() == "`" && p.next_token().asInput() == "`") { context.check_layout(os); begin_inset(os, "Quotes "); - os << "eld"; + os << guessQuoteStyle("eld", opening); end_inset(os); p.get_token(); skip_braces(p); @@ -2644,7 +2720,7 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, if (t.asInput() == "'" && p.next_token().asInput() == "'") { context.check_layout(os); begin_inset(os, "Quotes "); - os << "erd"; + os << guessQuoteStyle("erd", opening); end_inset(os); p.get_token(); skip_braces(p); @@ -2654,7 +2730,7 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, if (t.asInput() == ">" && p.next_token().asInput() == ">") { context.check_layout(os); begin_inset(os, "Quotes "); - os << "ald"; + os << guessQuoteStyle("ald", opening); end_inset(os); p.get_token(); skip_braces(p); @@ -2675,9 +2751,7 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, if (!has_chunk) { context.check_layout(os); begin_inset(os, "Quotes "); - //FIXME: this is a right danish quote; - // why not a left french quote? - os << "ard"; + os << guessQuoteStyle("ard", opening); end_inset(os); p.get_token(); skip_braces(p); @@ -2803,8 +2877,7 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, is_known(next.cs(), known_quotes) && end.cat() == catEnd) { // Something like {\textquoteright} (e.g. - // from writer2latex). LyX writes - // \textquoteright{}, so we may skip the + // from writer2latex). We may skip the // braces here for better readability. parse_text_snippet(p, os, FLAG_BRACE_LAST, outer, context); @@ -4356,7 +4429,13 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, if ((where = is_known(t.cs(), known_quotes))) { context.check_layout(os); begin_inset(os, "Quotes "); - os << known_coded_quotes[where - known_quotes]; + string quotetype = known_coded_quotes[where - known_quotes]; + // try to make a smart guess about the side + Token const prev = p.prev_token(); + bool const opening = (prev.cat() != catSpace && prev.character() != 0 + && prev.character() != '\n' && prev.character() != '~'); + quotetype = guessQuoteStyle(quotetype, opening); + os << quotetype; end_inset(os); // LyX adds {} after the quote, so we have to eat // spaces here if there are any before a possible @@ -4367,7 +4446,7 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, } if ((where = is_known(t.cs(), known_sizes)) && - context.new_layout_allowed) { + context.new_layout_allowed) { context.check_layout(os); TeXFont const oldFont = context.font; context.font.size = known_coded_sizes[where - known_sizes]; @@ -4532,13 +4611,6 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, continue; } - if (t.cs() == "textquotedbl") { - context.check_layout(os); - os << "\""; - skip_braces(p); - continue; - } - if (t.cs() == "_" || t.cs() == "&" || t.cs() == "#" || t.cs() == "$" || t.cs() == "{" || t.cs() == "}" || t.cs() == "%" || t.cs() == "-") { diff --git a/status.23x b/status.23x index 4f909307ae..14989d5592 100644 --- a/status.23x +++ b/status.23x @@ -27,6 +27,12 @@ What's new - Add support for \includeonly. +- Update tex2lyx quotation marks detection: + * Consider new quote styles of LyX 2.3. + * Consider changed quote styles in LYX 2.3. + * Try to be a bit smarter with ambiguous quotation marks, + depending on the main quote style and the local context. + - Add support for URW Classico, MinionPro and the new Libertine fonts. - Add support for the \t*{} (bottomtiebar) macro of TIPA. From cedb4838f0f555eb9f288dd9d8484450d3ac8b1e Mon Sep 17 00:00:00 2001 From: Juergen Spitzmueller Date: Mon, 12 Mar 2018 09:35:39 +0100 Subject: [PATCH 089/121] update tex2lyx tests --- src/tex2lyx/test/test-insets-basic.lyx.lyx | 18 ++++-------------- src/tex2lyx/test/test-insets.lyx.lyx | 18 ++++-------------- 2 files changed, 8 insertions(+), 28 deletions(-) diff --git a/src/tex2lyx/test/test-insets-basic.lyx.lyx b/src/tex2lyx/test/test-insets-basic.lyx.lyx index 3c2698d6d2..06999a6274 100644 --- a/src/tex2lyx/test/test-insets-basic.lyx.lyx +++ b/src/tex2lyx/test/test-insets-basic.lyx.lyx @@ -6469,22 +6469,12 @@ tz \begin_inset IPA \begin_layout Standard -:;eˈˌ|‖.͡* -\begin_inset ERT -status collapsed - -\begin_layout Plain Layout -{ -\end_layout - -\end_inset +:;eˈˌ|‖. +\begin_inset IPADeco bottomtiebar +status open +\begin_layout Standard -\begin_inset ERT -status collapsed - -\begin_layout Plain Layout -} \end_layout \end_inset diff --git a/src/tex2lyx/test/test-insets.lyx.lyx b/src/tex2lyx/test/test-insets.lyx.lyx index 7997f9231f..b8015cabf7 100644 --- a/src/tex2lyx/test/test-insets.lyx.lyx +++ b/src/tex2lyx/test/test-insets.lyx.lyx @@ -6914,22 +6914,12 @@ tz \begin_inset IPA \begin_layout Standard -:;eˈˌ|‖.͡* -\begin_inset ERT -status collapsed - -\begin_layout Plain Layout -{ -\end_layout - -\end_inset +:;eˈˌ|‖. +\begin_inset IPADeco bottomtiebar +status open +\begin_layout Standard -\begin_inset ERT -status collapsed - -\begin_layout Plain Layout -} \end_layout \end_inset From f01369a56f969ff800e9a65e44552aebccdbfa50 Mon Sep 17 00:00:00 2001 From: Juergen Spitzmueller Date: Tue, 13 Mar 2018 17:39:40 +0100 Subject: [PATCH 090/121] Fix known_escaped_chars (this includes the amend) --- src/tex2lyx/text.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tex2lyx/text.cpp b/src/tex2lyx/text.cpp index b81b866005..f0b4aedace 100644 --- a/src/tex2lyx/text.cpp +++ b/src/tex2lyx/text.cpp @@ -346,7 +346,7 @@ string minted_nonfloat_caption = ""; // Characters that have to be escaped by \\ in LaTeX char const * const known_escaped_chars[] = { - "&", "_", "$", "%", "#", "^", "{", "}"}; + "&", "_", "$", "%", "#", "^", "{", "}", 0}; /// splits "x=z, y=b" into a map and an ordered keyword vector @@ -621,7 +621,7 @@ pair convert_unicodesymbols(docstring s) else { res = false; for (auto const & c : known_escaped_chars) - if (prefixIs(s, from_ascii("\\") + c)) + if (c != 0 && prefixIs(s, from_ascii("\\") + c)) res = true; i = 1; } From 103f7a5ea6d431e28becd02aa7e50ba5941010ff Mon Sep 17 00:00:00 2001 From: Pavel Sanda Date: Mon, 12 Mar 2018 13:40:52 +0100 Subject: [PATCH 091/121] Paint \dot & \ddot more like a dot https://www.mail-archive.com/lyx-devel@lists.lyx.org/msg204183.html --- src/mathed/MathSupport.cpp | 34 ++++++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/src/mathed/MathSupport.cpp b/src/mathed/MathSupport.cpp index 57eca6ee31..dfe2438499 100644 --- a/src/mathed/MathSupport.cpp +++ b/src/mathed/MathSupport.cpp @@ -82,6 +82,7 @@ namespace { /* * Internal struct of a drawing: code n x1 y1 ... xn yn, where code is: * 0 = end, 1 = line, 2 = polyline, 3 = square line, 4 = square polyline + * 5 = rounded thick line (i.e. dot for short line) */ @@ -293,9 +294,18 @@ double const hline[] = { }; +double const dot[] = { +// 1, 0.5, 0.2, 0.5, 0.2, +// 1, 0.4, 0.4, 0.6, 0.4, +// 1, 0.5, 0.5, 0.5, 0.5, + 5, 0.4, 0.4, 0.6, 0.4, + 0 +}; + + double const ddot[] = { - 1, 0.2, 0.5, 0.3, 0.5, - 1, 0.7, 0.5, 0.8, 0.5, + 5, 0.0, 0.4, 0.3, 0.4, + 5, 0.6, 0.4, 1.0, 0.4, 0 }; @@ -333,12 +343,6 @@ double const dline3[] = { }; -double const hlinesmall[] = { - 1, 0.4, 0.5, 0.6, 0.5, - 0 -}; - - double const ring[] = { 2, 5, 0.5, 0.8, 0.8, 0.5, 0.5, 0.2, 0.2, 0.5, 0.5, 0.8, @@ -457,7 +461,7 @@ named_deco_struct deco_table[] = { {"acute", slash, 0 }, {"tilde", tilde, 0 }, {"bar", hline, 0 }, - {"dot", hlinesmall, 0 }, + {"dot", dot, 0 }, {"check", angle, 1 }, {"breve", parenth, 1 }, {"vec", arrow, 3 }, @@ -623,7 +627,7 @@ void mathed_draw_deco(PainterInfo & pi, int x, int y, int w, int h, for (int i = 0; d[i]; ) { int code = int(d[i++]); - if (code & 1) { // code == 1 || code == 3 + if (code & 1) { // code == 1 || code == 3 || code == 5 double xx = d[i++]; double yy = d[i++]; double x2 = d[i++]; @@ -637,6 +641,16 @@ void mathed_draw_deco(PainterInfo & pi, int x, int y, int w, int h, int(x + xx + 0.5), int(y + yy + 0.5), int(x + x2 + 0.5), int(y + y2 + 0.5), pi.base.font.color()); + if (code == 5) { // thicker, but rounded + pi.pain.line( + int(x + xx + 0.5+1), int(y + yy + 0.5-1), + int(x + x2 + 0.5-1), int(y + y2 + 0.5-1), + pi.base.font.color()); + pi.pain.line( + int(x + xx + 0.5+1), int(y + yy + 0.5+1), + int(x + x2 + 0.5-1), int(y + y2 + 0.5+1), + pi.base.font.color()); + } } else { int xp[32]; int yp[32]; From 31c293dec38a8910764e40b7f3851dc4284164a3 Mon Sep 17 00:00:00 2001 From: Juergen Spitzmueller Date: Mon, 12 Mar 2018 14:50:19 +0100 Subject: [PATCH 092/121] tex2lyx: towards beamer overlay argument support. Implemented: Overlay and standard overlay arguments for commands and environments. Still missing: * List item overlay * itemcommand overlay (\overprint) * overlay via LatexParam (e.g., Flex:ArticleMode) Needs fixing: * General list argument (\begin{itemize}[arg]) * nested content in a frame with no title (empty par) (cherry picked from commit 949de66956309ea787b86d69a00b72d154b4d4db) --- src/tex2lyx/Parser.h | 3 ++- src/tex2lyx/TODO.txt | 7 ----- src/tex2lyx/tex2lyx.h | 5 ++-- src/tex2lyx/text.cpp | 62 ++++++++++++++++++++++++++++++++----------- 4 files changed, 52 insertions(+), 25 deletions(-) diff --git a/src/tex2lyx/Parser.h b/src/tex2lyx/Parser.h index ca1edebfa2..08d07c1af1 100644 --- a/src/tex2lyx/Parser.h +++ b/src/tex2lyx/Parser.h @@ -67,7 +67,8 @@ enum { FLAG_OPTION = 1 << 11, // read [...] style option FLAG_BRACED = 1 << 12, // read {...} style argument FLAG_CELL = 1 << 13, // read table cell - FLAG_TABBING = 1 << 14 // We are inside a tabbing environment + FLAG_TABBING = 1 << 14, // We are inside a tabbing environment + FLAG_RDELIM = 1 << 15, // next right delimiter ends the parsing }; diff --git a/src/tex2lyx/TODO.txt b/src/tex2lyx/TODO.txt index 9588691285..b42ea3fd28 100644 --- a/src/tex2lyx/TODO.txt +++ b/src/tex2lyx/TODO.txt @@ -52,10 +52,6 @@ Format LaTeX feature LyX feature 415 automatic undertilde loading \use_package undertilde 443 unicode-math.sty InsetMath* 448 -451 beamer overlay arguments InsetArgument - \command, \begin{env} -452 beamer block arguments InsetArgument - \begin{block}{title} 453 automatic stmaryrd loading \use_package stmaryrd 454 beamer overprint environment InsetArgument, layout Overprint \begin{overprint}[maxlength] @@ -64,9 +60,6 @@ Format LaTeX feature LyX feature 455 beamer frametitle command \begin_layout FrameTitle \frametitle[short]{long} 457 automatic stackrel loading \use_package stackrel -459 beamer: \begin{frame}, \begin_layout Frame - \begin{frame}[plain], \begin_layout PlainFrame - \begin{frame}[fragile] \begin_layout FragileFrame 466 Powerdot updates: \pause[] layout Pause \onslide{}{} InsetFlex, InsetArgument diff --git a/src/tex2lyx/tex2lyx.h b/src/tex2lyx/tex2lyx.h index c830b0531f..34da5902b0 100644 --- a/src/tex2lyx/tex2lyx.h +++ b/src/tex2lyx/tex2lyx.h @@ -48,7 +48,7 @@ extern std::string rgbcolor2code(std::string const & name); std::string translate_len(std::string const &); void parse_text(Parser & p, std::ostream & os, unsigned flags, bool outer, - Context & context); + Context & context, std::string const rdelim = std::string()); void check_comment_bib(std::ostream & os, Context & context); void fix_child_filename(std::string & name); @@ -67,7 +67,8 @@ std::string find_file(std::string const & name, std::string const & path, */ void parse_text_in_inset(Parser & p, std::ostream & os, unsigned flags, bool outer, Context const & context, - InsetLayout const * layout = 0); + InsetLayout const * layout = 0, + std::string const rdelim = std::string()); /// Guess document language from \p p if CJK is used. /// \p lang is used for all non-CJK contents. diff --git a/src/tex2lyx/text.cpp b/src/tex2lyx/text.cpp index f0b4aedace..a36b7558f1 100644 --- a/src/tex2lyx/text.cpp +++ b/src/tex2lyx/text.cpp @@ -54,7 +54,8 @@ void output_arguments(ostream &, Parser &, bool, bool, bool, Context &, void parse_text_in_inset(Parser & p, ostream & os, unsigned flags, bool outer, - Context const & context, InsetLayout const * layout) + Context const & context, InsetLayout const * layout, + string const rdelim) { bool const forcePlainLayout = layout ? layout->forcePlainLayout() : false; @@ -66,7 +67,7 @@ void parse_text_in_inset(Parser & p, ostream & os, unsigned flags, bool outer, if (layout) output_arguments(os, p, outer, false, false, newcontext, layout->latexargs()); - parse_text(p, os, flags, outer, newcontext); + parse_text(p, os, flags, outer, newcontext, rdelim); if (layout) output_arguments(os, p, outer, false, true, newcontext, layout->postcommandargs()); @@ -77,14 +78,15 @@ void parse_text_in_inset(Parser & p, ostream & os, unsigned flags, bool outer, namespace { void parse_text_in_inset(Parser & p, ostream & os, unsigned flags, bool outer, - Context const & context, string const & name) + Context const & context, string const & name, + string const rdelim = string()) { InsetLayout const * layout = 0; DocumentClass::InsetLayouts::const_iterator it = context.textclass.insetLayouts().find(from_ascii(name)); if (it != context.textclass.insetLayouts().end()) layout = &(it->second); - parse_text_in_inset(p, os, flags, outer, context, layout); + parse_text_in_inset(p, os, flags, outer, context, layout, rdelim); } /// parses a paragraph snippet, useful for example for \\emph{...} @@ -764,7 +766,15 @@ void output_arguments(ostream & os, Parser & p, bool outer, bool need_layout, bo if (lait->second.mandatory) { if (p.next_token().cat() != catBegin) break; - p.get_token(); // eat '{' + string ldelim = to_utf8(lait->second.ldelim); + string rdelim = to_utf8(lait->second.rdelim); + if (ldelim.empty()) + ldelim = "{"; + if (rdelim.empty()) + rdelim = "}"; + p.get_token(); // eat ldelim + if (ldelim.size() > 1) + p.get_token(); // eat ldelim if (need_layout) { context.check_layout(os); need_layout = false; @@ -773,13 +783,24 @@ void output_arguments(ostream & os, Parser & p, bool outer, bool need_layout, bo if (post) os << "post:"; os << i << "\nstatus collapsed\n\n"; - parse_text_in_inset(p, os, FLAG_BRACE_LAST, outer, context); + parse_text_in_inset(p, os, FLAG_RDELIM, outer, context, 0, rdelim); end_inset(os); } else { - if (p.next_token().cat() == catEscape || - p.next_token().character() != '[') + string ldelim = to_utf8(lait->second.ldelim); + string rdelim = to_utf8(lait->second.rdelim); + if (ldelim.empty()) + ldelim = "["; + if (rdelim.empty()) + rdelim = "]"; + string tok = p.next_token().asInput(); + // we only support delimiters with max 2 chars for now. + if (ldelim.size() > 1) + tok += p.next_next_token().asInput(); + if (p.next_token().cat() == catEscape || tok != ldelim) continue; - p.get_token(); // eat '[' + p.get_token(); // eat ldelim + if (ldelim.size() > 1) + p.get_token(); // eat ldelim if (need_layout) { context.check_layout(os); need_layout = false; @@ -788,7 +809,7 @@ void output_arguments(ostream & os, Parser & p, bool outer, bool need_layout, bo if (post) os << "post:"; os << i << "\nstatus collapsed\n\n"; - parse_text_in_inset(p, os, FLAG_BRACK_LAST, outer, context); + parse_text_in_inset(p, os, FLAG_RDELIM, outer, context, 0, rdelim); end_inset(os); } eat_whitespace(p, os, context, false); @@ -2060,10 +2081,11 @@ void parse_environment(Parser & p, ostream & os, bool outer, } context.check_deeper(os); // handle known optional and required arguments - // Unfortunately LyX can't handle arguments of list arguments (bug 7468): - // It is impossible to place anything after the environment name, - // but before the first \\item. - if (context.layout->latextype == LATEX_ENVIRONMENT) + // FIXME: for item environments, this is currently + // placed wrongly (in an empty paragraph). It has to go to + // the first \item par instead. + if (context.layout->latextype == LATEX_ENVIRONMENT + || context.layout->latextype == LATEX_ITEM_ENVIRONMENT) output_arguments(os, p, outer, false, false, context, context.layout->latexargs()); parse_text(p, os, FLAG_END, outer, context); @@ -2579,7 +2601,7 @@ void fix_child_filename(string & name) void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, - Context & context) + Context & context, string const rdelim) { Layout const * newlayout = 0; InsetLayout const * newinsetlayout = 0; @@ -2654,6 +2676,16 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, return; if (t.cat() == catEnd && (flags & FLAG_BRACE_LAST)) return; + string tok = t.asInput(); + // we only support delimiters with max 2 chars for now. + if (rdelim.size() > 1) + tok += p.next_token().asInput(); + if (t.cat() != catEscape && !rdelim.empty() + && tok == rdelim && (flags & FLAG_RDELIM)) { + if (rdelim.size() > 1) + p.get_token(); // eat rdelim + return; + } // If there is anything between \end{env} and \begin{env} we // don't need to output a separator. From 7c816488b698e0c577e48da0f21678cda0337fb4 Mon Sep 17 00:00:00 2001 From: Juergen Spitzmueller Date: Wed, 14 Mar 2018 08:40:47 +0100 Subject: [PATCH 093/121] tex2lyx: More work on beamer support * Implement list item overlay support (\item) * Implement itemcommand support (e.g., \overprint) * Fix general list argument placement Part of: #11068 (cherry picked from commit e51265b5f3c7765ad185303ac147792c7599386f) --- src/tex2lyx/Context.cpp | 2 + src/tex2lyx/Context.h | 2 + src/tex2lyx/test/test-structure.lyx.lyx | 5 +- src/tex2lyx/text.cpp | 86 ++++++++++++------------- 4 files changed, 48 insertions(+), 47 deletions(-) diff --git a/src/tex2lyx/Context.cpp b/src/tex2lyx/Context.cpp index 61685180bd..cc95a1fc6d 100644 --- a/src/tex2lyx/Context.cpp +++ b/src/tex2lyx/Context.cpp @@ -247,6 +247,8 @@ void Context::dump(ostream & os, string const & desc) const os << "extrastuff=[" << extra_stuff << "] "; if (!par_extra_stuff.empty()) os << "parextrastuff=[" << par_extra_stuff << "] "; + if (!list_extra_stuff.empty()) + os << "listextrastuff=[" << list_extra_stuff << "] "; os << "textclass=" << textclass.name() << " layout=" << to_utf8(layout->name()) << " parent_layout=" << to_utf8(parent_layout->name()) << "] font=[" diff --git a/src/tex2lyx/Context.h b/src/tex2lyx/Context.h index b88a921f33..47b39fc37c 100644 --- a/src/tex2lyx/Context.h +++ b/src/tex2lyx/Context.h @@ -128,6 +128,8 @@ public: std::string extra_stuff; /// We may need to add something after this \\begin_layout command std::string par_extra_stuff; + /// We may need to add something at the beginning of a list. + std::string list_extra_stuff; /// If there has been an \\begin_deeper, we'll need a matching /// \\end_deeper bool need_end_deeper; diff --git a/src/tex2lyx/test/test-structure.lyx.lyx b/src/tex2lyx/test/test-structure.lyx.lyx index 52f4e11882..87d9f6b0d2 100644 --- a/src/tex2lyx/test/test-structure.lyx.lyx +++ b/src/tex2lyx/test/test-structure.lyx.lyx @@ -892,9 +892,10 @@ the second item \begin_layout Itemize \begin_inset Argument item:1 -status open +status collapsed -\begin_layout Plain Layout + +\begin_layout Standard custom label \end_layout diff --git a/src/tex2lyx/text.cpp b/src/tex2lyx/text.cpp index a36b7558f1..ac2bed1512 100644 --- a/src/tex2lyx/text.cpp +++ b/src/tex2lyx/text.cpp @@ -47,7 +47,7 @@ namespace lyx { namespace { -void output_arguments(ostream &, Parser &, bool, bool, bool, Context &, +void output_arguments(ostream &, Parser &, bool, bool, string, Context &, Layout::LaTeXArgMap const &); } @@ -65,11 +65,11 @@ void parse_text_in_inset(Parser & p, ostream & os, unsigned flags, bool outer, else newcontext.font = context.font; if (layout) - output_arguments(os, p, outer, false, false, newcontext, + output_arguments(os, p, outer, false, string(), newcontext, layout->latexargs()); parse_text(p, os, flags, outer, newcontext, rdelim); if (layout) - output_arguments(os, p, outer, false, true, newcontext, + output_arguments(os, p, outer, false, "post", newcontext, layout->postcommandargs()); newcontext.check_end_layout(os); } @@ -749,14 +749,16 @@ void skip_spaces_braces(Parser & p, bool keepws = false) } -void output_arguments(ostream & os, Parser & p, bool outer, bool need_layout, bool post, +void output_arguments(ostream & os, Parser & p, bool outer, bool need_layout, string const prefix, Context & context, Layout::LaTeXArgMap const & latexargs) { - if (need_layout) { - context.check_layout(os); - need_layout = false; - } else - need_layout = true; + if (context.layout->latextype != LATEX_ITEM_ENVIRONMENT || !prefix.empty()) { + if (need_layout) { + context.check_layout(os); + need_layout = false; + } else + need_layout = true; + } int i = 0; Layout::LaTeXArgMap::const_iterator lait = latexargs.begin(); Layout::LaTeXArgMap::const_iterator const laend = latexargs.end(); @@ -780,8 +782,8 @@ void output_arguments(ostream & os, Parser & p, bool outer, bool need_layout, bo need_layout = false; } begin_inset(os, "Argument "); - if (post) - os << "post:"; + if (!prefix.empty()) + os << prefix << ':'; os << i << "\nstatus collapsed\n\n"; parse_text_in_inset(p, os, FLAG_RDELIM, outer, context, 0, rdelim); end_inset(os); @@ -806,8 +808,8 @@ void output_arguments(ostream & os, Parser & p, bool outer, bool need_layout, bo need_layout = false; } begin_inset(os, "Argument "); - if (post) - os << "post:"; + if (!prefix.empty()) + os << prefix << ':'; os << i << "\nstatus collapsed\n\n"; parse_text_in_inset(p, os, FLAG_RDELIM, outer, context, 0, rdelim); end_inset(os); @@ -840,10 +842,10 @@ void output_command_layout(ostream & os, Parser & p, bool outer, context.need_end_deeper = true; } context.check_deeper(os); - output_arguments(os, p, outer, true, false, context, + output_arguments(os, p, outer, true, string(), context, context.layout->latexargs()); parse_text(p, os, FLAG_ITEM, outer, context); - output_arguments(os, p, outer, false, true, context, + output_arguments(os, p, outer, false, "post", context, context.layout->postcommandargs()); context.check_end_layout(os); if (parent_context.deeper_paragraph) { @@ -2081,16 +2083,18 @@ void parse_environment(Parser & p, ostream & os, bool outer, } context.check_deeper(os); // handle known optional and required arguments - // FIXME: for item environments, this is currently - // placed wrongly (in an empty paragraph). It has to go to - // the first \item par instead. - if (context.layout->latextype == LATEX_ENVIRONMENT - || context.layout->latextype == LATEX_ITEM_ENVIRONMENT) - output_arguments(os, p, outer, false, false, context, + if (context.layout->latextype == LATEX_ENVIRONMENT) + output_arguments(os, p, outer, false, string(), context, context.layout->latexargs()); + else if (context.layout->latextype == LATEX_ITEM_ENVIRONMENT) { + ostringstream oss; + output_arguments(oss, p, outer, false, string(), context, + context.layout->latexargs()); + context.list_extra_stuff = oss.str(); + } parse_text(p, os, FLAG_END, outer, context); if (context.layout->latextype == LATEX_ENVIRONMENT) - output_arguments(os, p, outer, false, true, context, + output_arguments(os, p, outer, false, "post", context, context.layout->postcommandargs()); context.check_end_layout(os); if (parent_context.deeper_paragraph) { @@ -3074,10 +3078,10 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, continue; } - if (t.cs() == "item") { + // "item" by default, but could be something else + if (t.cs() == context.layout->itemcommand()) { string s; - bool const optarg = p.hasOpt(); - if (optarg) { + if (context.layout->labeltype == LABEL_MANUAL) { // FIXME: This swallows comments, but we cannot use // eat_whitespace() since we must not output // anything before the item. @@ -3091,26 +3095,19 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, // An item in an unknown list-like environment // FIXME: Do this in check_layout()! context.has_item = false; - if (optarg) - output_ert_inset(os, "\\item", context); - else - output_ert_inset(os, "\\item ", context); + string item = "\\" + context.layout->itemcommand(); + if (!p.hasOpt()) + item += " "; + output_ert_inset(os, item, context); } - if (optarg) { - if (context.layout->labeltype != LABEL_MANUAL) { - // handle option of itemize item - begin_inset(os, "Argument item:1\n"); - os << "status open\n"; - os << "\n\\begin_layout Plain Layout\n"; - Parser p2(s + ']'); - os << parse_text_snippet(p2, - FLAG_BRACK_LAST, outer, context); - // we must not use context.check_end_layout(os) - // because that would close the outer itemize layout - os << "\n\\end_layout\n"; - end_inset(os); - eat_whitespace(p, os, context, false); - } else if (!s.empty()) { + if (context.layout->labeltype != LABEL_MANUAL) + output_arguments(os, p, outer, false, "item", context, + context.layout->itemargs()); + if (!context.list_extra_stuff.empty()) { + os << context.list_extra_stuff; + context.list_extra_stuff.clear(); + } + else if (!s.empty()) { // LyX adds braces around the argument, // so we need to remove them here. if (s.size() > 2 && s[0] == '{' && @@ -3132,7 +3129,6 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, os << ' '; eat_whitespace(p, os, context, false); } - } continue; } From 42863eac9259fa656c0e8a068f5847743a216fb6 Mon Sep 17 00:00:00 2001 From: Juergen Spitzmueller Date: Wed, 14 Mar 2018 14:38:18 +0100 Subject: [PATCH 094/121] tex2lyx: support for beamer text styles with overlays E.g. things like \textbf
{foo} have to be imported as insets. Part of #11068 (cherry picked from commit c74e3999812dfdff3cb6d20ef460dfca1f17c879) --- src/tex2lyx/Parser.cpp | 4 ++-- src/tex2lyx/Parser.h | 2 +- src/tex2lyx/text.cpp | 11 +++++++---- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/tex2lyx/Parser.cpp b/src/tex2lyx/Parser.cpp index 6e29623b96..1d506a78a8 100644 --- a/src/tex2lyx/Parser.cpp +++ b/src/tex2lyx/Parser.cpp @@ -453,7 +453,7 @@ bool Parser::good() } -bool Parser::hasOpt() +bool Parser::hasOpt(string const l) { // An optional argument can occur in any of the following forms: // - \foo[bar] @@ -479,7 +479,7 @@ bool Parser::hasOpt() putback(); break; } - bool const retval = (next_token().asInput() == "["); + bool const retval = (next_token().asInput() == l); pos_ = oldpos; return retval; } diff --git a/src/tex2lyx/Parser.h b/src/tex2lyx/Parser.h index 08d07c1af1..83fa1c745a 100644 --- a/src/tex2lyx/Parser.h +++ b/src/tex2lyx/Parser.h @@ -214,7 +214,7 @@ public: void dump() const; /// Does an optional argument follow after the current token? - bool hasOpt(); + bool hasOpt(std::string const l = "["); /// typedef std::pair Arg; /*! diff --git a/src/tex2lyx/text.cpp b/src/tex2lyx/text.cpp index ac2bed1512..f3617a8e97 100644 --- a/src/tex2lyx/text.cpp +++ b/src/tex2lyx/text.cpp @@ -3627,14 +3627,16 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, continue; } - if ((where = is_known(t.cs(), known_text_font_series))) { + // beamer has a \textbf{} inset + if (!p.hasOpt("<") && (where = is_known(t.cs(), known_text_font_series))) { parse_text_attributes(p, os, FLAG_ITEM, outer, context, "\\series", context.font.series, known_coded_font_series[where - known_text_font_series]); continue; } - if ((where = is_known(t.cs(), known_text_font_shapes))) { + // beamer has a \textit{} inset + if (!p.hasOpt("<") && (where = is_known(t.cs(), known_text_font_shapes))) { parse_text_attributes(p, os, FLAG_ITEM, outer, context, "\\shape", context.font.shape, known_coded_font_shapes[where - known_text_font_shapes]); @@ -3713,9 +3715,10 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, continue; } - if (t.cs() == "uuline" || t.cs() == "uwave" + // beamer has an \emph{} inset + if ((t.cs() == "uuline" || t.cs() == "uwave" || t.cs() == "emph" || t.cs() == "noun" - || t.cs() == "xout") { + || t.cs() == "xout") && !p.hasOpt("<")) { context.check_layout(os); os << "\n\\" << t.cs() << " on\n"; parse_text_snippet(p, os, FLAG_ITEM, outer, context); From ce5b420a44ec1bfa5898c05236cc16ccec210343 Mon Sep 17 00:00:00 2001 From: Juergen Spitzmueller Date: Fri, 16 Mar 2018 12:56:17 +0100 Subject: [PATCH 095/121] tex2lyx: add support for LaTeXParam Part of #11068 (cherry picked from commit 506ae2d2ea1e646461841c57edd3f79c97d671c2) --- src/tex2lyx/Context.h | 2 + src/tex2lyx/Parser.cpp | 21 +++++++++ src/tex2lyx/Parser.h | 5 +++ src/tex2lyx/TODO.txt | 15 ------- src/tex2lyx/tex2lyx.cpp | 36 ++++++++------- src/tex2lyx/tex2lyx.h | 10 +++-- src/tex2lyx/text.cpp | 99 ++++++++++++++++++++++++++++++++++++++--- 7 files changed, 146 insertions(+), 42 deletions(-) diff --git a/src/tex2lyx/Context.h b/src/tex2lyx/Context.h index 47b39fc37c..e48bdf35d6 100644 --- a/src/tex2lyx/Context.h +++ b/src/tex2lyx/Context.h @@ -130,6 +130,8 @@ public: std::string par_extra_stuff; /// We may need to add something at the beginning of a list. std::string list_extra_stuff; + /// A LaTeXParam to be ignored in parsing. + std::string latexparam; /// If there has been an \\begin_deeper, we'll need a matching /// \\end_deeper bool need_end_deeper; diff --git a/src/tex2lyx/Parser.cpp b/src/tex2lyx/Parser.cpp index 1d506a78a8..94da955fea 100644 --- a/src/tex2lyx/Parser.cpp +++ b/src/tex2lyx/Parser.cpp @@ -650,6 +650,27 @@ string const Parser::plainCommand(char left, char right, string const & name) } +string const Parser::getCommandLatexParam() +{ + if (!good()) + return string(); + string res; + size_t offset = 0; + while (true) { + if (pos_ + offset >= tokens_.size()) + tokenize_one(); + if (pos_ + offset >= tokens_.size()) + break; + Token t = tokens_[pos_ + offset]; + if (t.cat() == catBegin) + break; + res += t.asInput(); + ++offset; + } + return res; +} + + Parser::Arg Parser::verbatimStuff(string const & end_string, bool const allow_linebreak) { if (!good()) diff --git a/src/tex2lyx/Parser.h b/src/tex2lyx/Parser.h index 83fa1c745a..b15f95aa41 100644 --- a/src/tex2lyx/Parser.h +++ b/src/tex2lyx/Parser.h @@ -278,6 +278,11 @@ public: * This function is designed to parse verbatim commands. */ std::string const plainCommand(char left, char right, std::string const & name); + /* + * Returns everything before the main command argument. + * This is where the LaTeXParam value of a layout is output. + */ + std::string const getCommandLatexParam(); /* * Basically the same as plainEnvironment() but the parsing is * stopped at string \p end_string. Contrary to the other diff --git a/src/tex2lyx/TODO.txt b/src/tex2lyx/TODO.txt index b42ea3fd28..be5d770021 100644 --- a/src/tex2lyx/TODO.txt +++ b/src/tex2lyx/TODO.txt @@ -45,7 +45,6 @@ Format LaTeX feature LyX feature 386 LyX version InsetInfo 390 forward/reverse search \forward_search, \forward_macro 391 decimal alignment in tables InsetTabular -392 new beamer format InsetLayout 399 automatic mathdots loading \use_mathdots 407 vertical offset for multirows InsetTabular 411 support for polyglossia \language_package (the cases of no package, of babel and of custom package is supported) @@ -53,21 +52,7 @@ Format LaTeX feature LyX feature 443 unicode-math.sty InsetMath* 448 453 automatic stmaryrd loading \use_package stmaryrd -454 beamer overprint environment InsetArgument, layout Overprint - \begin{overprint}[maxlength] - \onslide text ... - \end{overprint} -455 beamer frametitle command \begin_layout FrameTitle - \frametitle[short]{long} 457 automatic stackrel loading \use_package stackrel -466 Powerdot updates: - \pause[] layout Pause - \onslide{}{} InsetFlex, InsetArgument - \onslide*{}{} InsetFlex, InsetArgument - \onslide+{}{} InsetFlex, InsetArgument - \twocolumn[]{}{} Layout Twocolumn, InsetArgument - \item[]<> InsetArgument - \begin{enumerate|itemize|...}[] InsetArgument 526 Plural and capitalized refstyles InsetRef 533 Multibib support \begin{btUnit}...\end{btUnit} \multibib {none|part|chapter|section|subsection} diff --git a/src/tex2lyx/tex2lyx.cpp b/src/tex2lyx/tex2lyx.cpp index cbdd7500b6..416f1268f3 100644 --- a/src/tex2lyx/tex2lyx.cpp +++ b/src/tex2lyx/tex2lyx.cpp @@ -172,30 +172,32 @@ void add_known_theorem(string const & theorem, string const & o1, } -Layout const * findLayoutWithoutModule(TextClass const & textclass, - string const & name, bool command) +Layout const * findLayoutWithoutModule(TextClass const & tc, + string const & name, bool command, + string const & latexparam) { - DocumentClass::const_iterator it = textclass.begin(); - DocumentClass::const_iterator en = textclass.end(); - for (; it != en; ++it) { - if (it->latexname() == name && - ((command && it->isCommand()) || (!command && it->isEnvironment()))) - return &*it; + for (auto const & lay : tc) { + if (lay.latexname() == name && + (latexparam.empty() || + (!lay.latexparam().empty() && suffixIs(latexparam, lay.latexparam()))) && + ((command && lay.isCommand()) || (!command && lay.isEnvironment()))) + return &lay; } return 0; } -InsetLayout const * findInsetLayoutWithoutModule(TextClass const & textclass, - string const & name, bool command) +InsetLayout const * findInsetLayoutWithoutModule(TextClass const & tc, + string const & name, bool command, + string const & latexparam) { - DocumentClass::InsetLayouts::const_iterator it = textclass.insetLayouts().begin(); - DocumentClass::InsetLayouts::const_iterator en = textclass.insetLayouts().end(); - for (; it != en; ++it) { - if (it->second.latexname() == name && - ((command && it->second.latextype() == InsetLayout::COMMAND) || - (!command && it->second.latextype() == InsetLayout::ENVIRONMENT))) - return &(it->second); + for (auto const & ilay : tc.insetLayouts()) { + if (ilay.second.latexname() == name && + (latexparam.empty() || + (!ilay.second.latexparam().empty() && suffixIs(latexparam, ilay.second.latexparam()))) && + ((command && ilay.second.latextype() == InsetLayout::COMMAND) || + (!command && ilay.second.latextype() == InsetLayout::ENVIRONMENT))) + return &(ilay.second); } return 0; } diff --git a/src/tex2lyx/tex2lyx.h b/src/tex2lyx/tex2lyx.h index 34da5902b0..1791c2f414 100644 --- a/src/tex2lyx/tex2lyx.h +++ b/src/tex2lyx/tex2lyx.h @@ -112,10 +112,12 @@ extern void add_known_environment(std::string const & environment, docstring const & end); extern void add_known_theorem(std::string const & theorem, std::string const & o1, bool o2, docstring const & definition); -extern Layout const * findLayoutWithoutModule(TextClass const & textclass, - std::string const & name, bool command); -extern InsetLayout const * findInsetLayoutWithoutModule( - TextClass const & textclass, std::string const & name, bool command); +extern Layout const * findLayoutWithoutModule(TextClass const & tc, + std::string const & name, bool command, + std::string const & latexparam = std::string()); +extern InsetLayout const * findInsetLayoutWithoutModule(TextClass const & tc, + std::string const & name, bool command, + std::string const & latexparam = std::string()); /*! * Check whether a module provides command (if \p command is true) or * environment (if \p command is false) \p name, and add the module to the diff --git a/src/tex2lyx/text.cpp b/src/tex2lyx/text.cpp index f3617a8e97..2036ea612c 100644 --- a/src/tex2lyx/text.cpp +++ b/src/tex2lyx/text.cpp @@ -67,6 +67,13 @@ void parse_text_in_inset(Parser & p, ostream & os, unsigned flags, bool outer, if (layout) output_arguments(os, p, outer, false, string(), newcontext, layout->latexargs()); + // If we have a latex param, we eat it here. + if (!context.latexparam.empty()) { + ostringstream oss; + Context dummy(true, context.textclass); + parse_text(p, oss, FLAG_RDELIM, outer, dummy, + string(1, context.latexparam.back())); + } parse_text(p, os, flags, outer, newcontext, rdelim); if (layout) output_arguments(os, p, outer, false, "post", newcontext, @@ -697,24 +704,27 @@ void output_comment(Parser & p, ostream & os, string const & s, } -Layout const * findLayout(TextClass const & textclass, string const & name, bool command) +Layout const * findLayout(TextClass const & textclass, string const & name, bool command, + string const & latexparam = string()) { - Layout const * layout = findLayoutWithoutModule(textclass, name, command); + Layout const * layout = findLayoutWithoutModule(textclass, name, command, latexparam); if (layout) return layout; if (checkModule(name, command)) - return findLayoutWithoutModule(textclass, name, command); + return findLayoutWithoutModule(textclass, name, command, latexparam); return layout; } -InsetLayout const * findInsetLayout(TextClass const & textclass, string const & name, bool command) +InsetLayout const * findInsetLayout(TextClass const & textclass, string const & name, bool command, + string const & latexparam = string()) { - InsetLayout const * insetlayout = findInsetLayoutWithoutModule(textclass, name, command); + InsetLayout const * insetlayout = + findInsetLayoutWithoutModule(textclass, name, command, latexparam); if (insetlayout) return insetlayout; if (checkModule(name, command)) - return findInsetLayoutWithoutModule(textclass, name, command); + return findInsetLayoutWithoutModule(textclass, name, command, latexparam); return insetlayout; } @@ -844,6 +854,13 @@ void output_command_layout(ostream & os, Parser & p, bool outer, context.check_deeper(os); output_arguments(os, p, outer, true, string(), context, context.layout->latexargs()); + // If we have a latex param, we eat it here. + if (!parent_context.latexparam.empty()) { + ostringstream oss; + Context dummy(true, parent_context.textclass); + parse_text(p, oss, FLAG_RDELIM, outer, dummy, + string(1, parent_context.latexparam.back())); + } parse_text(p, os, FLAG_ITEM, outer, context); output_arguments(os, p, outer, false, "post", context, context.layout->postcommandargs()); @@ -3269,6 +3286,25 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, continue; } + // Before we look for the layout name with star and alone below, we check the layouts including + // the LateXParam, which might be one or several options or a star. + // The single '=' is meant here. + if (context.new_layout_allowed && + (newlayout = findLayout(context.textclass, t.cs(), true, p.getCommandLatexParam()))) { + // store the latexparam here. This is eaten in output_command_layout + context.latexparam = newlayout->latexparam(); + // write the layout + output_command_layout(os, p, outer, context, newlayout); + p.skip_spaces(); + if (!preamble.titleLayoutFound()) + preamble.titleLayoutFound(newlayout->intitle); + set const & req = newlayout->requires(); + for (set::const_iterator it = req.begin(); it != req.end(); ++it) + preamble.registerAutomaticallyLoadedPackage(*it); + continue; + } + + // Starred section headings // Must attempt to parse "Section*" before "Section". if ((p.next_token().asInput() == "*") && @@ -5389,6 +5425,57 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, continue; } + // Before we look for the layout name alone below, we check the layouts including the LateXParam, which + // might be one or several options or a star. + // The single '=' is meant here. + if ((newinsetlayout = findInsetLayout(context.textclass, starredname, true, p.getCommandLatexParam()))) { + if (starred) + p.get_token(); + p.skip_spaces(); + context.check_layout(os); + // store the latexparam here. This is eaten in parse_text_in_inset + context.latexparam = newinsetlayout->latexparam(); + docstring name = newinsetlayout->name(); + bool const caption = name.find(from_ascii("Caption:")) == 0; + if (caption) { + // Already done for floating minted listings. + if (minted_float.empty()) { + begin_inset(os, "Caption "); + os << to_utf8(name.substr(8)) << '\n'; + } + } else { + // FIXME: what do we do if the prefix is not Flex: ? + if (prefixIs(name, from_ascii("Flex:"))) + name.erase(0, 5); + begin_inset(os, "Flex "); + os << to_utf8(name) << '\n' + << "status collapsed\n"; + } + if (!minted_float.empty()) { + parse_text_snippet(p, os, FLAG_ITEM, false, context); + } else if (newinsetlayout->isPassThru()) { + // set catcodes to verbatim early, just in case. + p.setCatcodes(VERBATIM_CATCODES); + string delim = p.get_token().asInput(); + if (delim != "{") + cerr << "Warning: bad delimiter for command " << t.asInput() << endl; + //FIXME: handle error condition + string const arg = p.verbatimStuff("}").second; + Context newcontext(true, context.textclass); + if (newinsetlayout->forcePlainLayout()) + newcontext.layout = &context.textclass.plainLayout(); + output_ert(os, arg, newcontext); + } else + parse_text_in_inset(p, os, FLAG_ITEM, false, context, newinsetlayout); + if (caption) + p.skip_spaces(); + // Minted caption insets are not closed here because + // we collect everything into the caption. + if (minted_float.empty()) + end_inset(os); + continue; + } + // The single '=' is meant here. if ((newinsetlayout = findInsetLayout(context.textclass, starredname, true))) { if (starred) From 5170efe2c9d98ea238474bcd8edf85490107a379 Mon Sep 17 00:00:00 2001 From: Juergen Spitzmueller Date: Sat, 17 Mar 2018 12:38:53 +0100 Subject: [PATCH 096/121] tex2lyx: clear latexparam after use. (cherry picked from commit 7e3a41bd15e993bf738134c6dc601f482d036894) --- src/tex2lyx/text.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/tex2lyx/text.cpp b/src/tex2lyx/text.cpp index 2036ea612c..cffeb58981 100644 --- a/src/tex2lyx/text.cpp +++ b/src/tex2lyx/text.cpp @@ -786,7 +786,7 @@ void output_arguments(ostream & os, Parser & p, bool outer, bool need_layout, st rdelim = "}"; p.get_token(); // eat ldelim if (ldelim.size() > 1) - p.get_token(); // eat ldelim + p.get_token(); // eat ldelim if (need_layout) { context.check_layout(os); need_layout = false; @@ -812,7 +812,7 @@ void output_arguments(ostream & os, Parser & p, bool outer, bool need_layout, st continue; p.get_token(); // eat ldelim if (ldelim.size() > 1) - p.get_token(); // eat ldelim + p.get_token(); // eat ldelim if (need_layout) { context.check_layout(os); need_layout = false; @@ -3295,6 +3295,7 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, context.latexparam = newlayout->latexparam(); // write the layout output_command_layout(os, p, outer, context, newlayout); + context.latexparam.clear(); p.skip_spaces(); if (!preamble.titleLayoutFound()) preamble.titleLayoutFound(newlayout->intitle); @@ -5467,6 +5468,7 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, output_ert(os, arg, newcontext); } else parse_text_in_inset(p, os, FLAG_ITEM, false, context, newinsetlayout); + context.latexparam.clear(); if (caption) p.skip_spaces(); // Minted caption insets are not closed here because From cfc2f0681e69e7f344ab86f9fd7d5c2a41e8094e Mon Sep 17 00:00:00 2001 From: Juergen Spitzmueller Date: Sat, 17 Mar 2018 12:39:13 +0100 Subject: [PATCH 097/121] tex2lyx: handle makebeamertitle (cherry picked from commit d93076c1284de96b12cb583edfee2654de928a61) --- src/tex2lyx/text.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tex2lyx/text.cpp b/src/tex2lyx/text.cpp index cffeb58981..d4dfbfabf0 100644 --- a/src/tex2lyx/text.cpp +++ b/src/tex2lyx/text.cpp @@ -3604,7 +3604,7 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, continue; } - else if (t.cs() == "makeindex" || t.cs() == "maketitle") { + else if (t.cs() == "makeindex" || t.cs() == "maketitle" || t.cs() == "makebeamertitle") { if (preamble.titleLayoutFound()) { // swallow this skip_spaces_braces(p); From b0c9da0da198c3b42e08ead912493222179db506 Mon Sep 17 00:00:00 2001 From: Juergen Spitzmueller Date: Sat, 17 Mar 2018 12:19:50 +0100 Subject: [PATCH 098/121] tex2lyx: do not eat empty paragraphs if keepempty is true Fixes: #11078 (cherry picked from commit 79728dcde975fc5968d0ef9e6b56df57023acd88) --- src/tex2lyx/text.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/tex2lyx/text.cpp b/src/tex2lyx/text.cpp index d4dfbfabf0..ce357ea031 100644 --- a/src/tex2lyx/text.cpp +++ b/src/tex2lyx/text.cpp @@ -2099,6 +2099,12 @@ void parse_environment(Parser & p, ostream & os, bool outer, break; } context.check_deeper(os); + if (newlayout->keepempty) { + // We need to start a new paragraph + // even if it is empty. + context.new_paragraph(os); + context.check_layout(os); + } // handle known optional and required arguments if (context.layout->latextype == LATEX_ENVIRONMENT) output_arguments(os, p, outer, false, string(), context, From 910daa27e4842731284e371757caf3bf2d8e4864 Mon Sep 17 00:00:00 2001 From: Juergen Spitzmueller Date: Sat, 17 Mar 2018 13:20:48 +0100 Subject: [PATCH 099/121] tex2lyx: add beamer test file (cherry picked from commit 63b67fee8329840f0fbbd75b8ec9321ba1243555) --- src/tex2lyx/Makefile.am | 2 + src/tex2lyx/test/CMakeLists.txt | 1 + src/tex2lyx/test/beamer.lyx.lyx | 4411 ++++++++++++++++++++ src/tex2lyx/test/beamer.tex | 706 ++++ src/tex2lyx/test/runtests.py | 1 + src/tex2lyx/test/test-insets-basic.lyx.lyx | 4 +- src/tex2lyx/test/test-insets.lyx.lyx | 4 +- src/tex2lyx/test/test-structure.lyx.lyx | 2 +- 8 files changed, 5126 insertions(+), 5 deletions(-) create mode 100644 src/tex2lyx/test/beamer.lyx.lyx create mode 100644 src/tex2lyx/test/beamer.tex diff --git a/src/tex2lyx/Makefile.am b/src/tex2lyx/Makefile.am index 7a744abc0b..da7c3183a4 100644 --- a/src/tex2lyx/Makefile.am +++ b/src/tex2lyx/Makefile.am @@ -25,6 +25,7 @@ TEST_FILES = \ test/runtests.cmake \ test/runtests.py \ test/algo2e.tex \ + test/beamer.tex \ test/box-color-size-space-align.tex \ test/CJK.tex \ test/CJKutf8.tex \ @@ -49,6 +50,7 @@ TEST_FILES = \ TEST_RESULTS = \ test/algo2e.lyx.lyx \ + test/beamer.lyx.lyx \ test/box-color-size-space-align.lyx.lyx \ test/CJK.lyx.lyx \ test/CJKutf8.lyx.lyx \ diff --git a/src/tex2lyx/test/CMakeLists.txt b/src/tex2lyx/test/CMakeLists.txt index 643b017bb2..a6f6789f85 100644 --- a/src/tex2lyx/test/CMakeLists.txt +++ b/src/tex2lyx/test/CMakeLists.txt @@ -12,6 +12,7 @@ project(testTex2lyx) set(_tex_tests test.ltx algo2e.tex + beamer.tex box-color-size-space-align.tex CJK.tex CJKutf8.tex diff --git a/src/tex2lyx/test/beamer.lyx.lyx b/src/tex2lyx/test/beamer.lyx.lyx new file mode 100644 index 0000000000..f3ba80fc5c --- /dev/null +++ b/src/tex2lyx/test/beamer.lyx.lyx @@ -0,0 +1,4411 @@ +#LyX file created by tex2lyx 2.3 +\lyxformat 544 +\begin_document +\begin_header +\save_transient_properties true +\origin roundtrip +\textclass beamer +\begin_preamble + + +\usepackage{babel} + + +\usetheme[left,width=3.45em]{Berkeley} + + +\end_preamble +\use_default_options false +\maintain_unincluded_children false +\language english +\language_package default +\inputencoding iso8859-15 +\fontencoding T1 +\font_roman "default" "default" +\font_sans "default" "default" +\font_typewriter "default" "default" +\font_math "auto" "auto" +\font_default_family default +\use_non_tex_fonts false +\font_sc false +\font_osf false +\font_sf_scale 100 100 +\font_tt_scale 100 100 +\use_microtype false +\use_dash_ligatures true +\graphics default +\default_output_format default +\output_sync 0 +\bibtex_command default +\index_command default +\paperfontsize default +\spacing single +\use_hyperref false +\papersize default +\use_geometry false +\use_package amsmath 1 +\use_package amssymb 0 +\use_package cancel 0 +\use_package esint 1 +\use_package mathdots 0 +\use_package mathtools 0 +\use_package mhchem 0 +\use_package stackrel 0 +\use_package stmaryrd 0 +\use_package undertilde 0 +\cite_engine basic +\cite_engine_type default +\biblio_style plain +\use_bibtopic false +\use_indices false +\paperorientation portrait +\suppress_date false +\justification true +\use_refstyle 0 +\use_minted 0 +\index Index +\shortcut idx +\color #008000 +\end_index +\secnumdepth 3 +\tocdepth 3 +\paragraph_separation indent +\paragraph_indentation default +\is_math_indent 0 +\math_numbering_side default +\quotes_style english +\dynamic_quotes 0 +\papercolumns 1 +\papersides 1 +\paperpagestyle default +\tracking_changes false +\output_changes false +\html_math_output 0 +\html_css_as_file 0 +\html_be_strict false +\end_header + +\begin_body + +\begin_layout Title +Presentations with Beamer +\end_layout + +\begin_layout Subtitle +An Introduction to the Basics +\end_layout + +\begin_layout Author +John Doe +\end_layout + +\begin_layout Date +Version +\begin_inset space ~ + +\end_inset + +2.3 +\end_layout + +\begin_layout Frame + +\end_layout + +\begin_deeper +\begin_layout FrameTitle + +\begin_inset Argument 1 +status collapsed + + +\begin_layout Standard +presentation +\end_layout + +\end_inset + +Contents +\end_layout + +\end_deeper +\begin_layout Frame + +\begin_inset CommandInset toc +LatexCommand tableofcontents + +\end_inset + + +\end_layout + +\begin_layout Section +Purposes +\end_layout + +\begin_layout Frame + +\begin_inset Argument 2 +status collapsed + + +\begin_layout Standard ++- +\end_layout + +\end_inset + + +\begin_inset Argument 4 +status collapsed + + +\begin_layout Standard +Purpose of the Beamer class +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Frame +With the +\begin_inset Flex Structure +status collapsed + +\begin_layout Plain Layout +Beamer +\end_layout + +\end_inset + + class, you can produce presentation slides, which +\end_layout + +\begin_deeper +\begin_layout Itemize +are visually highly customizable +\end_layout + +\begin_layout Itemize +can be very well structured +\end_layout + +\begin_layout Itemize +can be constructed step-by-step ( +\begin_inset Quotes eld +\end_inset + +overlay +\begin_inset Quotes erd +\end_inset + + concept) +\end_layout + +\begin_layout Itemize +may contain different navigation paths (note that the slides contain all sorts of hyperlinks) +\end_layout + +\begin_layout Itemize +use \SpecialChar LaTeX +'s superb output quality +\end_layout + +\begin_layout Itemize +might embed multimedia content (audio, video) +\end_layout + +\begin_layout Itemize +can easily be transformed to accompanying material (such as an article-like handout) +\end_layout + +\begin_layout Itemize +and much more \SpecialChar ldots + +\end_layout + +\end_deeper +\begin_layout Standard + +\begin_inset Separator plain + +\end_inset + + +\end_layout + +\begin_layout Frame + +\begin_inset Argument 4 +status collapsed + + +\begin_layout Standard +Purpose of this presentation +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Frame +This presentation +\end_layout + +\begin_deeper +\begin_layout Itemize + +\begin_inset Argument 1 +status collapsed + + +\begin_layout Standard ++- +\end_layout + +\end_inset + +describes some basic features of +\begin_inset Flex Structure +status collapsed + +\begin_layout Plain Layout +Beamer +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Itemize +especially how they can be used +\end_layout + +\end_deeper +\begin_layout Frame +For more general and comprehensive information on +\begin_inset Flex Flex:Structure +status collapsed + +\begin_layout Plain Layout + +\begin_inset Argument 1 +status collapsed + + +\begin_layout Standard +presentation +\end_layout + +\end_inset + +Beamer +\end_layout + +\end_inset + + itself, please refer to the extensive class manual +\begin_inset CommandInset citation +LatexCommand cite +after "" +key "beamer-ug" +literal "false" + +\end_inset + + +\end_layout + +\begin_layout Section* +Segments of a presentation +\end_layout + +\begin_layout Frame + +\begin_inset Argument 4 +status collapsed + + +\begin_layout Standard +The global structure +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Frame +A presentation usually consists of +\end_layout + +\begin_deeper +\begin_layout Itemize + +\begin_inset Argument item:2 +status collapsed + + +\begin_layout Standard ++- +\end_layout + +\end_inset + +a title page +\end_layout + +\begin_layout Itemize + +\begin_inset Argument item:2 +status collapsed + + +\begin_layout Standard ++- +\end_layout + +\end_inset + +slides that might be grouped to sections/parts +\end_layout + +\begin_layout Itemize + +\begin_inset Argument item:1 +status collapsed + + +\begin_layout Standard +extra +\end_layout + +\end_inset + + +\begin_inset Argument item:2 +status collapsed + + +\begin_layout Standard ++- +\end_layout + +\end_inset + +an appendix with additional information, such as a bibliography +\end_layout + +\end_deeper +\begin_layout Frame +We describe these global segments in what follows. +\end_layout + +\begin_layout Standard + +\begin_inset Separator plain + +\end_inset + + +\end_layout + +\begin_layout Frame + +\begin_inset Argument 4 +status collapsed + + +\begin_layout Standard +The title page +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Frame +A title page is constructed by the layouts +\begin_inset Flex Structure +status collapsed + +\begin_layout Plain Layout +Title +\end_layout + +\end_inset + +, +\begin_inset Flex Structure +status collapsed + +\begin_layout Plain Layout +Subtitle +\end_layout + +\end_inset + +, +\begin_inset Flex Flex:Structure +status collapsed + +\begin_layout Plain Layout + +\begin_inset Argument 1 +status collapsed + + +\begin_layout Standard +2 +\end_layout + +\end_inset + +Author +\end_layout + +\end_inset + +, +\begin_inset Flex Structure +status collapsed + +\begin_layout Plain Layout +Institute +\end_layout + +\end_inset + +, +\begin_inset Flex Structure +status collapsed + +\begin_layout Plain Layout +Date +\end_layout + +\end_inset + + and +\begin_inset Flex Structure +status collapsed + +\begin_layout Plain Layout +TitleGraphic +\end_layout + +\end_inset + +. +\end_layout + +\begin_deeper +\begin_layout Itemize +None of these elements is mandatory, but at least one must be given +\end_layout + +\begin_layout Itemize +The order of insertion does not matter (the real order is defined in the +\begin_inset Flex Structure +status collapsed + +\begin_layout Plain Layout +Beamer +\end_layout + +\end_inset + + theme) +\end_layout + +\begin_layout Itemize +For +\begin_inset Flex Structure +status collapsed + +\begin_layout Plain Layout +Title +\end_layout + +\end_inset + +, +\begin_inset Flex Structure +status collapsed + +\begin_layout Plain Layout +Subtitle +\end_layout + +\end_inset + +, +\begin_inset Flex Structure +status collapsed + +\begin_layout Plain Layout +Author +\end_layout + +\end_inset + +, +\begin_inset Flex Structure +status collapsed + +\begin_layout Plain Layout +Institute +\end_layout + +\end_inset + + and +\begin_inset Flex Structure +status collapsed + +\begin_layout Plain Layout +Date +\end_layout + +\end_inset + +, you can define +\begin_inset Quotes eld +\end_inset + +short +\begin_inset Quotes erd +\end_inset + + forms via +\begin_inset Flex Alert +status collapsed + +\begin_layout Plain Layout +Insert →Short Title\SpecialChar breakableslash +Date\SpecialChar breakableslash +\SpecialChar ldots + +\end_layout + +\end_inset + + These are used in the sidebar\SpecialChar breakableslash +heading (given the theme actually provides a sidebar\SpecialChar breakableslash +heading) +\end_layout + +\begin_layout Itemize +If you select +\begin_inset Flex Structure +status collapsed + +\begin_layout Plain Layout +Title (Plain Frame) +\end_layout + +\end_inset + + instead of +\begin_inset Flex Structure +status collapsed + +\begin_layout Plain Layout +Title +\end_layout + +\end_inset + +, the title page will have no sidebar or heading +\end_layout + +\end_deeper +\begin_layout Standard + +\begin_inset Separator plain + +\end_inset + + +\end_layout + +\begin_layout Frame + +\begin_inset Argument 1 +status collapsed + + +\begin_layout Standard +1-2 +\end_layout + +\end_inset + + +\begin_inset Argument 3 +status collapsed + + +\begin_layout Standard +label=myframe +\end_layout + +\end_inset + + +\begin_inset Argument 4 +status collapsed + + +\begin_layout Standard +Frames can be repeated +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Frame +Frames can be repeated fully or only in terms of selected sub-slides, multiple times at any later point of the presentation. +\end_layout + +\begin_layout Frame +You just need to give the respective frame a label name via the frame option +\begin_inset Quotes eld +\end_inset + +label +\begin_inset Quotes erd +\end_inset + + (as done here). +\end_layout + +\begin_deeper +\begin_layout Pause + +\end_layout + +\end_deeper +\begin_layout Frame +Then you can repeat this frame by means of the +\begin_inset Flex Structure +status collapsed + +\begin_layout Plain Layout +AgainFrame +\end_layout + +\end_inset + + layout later in the presentation. Just enter the label name in the +\begin_inset Flex Structure +status collapsed + +\begin_layout Plain Layout +AgainFrame +\end_layout + +\end_inset + + layout and specify, if required, which sub-slides you want to be repeated via +\begin_inset Flex Alert +status collapsed + +\begin_layout Plain Layout +Insert →Overlay Specifications +\end_layout + +\end_inset + + (again, see below for the concept of +\begin_inset Quotes eld +\end_inset + +overlays +\begin_inset Quotes erd +\end_inset + +). +\end_layout + +\begin_deeper +\begin_layout Proof + +\begin_inset Argument 1 +status collapsed + + +\begin_layout Standard +3 +\end_layout + +\end_inset + + +\begin_inset Flex Alert +status collapsed + +\begin_layout Plain Layout +Here's the proof! +\end_layout + +\end_inset + + (This text is only shown on sub-slide 3 which is itself only shown when this frame is repeated later on) +\end_layout + +\end_deeper +\begin_layout Standard + +\begin_inset Separator plain + +\end_inset + + +\end_layout + +\begin_layout Frame + +\begin_inset Argument 4 +status collapsed + + +\begin_layout Standard +Keeping frames together +\end_layout + +\end_inset + + +\end_layout + +\begin_deeper +\begin_layout FrameSubtitle +Use nesting! +\end_layout + +\end_deeper +\begin_deeper +\begin_layout Itemize +Note that all frame content, if the style is not +\begin_inset Flex Structure +status collapsed + +\begin_layout Plain Layout +Frame +\end_layout + +\end_inset + +, must be nested to the frame environment (via +\begin_inset Flex Alert +status collapsed + +\begin_layout Plain Layout +Edit →Increase List Depth +\end_layout + +\end_inset + + or +\family sans +Alt+Shift+Right +\family default +). This is done automatically if you insert new frame paragraphs. +\end_layout + +\begin_layout Itemize +Nested content is marked by a red bar in the margin of the LyX workarea +\end_layout + +\end_deeper +\begin_layout Itemize +Non-nested content (such as this) will also be displayed in the presentation (on a separate slide), but not properly aligned +\end_layout + +\begin_layout Itemize +So please avoid this +\end_layout + +\begin_layout Frame + +\begin_inset Argument 4 +status collapsed + + +\begin_layout Standard +Separating frames +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Frame +\noindent +Consecutive frames have to be separated from each other. This is done by means of the +\begin_inset Flex Structure +status collapsed + +\begin_layout Plain Layout +\noindent +Separator +\end_layout + +\end_inset + + inset, which can be produced by hitting return in an empty Standard paragraph right below the frame (see UserGuide, sec. +\begin_inset space ~ + +\end_inset + +3.4.6). +\end_layout + +\begin_deeper +\begin_layout Block + +\begin_inset Argument 2 +status collapsed + + +\begin_layout Standard +Tip +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Block +There is a simple and much more convenient way to start a new frame: Issue +\begin_inset Flex Alert +status collapsed + +\begin_layout Plain Layout +Insert →Separated Frame Below +\end_layout + +\end_inset + + ( +\family sans +undefiniert +\family default + if you are in a non-nested +\begin_inset Flex Structure +status collapsed + +\begin_layout Plain Layout +Frame +\end_layout + +\end_inset + + paragraph, or +\family sans +Alt+A Shift+Return +\family default +, respectively, if you are in a nested paragraph within the frame). If you are in the frame heading, +\begin_inset Flex Alert +status collapsed + +\begin_layout Plain Layout +Insert →Separated Frame Above +\end_layout + +\end_inset + + inserts a new, properly separated frame above the current one! +\end_layout + +\end_deeper +\begin_layout AgainFrame + +\begin_inset Argument 1 +status collapsed + + +\begin_layout Standard +3 +\end_layout + +\end_inset + +myframe +\end_layout + +\begin_layout Frame + +\begin_inset Argument 3 +status collapsed + + +\begin_layout Standard +plain +\end_layout + +\end_inset + + +\begin_inset Argument 4 +status collapsed + + +\begin_layout Standard +Special frame types +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Frame +LyX provides two special frame types: +\end_layout + +\begin_deeper +\begin_layout Enumerate + +\begin_inset Flex Structure +status collapsed + +\begin_layout Plain Layout +Frame (plain) +\end_layout + +\end_inset + + is a frame without a sidebar/header (such as this one). This is useful for slides with much content\SpecialChar breakableslash +wide tables +\end_layout + +\begin_layout Enumerate + +\begin_inset Flex Structure +status collapsed + +\begin_layout Plain Layout +Frame (fragile) +\end_layout + +\end_inset + + is to be used if the frame consists of +\begin_inset Quotes eld +\end_inset + +fragile +\begin_inset Quotes erd +\end_inset + + content, especially verbatim stuff such as program listings +\end_layout + +\end_deeper +\begin_layout Frame +If you want a fragile plain frame, pass the option +\begin_inset Quotes eld +\end_inset + +plain +\begin_inset Quotes erd +\end_inset + + to a fragile frame or the option +\begin_inset Quotes eld +\end_inset + +fragile +\begin_inset Quotes erd +\end_inset + + to a plain frame. +\end_layout + +\begin_layout Standard + +\begin_inset Separator plain + +\end_inset + + +\end_layout + +\begin_layout Frame + +\begin_inset Argument 4 +status collapsed + + +\begin_layout Standard +Re-arranging frames +\end_layout + +\end_inset + + +\end_layout + +\begin_deeper +\begin_layout Block + +\begin_inset Argument 2 +status collapsed + + +\begin_layout Standard +Tip +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Block +Did you know that you can easily move and re-arrange whole frames via the outliner ( +\begin_inset Flex Alert +status collapsed + +\begin_layout Plain Layout +View →Outline Pane +\end_layout + +\end_inset + +)? +\end_layout + +\begin_layout Block +Also, you can navigate to a specific frame via the +\begin_inset Flex Alert +status collapsed + +\begin_layout Plain Layout +Navigate +\end_layout + +\end_inset + + menu! +\end_layout + +\end_deeper +\begin_layout Section* + +\begin_inset Argument 1 +status collapsed + + +\begin_layout Standard +article +\end_layout + +\end_inset + +The overlay concept +\end_layout + +\begin_layout Frame + +\begin_inset Argument 4 +status collapsed + + +\begin_layout Standard +What are overlays? +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Frame +Basically, the overlay concept allows to change the slide content dynamically. You can uncover things/text piecewise, fade out content, highlight things, replace text, images etc. +\end_layout + +\begin_deeper +\begin_layout Pause + +\end_layout + +\end_deeper +\begin_deeper +\begin_layout Itemize + +\begin_inset Argument 1 +status collapsed + + +\begin_layout Standard ++- +\end_layout + +\end_inset + +Overlays are useful to build up slides as you speak +\end_layout + +\begin_layout Itemize +They help you to shift your audience's focus on specific things +\end_layout + +\begin_layout Itemize +And they help your audience to follow you +\end_layout + +\begin_layout Itemize +So use overlays! +\begin_inset Flex Flex:Alert +status collapsed + +\begin_layout Plain Layout + +\begin_inset Argument 1 +status collapsed + + +\begin_layout Standard +6 +\end_layout + +\end_inset + +Really, use them! +\end_layout + +\end_inset + + +\end_layout + +\end_deeper +\begin_layout Standard + +\begin_inset Separator plain + +\end_inset + + +\end_layout + +\begin_layout Frame + +\begin_inset Argument 4 +status collapsed + + +\begin_layout Standard +Overlay types +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Frame + +\begin_inset Flex Structure +status collapsed + +\begin_layout Plain Layout +Beamer +\end_layout + +\end_inset + + provides many different overlay types. The most important ones are: +\end_layout + +\begin_deeper +\begin_layout Description +Hidden +\begin_inset space ~ + +\end_inset + +content: Stuff that is completely invisible up to a point +\end_layout + +\begin_layout Description +Covered +\begin_inset space ~ + +\end_inset + +content: Stuff that is faded out (not completely invisible) +\end_layout + +\begin_layout Description +Highlighted +\begin_inset space ~ + +\end_inset + +content: Stuff that is somehow emphasized at a certain point +\end_layout + +\end_deeper +\begin_layout Frame +We give examples for these types in what follows, but begin with some general remarks on overlay possibilities +\end_layout + +\begin_layout Standard + +\begin_inset Separator plain + +\end_inset + + +\end_layout + +\begin_layout Frame + +\begin_inset Argument 4 +status collapsed + + +\begin_layout Standard +General overlay/action possibilities +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Frame +Many +\begin_inset Flex Structure +status collapsed + +\begin_layout Plain Layout +Beamer +\end_layout + +\end_inset + + elements provide overlay settings. Basically, you can define on which sub-slide(s) a given content appears ( +\begin_inset Quotes eld +\end_inset + +2 +\begin_inset Quotes erd +\end_inset + +, +\begin_inset Quotes eld +\end_inset + +2-4 +\begin_inset Quotes erd +\end_inset + +, +\begin_inset Quotes eld +\end_inset + +3- +\begin_inset Quotes erd +\end_inset + +, +\begin_inset Quotes eld +\end_inset + +1,3 +\begin_inset Quotes erd +\end_inset + + etc.), or in which output mode ( +\begin_inset Quotes eld +\end_inset + +presentation +\begin_inset Quotes erd +\end_inset + +, +\begin_inset Quotes eld +\end_inset + +article +\begin_inset Quotes erd +\end_inset + + etc.) +\end_layout + +\begin_deeper +\begin_layout Itemize +In LyX, these settings are generally accessible via +\begin_inset Flex Alert +status collapsed + +\begin_layout Plain Layout +Insert →Overlay Specifications +\end_layout + +\end_inset + + or +\begin_inset Flex Alert +status collapsed + +\begin_layout Plain Layout +Insert →Action Specifications +\end_layout + +\end_inset + + +\end_layout + +\end_deeper +\begin_deeper +\begin_layout Overprint + +\begin_inset Argument item:1 +status collapsed + + +\begin_layout Standard +2 +\end_layout + +\end_inset + + +\end_layout + +\begin_deeper +\begin_layout Definition + +\begin_inset Quotes eld +\end_inset + +Action +\begin_inset Quotes erd +\end_inset + + is a more general concept, which does not only include what we have called +\begin_inset Quotes eld +\end_inset + +overlays +\begin_inset Quotes erd +\end_inset + + ( +\begin_inset Quotes eld +\end_inset + +on which sub-slide[s] is this to be shown\SpecialChar breakableslash +hidden\SpecialChar breakableslash +highlighted +\begin_inset Quotes erd +\end_inset + +), but also tasks such as +\begin_inset Quotes eld +\end_inset + +only show this in the presentation, not on the handout +\begin_inset Quotes erd +\end_inset + + or +\begin_inset Quotes eld +\end_inset + +show this on the second screen only +\begin_inset Quotes erd +\end_inset + + (so-called +\begin_inset Quotes eld +\end_inset + +modes +\begin_inset Quotes erd +\end_inset + +). +\end_layout + +\end_deeper +\begin_layout Overprint + +\begin_inset Argument item:1 +status collapsed + + +\begin_layout Standard +3 +\end_layout + +\end_inset + + +\end_layout + +\begin_deeper +\begin_layout AlertBlock + +\begin_inset Argument 2 +status collapsed + + +\begin_layout Standard +Note to the \SpecialChar LaTeX + aficionados +\end_layout + +\end_inset + + +\end_layout + +\begin_layout AlertBlock +The mentioned overlay/action settings conform to those command/environment options embraced by +\begin_inset Flex Alert +status collapsed + +\begin_layout Plain Layout + +\begin_inset space \space{} + +\end_inset + +<\SpecialChar ldots +> +\end_layout + +\end_inset + + and +\begin_inset Flex Alert +status collapsed + +\begin_layout Plain Layout +[<\SpecialChar ldots +>] +\end_layout + +\end_inset + + in the \SpecialChar LaTeX + output. +\end_layout + +\begin_layout AlertBlock +Note that LyX adds those braces on export, so you must not enter them yourself. In other words, enter +\begin_inset Quotes eld +\end_inset + +1 +\begin_inset Quotes erd +\end_inset + + or +\begin_inset Quotes eld +\end_inset + ++- +\begin_inset Quotes erd +\end_inset + + to the overlay/action insets, not +\begin_inset Quotes eld +\end_inset + +<1> +\begin_inset Quotes erd +\end_inset + + or +\begin_inset Quotes eld +\end_inset + +[<+->] +\begin_inset Quotes erd +\end_inset + +! +\end_layout + +\end_deeper +\end_deeper +\begin_layout Standard + +\begin_inset Separator plain + +\end_inset + + +\end_layout + +\begin_layout Frame + +\begin_inset Argument 4 +status collapsed + + +\begin_layout Standard +An example +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Frame +Take for example a quote. In a +\begin_inset Flex Structure +status collapsed + +\begin_layout Plain Layout +Quote +\end_layout + +\end_inset + + environment, you can specify the overlay settings via +\begin_inset Flex Alert +status collapsed + +\begin_layout Plain Layout +Insert →Overlay Specifications +\end_layout + +\end_inset + +. If you do this and enter +\begin_inset Quotes eld +\end_inset + +2 +\begin_inset Quotes erd +\end_inset + +, the quote will only appear on (sub-)slide 2: +\end_layout + +\begin_deeper +\begin_layout Quote + +\begin_inset Argument 1 +status collapsed + + +\begin_layout Standard +2 +\end_layout + +\end_inset + +Fear no more the heat o +\begin_inset Quotes ers +\end_inset + + the sun +\end_layout + +\begin_layout Quote +Nor the furious winter +\begin_inset Quotes ers +\end_inset + +s rages +\end_layout + +\begin_layout Quote +Thou thy worldly task hast done +\end_layout + +\begin_layout Quote +Home art gone, and ta +\begin_inset Quotes ers +\end_inset + +en thy wages +\end_layout + +\end_deeper +\begin_layout Frame +This is how the concept works, basically. +\end_layout + +\begin_layout Standard + +\begin_inset Separator plain + +\end_inset + + +\end_layout + +\begin_layout Frame + +\begin_inset Argument 4 +status collapsed + + +\begin_layout Standard +Covering vs. hiding +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Frame +The difference between +\begin_inset Quotes eld +\end_inset + +covering +\begin_inset Quotes erd +\end_inset + + and +\begin_inset Quotes eld +\end_inset + +hiding +\begin_inset Quotes erd +\end_inset + + is that hidden content is treated as if it isn't there, while covered content is just covered (and the space is reserved). If we would have hidden the quote on the last slide and not covered, it would only have taken space on appearance: +\end_layout + +\begin_deeper +\begin_layout Quote + +\begin_inset Argument 1 +status collapsed + + +\begin_layout Standard +only@2 +\end_layout + +\end_inset + +Fear no more the heat o +\begin_inset Quotes ers +\end_inset + + the sun +\end_layout + +\begin_layout Quote +Nor the furious winter +\begin_inset Quotes ers +\end_inset + +s rages +\end_layout + +\begin_layout Quote +Thou thy worldly task hast done +\end_layout + +\begin_layout Quote +Home art gone, and ta +\begin_inset Quotes ers +\end_inset + +en thy wages +\end_layout + +\end_deeper +\begin_layout Frame +You can see how this text moves when the quote is un-hidden. +\end_layout + +\begin_layout Standard + +\begin_inset Separator plain + +\end_inset + + +\end_layout + +\begin_layout Frame + +\begin_inset Argument 4 +status collapsed + + +\begin_layout Standard +Coverage degrees +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Frame + +\begin_inset ERT +status collapsed + +\begin_layout Plain Layout + +\backslash +setbeamercovered +\end_layout + +\end_inset + + +\begin_inset ERT +status collapsed + +\begin_layout Plain Layout +{ +\end_layout + +\end_inset + +transparent +\begin_inset ERT +status collapsed + +\begin_layout Plain Layout +} +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Frame + +\begin_inset Flex Structure +status collapsed + +\begin_layout Plain Layout +Beamer +\end_layout + +\end_inset + + offers several degrees of +\begin_inset Quotes eld +\end_inset + +coverage +\begin_inset Quotes erd +\end_inset + +, which can be set via the command +\begin_inset Flex Alert +status collapsed + +\begin_layout Plain Layout + +\backslash +setbeamercovered +\end_layout + +\end_inset + + either globally (for the whole presentation) or locally (e. +\begin_inset space \thinspace{} + +\end_inset + +g. for a single frame, as here). By default, content is completely covered. In +\begin_inset Quotes eld +\end_inset + +transparent +\begin_inset Quotes erd +\end_inset + + mode, you can see covered text greyed-out: +\end_layout + +\begin_deeper +\begin_layout Quote + +\begin_inset Argument 1 +status collapsed + + +\begin_layout Standard +2 +\end_layout + +\end_inset + +Fear no more the heat o +\begin_inset Quotes ers +\end_inset + + the sun +\end_layout + +\begin_layout Quote +Nor the furious winter +\begin_inset Quotes ers +\end_inset + +s rages +\end_layout + +\begin_layout Quote +Thou thy worldly task hast done +\end_layout + +\begin_layout Quote +Home art gone, and ta +\begin_inset Quotes ers +\end_inset + +en thy wages +\end_layout + +\end_deeper +\begin_layout Frame +Check the +\begin_inset Flex Structure +status collapsed + +\begin_layout Plain Layout +Beamer +\end_layout + +\end_inset + + manual for more possibilities. +\end_layout + +\begin_layout Standard + +\begin_inset Separator plain + +\end_inset + + +\end_layout + +\begin_layout Frame + +\begin_inset Argument 4 +status collapsed + + +\begin_layout Standard +Default overlay/action specifications vs. +\begin_inset Newline newline +\end_inset + + (normal) overlay/action specifications +\end_layout + +\end_inset + + +\end_layout + +\begin_deeper +\begin_layout Itemize +For some environments (such as lists and also frames), you can set +\begin_inset Quotes eld +\end_inset + +default specifications +\begin_inset Quotes erd +\end_inset + + additionally to normal overlay/action specifications (or in the case of lists: +\begin_inset Quotes eld +\end_inset + +overlay specifications +\begin_inset Quotes erd +\end_inset + + for the whole list and +\begin_inset Quotes eld +\end_inset + +item overlay specifications +\begin_inset Quotes erd +\end_inset + + for singular items) +\end_layout + +\begin_layout Itemize +Default specifications apply to all content of the given environment, if not individually specified otherwise +\end_layout + +\begin_layout Itemize +They use a placeholder syntax. E. +\begin_inset space \thinspace{} + +\end_inset + +g., +\begin_inset Quotes eld +\end_inset + ++(1)- +\begin_inset Quotes erd +\end_inset + + will uncover all items in a list step by step (with a start offset of 1) if they have no individual item specification: +\end_layout + +\begin_deeper +\begin_layout Itemize + +\begin_inset Argument 1 +status collapsed + + +\begin_layout Standard ++(1)- +\end_layout + +\end_inset + +One +\end_layout + +\begin_layout Itemize +Two +\end_layout + +\begin_layout Itemize +Three +\end_layout + +\begin_layout Itemize + +\begin_inset Argument item:2 +status collapsed + + +\begin_layout Standard +1- +\end_layout + +\end_inset + +Always +\end_layout + +\end_deeper +\end_deeper +\begin_layout Frame +Please consult the +\begin_inset Flex Structure +status collapsed + +\begin_layout Plain Layout +Beamer +\end_layout + +\end_inset + + manual for details on this syntax. +\end_layout + +\begin_layout Standard + +\begin_inset Separator plain + +\end_inset + + +\end_layout + +\begin_layout Frame + +\begin_inset Argument 2 +status collapsed + + +\begin_layout Standard ++- +\end_layout + +\end_inset + + +\begin_inset Argument 4 +status collapsed + + +\begin_layout Standard +Default overlay/action specifications vs. +\begin_inset Newline newline +\end_inset + + (normal) overlay/action specifications +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Frame +\noindent +This frame uses a specific default overlay specification +\end_layout + +\begin_layout Frame +which causes each overlay-aware paragraph \SpecialChar ldots + +\end_layout + +\begin_deeper +\begin_layout Itemize +\SpecialChar ldots + or list item \SpecialChar ldots + +\end_layout + +\begin_layout Itemize +\SpecialChar ldots + to appear \SpecialChar ldots + +\end_layout + +\begin_layout Itemize +\SpecialChar ldots + on a subsequent sub-slide \SpecialChar ldots + +\end_layout + +\end_deeper +\begin_deeper +\begin_layout Block + +\begin_inset Argument 2 +status collapsed + + +\begin_layout Standard +A block +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Block +\SpecialChar ldots + one after the other +\end_layout + +\end_deeper +\begin_layout Standard + +\begin_inset Separator plain + +\end_inset + + +\end_layout + +\begin_layout Frame + +\begin_inset Argument 2 +status collapsed + + +\begin_layout Standard +alert@+ +\end_layout + +\end_inset + + +\begin_inset Argument 4 +status collapsed + + +\begin_layout Standard +Default overlay/action specifications vs. +\begin_inset Newline newline +\end_inset + + (normal) overlay/action specifications +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Frame +\noindent +And this frame uses a specific default overlay specification \SpecialChar ldots + +\end_layout + +\begin_deeper +\begin_layout Itemize +\SpecialChar ldots + which causes each overlay-aware list item \SpecialChar ldots + +\end_layout + +\begin_layout Itemize +\SpecialChar ldots + to be highlighted \SpecialChar ldots + +\end_layout + +\begin_layout Itemize +\SpecialChar ldots + on respective sub-slides +\end_layout + +\end_deeper +\begin_layout Standard + +\begin_inset Separator plain + +\end_inset + + +\end_layout + +\begin_layout Frame + +\begin_inset Argument 4 +status collapsed + + +\begin_layout Standard +Pause +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Frame +The +\begin_inset Flex Structure +status collapsed + +\begin_layout Plain Layout +Pause +\end_layout + +\end_inset + + layout lets you mark a point where all following content will be covered (by default for one slide, with regard to the content preceding the pause): +\end_layout + +\begin_deeper +\begin_layout Pause + +\end_layout + +\end_deeper +\begin_layout Frame +After first pause +\end_layout + +\begin_deeper +\begin_layout Pause + +\end_layout + +\end_deeper +\begin_layout Frame +After second pause +\end_layout + +\begin_deeper +\begin_layout Pause + +\begin_inset Argument 1 +status collapsed + + +\begin_layout Standard +2 +\end_layout + +\end_inset + + +\end_layout + +\end_deeper +\begin_layout Frame +By default, consecutive pauses also end consecutively. +\end_layout + +\begin_layout Frame +Via +\begin_inset Flex Alert +status collapsed + +\begin_layout Plain Layout +Insert →Pause Number +\end_layout + +\end_inset + +, however, you can specify a specific sub-slide at which the given pause ends, independent from the number of pauses inserted before this one. +\end_layout + +\begin_layout Standard + +\begin_inset Separator plain + +\end_inset + + +\end_layout + +\begin_layout Frame + +\begin_inset Argument 4 +status collapsed + + +\begin_layout Standard +Paragraph-wide overlays +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Frame + +\begin_inset Flex Structure +status collapsed + +\begin_layout Plain Layout +Beamer +\end_layout + +\end_inset + + and LyX provide you with paragraph layouts whose purpose it is to show/hide whole paragraphs or sequences of paragraphs on specific slides. These are particularly: +\end_layout + +\begin_deeper +\begin_layout Uncover + +\begin_inset Argument 1 +status collapsed + + +\begin_layout Standard +2- +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Uncover +The +\begin_inset Flex Structure +status collapsed + +\begin_layout Plain Layout +Uncovered +\end_layout + +\end_inset + + layout which uncovers all content on the specified slides \SpecialChar ldots + +\end_layout + +\begin_deeper +\begin_layout Itemize +\SpecialChar ldots + including nested paragraphs of other layout. +\end_layout + +\end_deeper +\end_deeper +\begin_deeper +\begin_layout Only + +\begin_inset Argument 1 +status collapsed + + +\begin_layout Standard +3- +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Only +The +\begin_inset Flex Structure +status collapsed + +\begin_layout Plain Layout +Only +\end_layout + +\end_inset + + layout which un-hides content (note again how the surrounding text +\begin_inset Quotes eld +\end_inset + +moves +\begin_inset Quotes erd +\end_inset + + when this gets visible). +\end_layout + +\end_deeper +\begin_deeper +\begin_layout Overprint + +\begin_inset Argument item:1 +status collapsed + + +\begin_layout Standard +4 +\end_layout + +\end_inset + + +\end_layout + +\begin_deeper +\begin_layout Standard +And the +\begin_inset Flex Structure +status collapsed + +\begin_layout Plain Layout +Overprint +\end_layout + +\end_inset + + environment which lets you enter \SpecialChar ldots + +\end_layout + +\end_deeper +\begin_layout Overprint + +\begin_inset Argument item:1 +status collapsed + + +\begin_layout Standard +5 +\end_layout + +\end_inset + + +\end_layout + +\begin_deeper +\begin_layout Standard +\SpecialChar ldots + alternative text taking a specific space on specified slides. +\end_layout + +\end_deeper +\end_deeper +\begin_layout Frame +as demonstrated here. +\end_layout + +\begin_layout Standard + +\begin_inset Separator plain + +\end_inset + + +\end_layout + +\begin_layout Frame + +\begin_inset Argument 4 +status collapsed + + +\begin_layout Standard +Inline overlays +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Frame + +\begin_inset ERT +status collapsed + +\begin_layout Plain Layout + +\backslash +setbeamercovered +\end_layout + +\end_inset + + +\begin_inset ERT +status collapsed + +\begin_layout Plain Layout +{ +\end_layout + +\end_inset + +transparent +\begin_inset ERT +status collapsed + +\begin_layout Plain Layout +} +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Frame + +\begin_inset Flex Structure +status collapsed + +\begin_layout Plain Layout +Beamer +\end_layout + +\end_inset + + also supports inline overlays for text parts (as opposed to whole paragraphs), which are accessible via +\begin_inset Flex Alert +status collapsed + +\begin_layout Plain Layout +Edit →Text Style +\end_layout + +\end_inset + + in LyX: +\end_layout + +\begin_deeper +\begin_layout Itemize +You can +\begin_inset Flex Structure +status collapsed + +\begin_layout Plain Layout +uncover +\end_layout + +\end_inset + + +\begin_inset Flex Flex:Uncover +status collapsed + +\begin_layout Plain Layout + +\begin_inset Argument 1 +status collapsed + + +\begin_layout Standard +2- +\end_layout + +\end_inset + +text +\end_layout + +\end_inset + + on specific slides +\end_layout + +\begin_layout Itemize +You can make +\begin_inset Flex Flex:Visible +status collapsed + +\begin_layout Plain Layout + +\begin_inset Argument 1 +status collapsed + + +\begin_layout Standard +3- +\end_layout + +\end_inset + +text +\end_layout + +\end_inset + + +\begin_inset Flex Structure +status collapsed + +\begin_layout Plain Layout +visible +\end_layout + +\end_inset + + (which makes a difference to +\begin_inset Quotes eld +\end_inset + +uncover +\begin_inset Quotes erd +\end_inset + + only with +\begin_inset Quotes eld +\end_inset + +transparent +\begin_inset Quotes erd +\end_inset + + coverage setting, as used locally on this slide) +\end_layout + +\begin_layout Itemize +You can show +\begin_inset Flex Flex:Only +status collapsed + +\begin_layout Plain Layout + +\begin_inset Argument 1 +status collapsed + + +\begin_layout Standard +4- +\end_layout + +\end_inset + +text +\end_layout + +\end_inset + + +\begin_inset Flex Structure +status collapsed + +\begin_layout Plain Layout +only +\end_layout + +\end_inset + + on specific slides +\end_layout + +\begin_layout Itemize +You can make +\begin_inset Flex Flex:Invisible +status collapsed + +\begin_layout Plain Layout + +\begin_inset Argument 1 +status collapsed + + +\begin_layout Standard +5- +\end_layout + +\end_inset + +text +\end_layout + +\end_inset + + +\begin_inset Flex Structure +status collapsed + +\begin_layout Plain Layout +invisible +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Itemize +And you can show +\begin_inset Flex Flex:Alternative +status collapsed + +\begin_layout Plain Layout + +\begin_inset Argument 1 +status collapsed + + +\begin_layout Standard +6- +\end_layout + +\end_inset + + +\begin_inset Argument 2 +status collapsed + + +\begin_layout Standard +different +\end_layout + +\end_inset + + +\begin_inset Flex Structure +status collapsed + +\begin_layout Plain Layout +alternative +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + text +\end_layout + +\end_deeper +\begin_layout Frame +As for the paragraph layouts, the overlay settings can be accessed via the +\begin_inset Flex Alert +status collapsed + +\begin_layout Plain Layout +Insert +\end_layout + +\end_inset + + menu. +\end_layout + +\begin_layout Standard + +\begin_inset Separator plain + +\end_inset + + +\end_layout + +\begin_layout Frame + +\begin_inset Argument 4 +status collapsed + + +\begin_layout Standard +Overlay-aware commands +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Frame +Many +\begin_inset Quotes eld +\end_inset + +inline +\begin_inset Quotes erd +\end_inset + + commands (also to be found at +\begin_inset Flex Alert +status collapsed + +\begin_layout Plain Layout +Edit →Text Style +\end_layout + +\end_inset + +) are overlay-aware. +\end_layout + +\begin_deeper +\begin_layout Itemize +Thus, you can make for instance text on specific slides +\begin_inset Flex Flex:Emphasize +status collapsed + +\begin_layout Plain Layout + +\begin_inset Argument 1 +status collapsed + + +\begin_layout Standard +2 +\end_layout + +\end_inset + +emphasized +\end_layout + +\end_inset + +, +\begin_inset Flex Flex:Bold +status collapsed + +\begin_layout Plain Layout + +\begin_inset Argument 1 +status collapsed + + +\begin_layout Standard +3 +\end_layout + +\end_inset + +bold +\end_layout + +\end_inset + +, shown in +\begin_inset Flex Flex:Alert +status collapsed + +\begin_layout Plain Layout + +\begin_inset Argument 1 +status collapsed + + +\begin_layout Standard +4 +\end_layout + +\end_inset + +alert +\end_layout + +\end_inset + + or +\begin_inset Flex Flex:Structure +status collapsed + +\begin_layout Plain Layout + +\begin_inset Argument 1 +status collapsed + + +\begin_layout Standard +5 +\end_layout + +\end_inset + +structure +\end_layout + +\end_inset + + color. +\end_layout + +\end_deeper +\begin_deeper +\begin_layout Block + +\begin_inset Argument 1 +status collapsed + + +\begin_layout Standard +6 +\end_layout + +\end_inset + + +\begin_inset Argument 2 +status collapsed + + +\begin_layout Standard +Tip +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Block +Use these Emphasize and Bold insets (instead of the usual respective font settings) also if you do not need overlay specifications. Due to the way emphasized and bold is defined in +\begin_inset Flex Structure +status collapsed + +\begin_layout Plain Layout +Beamer +\end_layout + +\end_inset + +, normal emphasizing and boldface can lead to \SpecialChar LaTeX + errors, e. +\begin_inset space \thinspace{} + +\end_inset + +g. when used in section headings. +\end_layout + +\end_deeper +\begin_layout Section +Specific environments +\end_layout + +\begin_layout Frame + +\begin_inset Argument 4 +status collapsed + + +\begin_layout Standard +Specific environments +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Frame +Specific environments, particularly suited for presentations are: +\end_layout + +\begin_deeper +\begin_layout Itemize +Diverse +\begin_inset Quotes eld +\end_inset + +blocks +\begin_inset Quotes erd +\end_inset + + +\end_layout + +\begin_layout Itemize +Theorem-style environments +\end_layout + +\begin_layout Itemize +Columns +\end_layout + +\end_deeper +\begin_layout Frame +We sketch them briefly in what follows. +\end_layout + +\begin_layout Standard + +\begin_inset Separator plain + +\end_inset + + +\end_layout + +\begin_layout Frame + +\begin_inset Argument 4 +status collapsed + + +\begin_layout Standard +Blocks +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Frame +Blocks can contain all sorts of information. We used them here for +\begin_inset Quotes eld +\end_inset + +tips +\begin_inset Quotes erd +\end_inset + + and +\begin_inset Quotes eld +\end_inset + +hints +\begin_inset Quotes erd +\end_inset + +. The class provides 3 pre-defined blocks with different look: +\end_layout + +\begin_deeper +\begin_layout Block + +\begin_inset Argument 1 +status collapsed + + +\begin_layout Standard +2- +\end_layout + +\end_inset + + +\begin_inset Argument 2 +status collapsed + + +\begin_layout Standard +Block +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Block +A general-purpose block +\end_layout + +\end_deeper +\begin_deeper +\begin_layout ExampleBlock + +\begin_inset Argument 1 +status collapsed + + +\begin_layout Standard +3- +\end_layout + +\end_inset + + +\begin_inset Argument 2 +status collapsed + + +\begin_layout Standard +Example Block +\end_layout + +\end_inset + + +\end_layout + +\begin_layout ExampleBlock +A block for +\begin_inset Quotes eld +\end_inset + +examples +\begin_inset Quotes erd +\end_inset + + +\end_layout + +\end_deeper +\begin_deeper +\begin_layout AlertBlock + +\begin_inset Argument 1 +status collapsed + + +\begin_layout Standard +4- +\end_layout + +\end_inset + + +\begin_inset Argument 2 +status collapsed + + +\begin_layout Standard +Alert Block +\end_layout + +\end_inset + + +\end_layout + +\begin_layout AlertBlock +And an +\begin_inset Quotes eld +\end_inset + +alert +\begin_inset Quotes erd +\end_inset + + block for important remarks. +\end_layout + +\end_deeper +\begin_layout Standard + +\begin_inset Separator plain + +\end_inset + + +\end_layout + +\begin_layout Frame + +\begin_inset Argument 4 +status collapsed + + +\begin_layout Standard +Handling Blocks +\end_layout + +\end_inset + + +\end_layout + +\begin_deeper +\begin_layout Itemize +In LyX, blocks have a similar user interface to frames, which means that +\end_layout + +\begin_deeper +\begin_layout Itemize +Content inside blocks needs to be nested (if the paragraph layout is not +\begin_inset Flex Structure +status collapsed + +\begin_layout Plain Layout +Block +\end_layout + +\end_inset + +) +\end_layout + +\begin_layout Itemize +Consecutive blocks of the same type must be separated by the +\begin_inset Flex Structure +status collapsed + +\begin_layout Plain Layout +Separator +\end_layout + +\end_inset + + paragraph style +\end_layout + +\begin_deeper +\begin_layout Block + +\begin_inset Argument 1 +status collapsed + + +\begin_layout Standard +only@2 +\end_layout + +\end_inset + + +\begin_inset Argument 2 +status collapsed + + +\begin_layout Standard +Tip +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Block +Use +\begin_inset Flex Alert +status collapsed + +\begin_layout Plain Layout +Edit →Start New Environment +\end_layout + +\end_inset + + ( +\family sans +undefiniert +\family default +) to quickly start a new block from within a previous block! +\end_layout + +\end_deeper +\end_deeper +\begin_layout Itemize +Blocks are overlay-aware +\end_layout + +\end_deeper +\begin_layout Standard + +\begin_inset Separator plain + +\end_inset + + +\end_layout + +\begin_layout Frame + +\begin_inset Argument 4 +status collapsed + + +\begin_layout Standard +Theorem-style environments +\end_layout + +\end_inset + + +\end_layout + +\begin_deeper +\begin_layout FrameSubtitle +(Theorem, Corollary, Definition, Definitions, Example, Examples, Fact, Proof) +\end_layout + +\end_deeper +\begin_layout Frame +Theorems look similar to blocks in the output, but they have a fixed title (depending on the type). +\end_layout + +\begin_deeper +\begin_layout Theorem +This is a theorem! +\end_layout + +\end_deeper +\begin_deeper +\begin_layout Fact +This is a fact! +\end_layout + +\end_deeper +\begin_deeper +\begin_layout Pause + +\end_layout + +\end_deeper +\begin_layout Frame +Via +\begin_inset Flex Alert +status collapsed + +\begin_layout Plain Layout +Insert →Additional Theorem Text +\end_layout + +\end_inset + +, you can add some extra text to this fixed title +\end_layout + +\begin_deeper +\begin_layout Example + +\begin_inset Argument 2 +status collapsed + + +\begin_layout Standard +a bad one! +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Example +An example with additional text (brackets added automatically) +\end_layout + +\end_deeper +\begin_layout Standard + +\begin_inset Separator plain + +\end_inset + + +\end_layout + +\begin_layout Frame + +\begin_inset Argument 4 +status collapsed + + +\begin_layout Standard +Columns +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Frame +Sometimes it is useful to divide a presentation into columns +\end_layout + +\begin_deeper +\begin_layout Columns + +\begin_inset Argument 1 +status collapsed + + +\begin_layout Standard +t +\end_layout + +\end_inset + + +\end_layout + +\begin_deeper +\begin_layout Column +.4 +\begin_inset ERT +status collapsed + +\begin_layout Plain Layout + +\backslash +textwidth +\end_layout + +\end_inset + + +\end_layout + +\end_deeper +\begin_layout Columns +To do this, first select +\begin_inset Flex Structure +status collapsed + +\begin_layout Plain Layout +Columns +\end_layout + +\end_inset + + (note the plural) to start the columns +\end_layout + +\begin_deeper +\begin_layout Pause + +\end_layout + +\end_deeper +\begin_deeper +\begin_layout Column +.4 +\begin_inset ERT +status collapsed + +\begin_layout Plain Layout + +\backslash +textwidth +\end_layout + +\end_inset + + +\end_layout + +\end_deeper +\begin_layout Columns +And then, in the following paragraph, select +\begin_inset Flex Structure +status collapsed + +\begin_layout Plain Layout +Column +\end_layout + +\end_inset + + (singular) to start a specific column +\end_layout + +\end_deeper +\begin_deeper +\begin_layout Pause + +\end_layout + +\end_deeper +\begin_layout Frame + +\begin_inset VSpace medskip +\end_inset + + +\end_layout + +\begin_layout Frame +Note: +\end_layout + +\begin_deeper +\begin_layout Itemize +In the +\begin_inset Flex Structure +status collapsed + +\begin_layout Plain Layout +Column +\end_layout + +\end_inset + + (singular) environment, you need to specify the width using \SpecialChar LaTeX + syntax (but also something like +\begin_inset Quotes eld +\end_inset + +3.5cm +\begin_inset Quotes erd +\end_inset + + will work) +\end_layout + +\begin_layout Itemize +Any (singular) +\begin_inset Flex Structure +status collapsed + +\begin_layout Plain Layout +Column +\end_layout + +\end_inset + + must be nested to the (plural) +\begin_inset Flex Structure +status collapsed + +\begin_layout Plain Layout +Columns +\end_layout + +\end_inset + +. Likewise, column content can be any paragraph style that is nested to a singular +\begin_inset Flex Structure +status collapsed + +\begin_layout Plain Layout +Column +\end_layout + +\end_inset + + +\end_layout + +\end_deeper +\begin_layout Section +Short remarks on modes +\end_layout + +\begin_layout Frame + +\begin_inset Argument 4 +status collapsed + + +\begin_layout Standard +Modes +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Frame +In +\begin_inset Flex Structure +status collapsed + +\begin_layout Plain Layout +Beamer +\end_layout + +\end_inset + + terms, a +\begin_inset Quotes eld +\end_inset + +mode +\begin_inset Quotes erd +\end_inset + + is a specific output route. There are several modes for different purposes. We just want to highlight three: +\end_layout + +\begin_deeper +\begin_layout Enumerate +The +\begin_inset Quotes eld +\end_inset + +beamer +\begin_inset Quotes erd +\end_inset + + mode +\end_layout + +\begin_layout Enumerate +The +\begin_inset Quotes eld +\end_inset + +presentation +\begin_inset Quotes erd +\end_inset + + mode +\end_layout + +\begin_layout Enumerate +The +\begin_inset Quotes eld +\end_inset + +article +\begin_inset Quotes erd +\end_inset + + mode +\end_layout + +\end_deeper +\begin_layout Frame +The beamer mode is the default. Unless explicitly specified otherwise, your +\begin_inset Flex Structure +status collapsed + +\begin_layout Plain Layout +Beamer +\end_layout + +\end_inset + + document is in +\begin_inset Quotes eld +\end_inset + +beamer +\begin_inset Quotes erd +\end_inset + + mode. +\end_layout + +\begin_layout Standard + +\begin_inset Separator plain + +\end_inset + + +\end_layout + +\begin_layout Frame + +\begin_inset Argument 1 +status collapsed + + +\begin_layout Standard +presentation +\end_layout + +\end_inset + + +\begin_inset Argument 4 +status collapsed + + +\begin_layout Standard +Switching Modes +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Frame +However, you can switch document parts, frames, headings and all +\begin_inset Quotes eld +\end_inset + +action +\begin_inset Quotes erd +\end_inset + +-aware environments to a different mode. For instance, we have switched this frame to +\begin_inset Quotes eld +\end_inset + +presentation +\begin_inset Quotes erd +\end_inset + + mode. +\end_layout + +\begin_deeper +\begin_layout Itemize +What does this mean? +\end_layout + +\begin_deeper +\begin_layout Itemize +It means that this frame will only be visible in the presentation, not in the accompanying +\begin_inset Quotes eld +\end_inset + +article +\begin_inset Quotes erd +\end_inset + +, if you produce such an article (we will elaborate on this a bit below) +\end_layout + +\end_deeper +\end_deeper +\begin_layout Standard + +\begin_inset Separator plain + +\end_inset + + +\end_layout + +\begin_layout Frame + +\begin_inset Argument 1 +status collapsed + + +\begin_layout Standard +article +\end_layout + +\end_inset + + +\begin_inset Argument 4 +status collapsed + + +\begin_layout Standard +Switching Modes +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Frame +This frame will not be visible in the presentation, but only in the article, since it is in +\begin_inset Quotes eld +\end_inset + +article +\begin_inset Quotes erd +\end_inset + + mode. +\end_layout + +\begin_layout Standard + +\begin_inset Separator plain + +\end_inset + + +\end_layout + +\begin_layout Frame + +\begin_inset Argument 4 +status collapsed + + +\begin_layout Standard +So what? +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Frame +This is actually pretty useful! You can set up a single document and produce both a presentation and – using the article mode – a handout. +\end_layout + +\begin_deeper +\begin_layout Itemize +And we mean a +\emph on +real +\emph default +, useful handout, not one of those scaled slide printouts that are so common nowadays (but if you insist, you can produce one of those as well) +\end_layout + +\begin_layout Itemize +Modes allow you to add extra text to the handout or hide parts from it +\end_layout + +\begin_layout Itemize +You can use for instance different graphics for the presentation and the handout +\end_layout + +\begin_layout Itemize +and so on \SpecialChar ldots + +\end_layout + +\end_deeper +\begin_layout Standard + +\begin_inset Separator plain + +\end_inset + + +\end_layout + +\begin_layout Frame + +\begin_inset Argument 4 +status collapsed + + +\begin_layout Standard +Examples +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Frame +As said, many elements are mode-aware. +\end_layout + +\begin_deeper +\begin_layout Itemize +You can show particular text +\begin_inset Flex Flex:Only +status collapsed + +\begin_layout Plain Layout + +\begin_inset Argument 1 +status collapsed + + +\begin_layout Standard +presentation +\end_layout + +\end_inset + +only in the presentation +\end_layout + +\end_inset + + +\begin_inset Flex Flex:Only +status collapsed + +\begin_layout Plain Layout + +\begin_inset Argument 1 +status collapsed + + +\begin_layout Standard +article +\end_layout + +\end_inset + +only in the article +\end_layout + +\end_inset + + via +\begin_inset Flex Alert +status collapsed + +\begin_layout Plain Layout +\noindent +Edit →Text Style →Only +\end_layout + +\end_inset + + +\end_layout + +\end_deeper +\begin_layout Frame + +\begin_inset Flex ArticleMode +status collapsed + +\begin_layout Itemize +Or put all sorts of complex contents via +\begin_inset Flex Alert +status collapsed + +\begin_layout Plain Layout +Insert →Custom Insets →ArticleMode +\end_layout + +\end_inset + + in an inset that will only be output in article mode +\end_layout + +\end_inset + + +\begin_inset Flex PresentationMode +status collapsed + +\begin_layout Itemize +Or put all sorts of complex contents via +\begin_inset Flex Alert +status collapsed + +\begin_layout Plain Layout +Insert →Custom Insets →PresentationMode +\end_layout + +\end_inset + + in an inset that will only be output in presentation mode +\end_layout + +\end_inset + + +\end_layout + +\begin_deeper +\begin_layout Itemize +Or you can define that an +\begin_inset Flex Flex:Emphasize +status collapsed + +\begin_layout Plain Layout + +\begin_inset Argument 1 +status collapsed + + +\begin_layout Standard +presentation +\end_layout + +\end_inset + +emphasizing +\end_layout + +\end_inset + + should only apply to the presentation, +\begin_inset Flex Flex:Bold +status collapsed + +\begin_layout Plain Layout + +\begin_inset Argument 1 +status collapsed + + +\begin_layout Standard +article +\end_layout + +\end_inset + +a bold face +\end_layout + +\end_inset + + only to article +\end_layout + +\begin_layout Itemize +You can also show section headings or frame titles\SpecialChar breakableslash +subtitles only in the presentation\SpecialChar breakableslash +article (like we do for the +\begin_inset Quotes eld +\end_inset + +Contents +\begin_inset Quotes erd +\end_inset + + and +\begin_inset Quotes eld +\end_inset + +References +\begin_inset Quotes erd +\end_inset + + frame titles in this presentation) +\end_layout + +\begin_layout Itemize +And much more of this sort \SpecialChar ldots + +\end_layout + +\end_deeper +\begin_layout Standard + +\begin_inset Separator plain + +\end_inset + + +\end_layout + +\begin_layout Frame + +\begin_inset Argument 4 +status collapsed + + +\begin_layout Standard +Setting up an article +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Frame +Setting up a beamer article with LyX is easy. +\end_layout + +\begin_deeper +\begin_layout Itemize +Just create a new document with the class +\begin_inset Flex Structure +status collapsed + +\begin_layout Plain Layout +\noindent +Beamer Article (Standard Class) +\end_layout + +\end_inset + + or +\begin_inset Flex Structure +status collapsed + +\begin_layout Plain Layout +\noindent +Beamer Article (KOMA-Script) +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Itemize +Then add the presentation to this document as a child (via +\begin_inset Flex Alert +status collapsed + +\begin_layout Plain Layout +Insert →File →Child Document\SpecialChar ldots + +\end_layout + +\end_inset + +) +\end_layout + +\begin_layout Itemize +And that's it. Now you can produce the handout and the presentation by compiling one of these two documents, while you only need to edit one, namely the presentation +\end_layout + +\end_deeper +\begin_layout Frame +Check out the accompanying beamer-article example document for this presentation. You can find it in the same folder as this document. +\end_layout + +\begin_layout Section +Changing the look +\end_layout + +\begin_layout Frame + +\begin_inset Argument 4 +status collapsed + + +\begin_layout Standard +Themes +\end_layout + +\end_inset + + +\end_layout + +\begin_deeper +\begin_layout Itemize + +\begin_inset Flex Structure +status collapsed + +\begin_layout Plain Layout +Beamer +\end_layout + +\end_inset + + presentations are themeable. Themes determine the colors used, the macro structure (use of sidebars, headlines etc.), the fonts, the look of list items, blocks and in general the whole look and feel of a presentation +\end_layout + +\begin_layout Itemize + +\begin_inset Flex Structure +status collapsed + +\begin_layout Plain Layout +Beamer +\end_layout + +\end_inset + + itself ships a number of different-looking themes to chose from (we use the +\begin_inset Quotes eld +\end_inset + +Berkeley +\begin_inset Quotes erd +\end_inset + + theme in this presentation; see +\begin_inset Flex Alert +status collapsed + +\begin_layout Plain Layout +Document →Settings →LaTeX +\begin_inset space ~ + +\end_inset + +Preamble +\end_layout + +\end_inset + + for how we activated and slightly tweaked the theme) +\end_layout + +\begin_layout Itemize +In addition to this standard set, you can get more themes from +\begin_inset CommandInset href +LatexCommand href +name "CTAN" +target "http://www.ctan.org" +literal "false" + +\end_inset + +and other places at the Internet +\end_layout + +\begin_layout Itemize +If you still are not satisified or if you need a theme matching to your University's or company's corporate design, the +\begin_inset Flex Structure +status collapsed + +\begin_layout Plain Layout +Beamer +\end_layout + +\end_inset + + manual +\begin_inset CommandInset citation +LatexCommand cite +after "" +key "beamer-ug" +literal "false" + +\end_inset + + explains how you can setup your own theme +\end_layout + +\end_deeper +\begin_layout Standard + +\begin_inset Separator plain + +\end_inset + + +\end_layout + +\begin_layout Frame + +\begin_inset Argument 4 +status collapsed + + +\begin_layout Standard +Themes can be modified +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Frame +But you do not need to write a theme from scratch if you want to alter the look. +\end_layout + +\begin_deeper +\begin_layout Itemize +Existing themes can be modified both in details and in major areas (such as the coloring) +\end_layout + +\begin_layout Itemize +Consult the +\begin_inset Flex Structure +status collapsed + +\begin_layout Plain Layout +Beamer +\end_layout + +\end_inset + + manual +\begin_inset CommandInset citation +LatexCommand cite +after "" +key "beamer-ug" +literal "false" + +\end_inset + + for details +\end_layout + +\end_deeper +\begin_layout Section +And more \SpecialChar ldots + +\end_layout + +\begin_layout Frame + +\begin_inset Argument 4 +status collapsed + + +\begin_layout Standard +\SpecialChar ldots + much more! +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Frame +Note that +\begin_inset Flex Structure +status collapsed + +\begin_layout Plain Layout +Beamer +\end_layout + +\end_inset + + can do much more than we have described here. The +\begin_inset Flex Structure +status collapsed + +\begin_layout Plain Layout +Beamer +\end_layout + +\end_inset + + manual +\begin_inset CommandInset citation +LatexCommand cite +after "" +key "beamer-ug" +literal "false" + +\end_inset + + provides a comprehensive documentation. +\end_layout + +\begin_layout Frame +Also, have a look at the +\begin_inset Flex Structure +status collapsed + +\begin_layout Plain Layout +Beamer +\end_layout + +\end_inset + + examples and templates shipped with LyX! +\end_layout + +\begin_layout Standard +\start_of_appendix + +\begin_inset ERT +status collapsed + +\begin_layout Plain Layout +%dummy comment inserted by tex2lyx to ensure that this paragraph is not empty +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Section +Appendix +\end_layout + +\begin_layout Frame + +\end_layout + +\begin_deeper +\begin_layout FrameTitle + +\begin_inset Argument 1 +status collapsed + + +\begin_layout Standard +presentation +\end_layout + +\end_inset + +References +\end_layout + +\end_deeper +\begin_deeper +\begin_layout Bibliography + +\begin_inset CommandInset bibitem +LatexCommand bibitem +label "" +key "beamer-ug" +literal "false" + +\end_inset + +Tantau, Till et al.: +\begin_inset ERT +status collapsed + +\begin_layout Plain Layout + +\backslash +newblock +\end_layout + +\end_inset + + The beamer class. +\begin_inset Flex URL +status collapsed + +\begin_layout Plain Layout +https://ctan.org/tex-archive/macros/latex/contrib/beamer/doc/beameruserguide.pdf +\end_layout + +\end_inset + +. +\end_layout + +\end_deeper +\end_body +\end_document diff --git a/src/tex2lyx/test/beamer.tex b/src/tex2lyx/test/beamer.tex new file mode 100644 index 0000000000..c5424fee4c --- /dev/null +++ b/src/tex2lyx/test/beamer.tex @@ -0,0 +1,706 @@ +\documentclass[english]{beamer} +\usepackage[T1]{fontenc} +\usepackage[latin9]{inputenc} + +\usepackage{babel} + +\usetheme[left,width=3.45em]{Berkeley} + +\begin{document} + +\title{Presentations with Beamer} + +\subtitle{An Introduction to the Basics} + +\author{John Doe} + +\date{Version~2.3} + +\maketitle + +\begin{frame} + +\frametitle{Contents} + +\tableofcontents +\end{frame} + +\section{Purposes} + +\begin{frame}[<+->]{Purpose of the Beamer class} + +With the \structure{Beamer} class, you can produce presentation slides, +which +\begin{itemize} +\item are visually highly customizable +\item can be very well structured +\item can be constructed step-by-step (``overlay'' concept) +\item may contain different navigation paths (note that the slides contain +all sorts of hyperlinks) +\item use \LaTeX 's superb output quality +\item might embed multimedia content (audio, video) +\item can easily be transformed to accompanying material (such as an article-like +handout) +\item and much more \ldots{} +\end{itemize} +\end{frame} + +\begin{frame}{Purpose of this presentation} + +This presentation +\begin{itemize}[<+->] +\item describes some basic features of \structure{Beamer} +\item especially how they can be used +\end{itemize} +For more general and comprehensive information on \structure{Beamer} +itself, please refer to the extensive class manual \cite{beamer-ug} +\end{frame} + +\section*{Segments of a presentation} + +\begin{frame}{The global structure} + +A presentation usually consists of +\begin{itemize} +\item<+-> a title page +\item<+-> slides that might be grouped to sections/parts +\item[extra]<+-> an appendix with additional information, such as a bibliography +\end{itemize} +We describe these global segments in what follows. +\end{frame} + +\begin{frame}{The title page} + +A title page is constructed by the layouts \structure{Title}, +\structure{Subtitle}, \structure<2>{Author}, \structure{Institute}, +\structure{Date} and \structure{TitleGraphic}. +\begin{itemize} +\item None of these elements is mandatory, but at least one must be given +\item The order of insertion does not matter (the real order is defined +in the \structure{Beamer} theme) +\item For \structure{Title}, \structure{Subtitle}, \structure{Author}, +\structure{Institute} and \structure{Date}, you can define ``short'' +forms via \alert{Insert \textrightarrow Short Title\slash Date\slash\ldots} +These are used in the sidebar\slash heading (given the theme actually +provides a sidebar\slash heading) +\item If you select \structure{Title (Plain Frame)} instead of \structure{Title}, +the title page will have no sidebar or heading +\end{itemize} +\end{frame} + +\begin{frame}<1-2>[label=myframe]{Frames can be repeated} + +Frames can be repeated fully or only in terms of selected sub-slides, +multiple times at any later point of the presentation. + +You just need to give the respective frame a label name via the frame +option ``label'' (as done here). + +\pause{} + +Then you can repeat this frame by means of the \structure{AgainFrame} +layout later in the presentation. Just enter the label name in the +\structure{AgainFrame} layout and specify, if required, which sub-slides +you want to be repeated via \alert{Insert \textrightarrow Overlay Specifications} +(again, see below for the concept of ``overlays''). +\begin{proof}<3> +\alert{Here's the proof!} (This text is only shown on sub-slide +3 which is itself only shown when this frame is repeated later on) +\end{proof} + +\end{frame} + +\begin{frame}{Keeping frames together} + +\framesubtitle{Use nesting!} +\begin{itemize} +\item Note that all frame content, if the style is not \structure{Frame}, +must be nested to the frame environment (via \alert{Edit \textrightarrow Increase List Depth} +or \textsf{Alt+Shift+Right}). This is done automatically if you +insert new frame paragraphs. +\item Nested content is marked by a red bar in the margin of the LyX workarea +\end{itemize} +\end{frame} +\begin{itemize} +\item Non-nested content (such as this) will also be displayed in the presentation +(on a separate slide), but not properly aligned +\item So please avoid this +\end{itemize} + +\begin{frame}{Separating frames} + +\noindent Consecutive frames have to be separated from each other. +This is done by means of the \structure{\noindent Separator} inset, +which can be produced by hitting return in an empty Standard paragraph +right below the frame (see UserGuide, sec.~3.4.6). +\begin{block}{Tip} + +There is a simple and much more convenient way to start a new frame: +Issue \alert{Insert \textrightarrow Separated Frame Below} (\textsf{undefiniert} +if you are in a non-nested \structure{Frame} paragraph, or \textsf{Alt+A Shift+Return}, +respectively, if you are in a nested paragraph within the frame). +If you are in the frame heading, \alert{Insert \textrightarrow Separated Frame Above} +inserts a new, properly separated frame above the current one! +\end{block} +\end{frame} + +\againframe<3>{myframe} + +\begin{frame}[plain]{Special frame types} + +LyX provides two special frame types: +\begin{enumerate} +\item \structure{Frame (plain)} is a frame without a sidebar/header (such +as this one). This is useful for slides with much content\slash wide +tables +\item \structure{Frame (fragile)} is to be used if the frame consists of +``fragile'' content, especially verbatim stuff such as program listings +\end{enumerate} +If you want a fragile plain frame, pass the option ``plain'' to +a fragile frame or the option ``fragile'' to a plain frame. +\end{frame} + +\begin{frame}{Re-arranging frames} +\begin{block}{Tip} + +Did you know that you can easily move and re-arrange whole frames +via the outliner (\alert{View \textrightarrow Outline Pane})? + +Also, you can navigate to a specific frame via the \alert{Navigate} +menu! +\end{block} +\end{frame} + +\section
*{The overlay concept} + +\begin{frame}{What are overlays?} + +Basically, the overlay concept allows to change the slide content +dynamically. You can uncover things/text piecewise, fade out content, +highlight things, replace text, images etc. + +\pause{} +\begin{itemize}[<+->] +\item Overlays are useful to build up slides as you speak +\item They help you to shift your audience's focus on specific things +\item And they help your audience to follow you +\item So use overlays! \alert<6>{Really, use them!} +\end{itemize} +\end{frame} +% +\begin{frame}{Overlay types} + +\structure{Beamer} provides many different overlay types. The most +important ones are: +\begin{description} +\item [{Hidden~content:}] Stuff that is completely invisible up to a point +\item [{Covered~content:}] Stuff that is faded out (not completely invisible) +\item [{Highlighted~content:}] Stuff that is somehow emphasized at a certain +point +\end{description} +We give examples for these types in what follows, but begin with some +general remarks on overlay possibilities +\end{frame} + +\begin{frame}{General overlay/action possibilities} + +Many \structure{Beamer} elements provide overlay settings. Basically, +you can define on which sub-slide(s) a given content appears (``2'', +``2-4'', ``3-'', ``1,3'' etc.), or in which output mode (``presentation'', +``article'' etc.) +\begin{itemize} +\item In LyX, these settings are generally accessible via \alert{Insert \textrightarrow Overlay Specifications} +or \alert{Insert \textrightarrow Action Specifications} +\end{itemize} +\begin{overprint} +\onslide<2> +\begin{definition} +``Action'' is a more general concept, which does not only include +what we have called ``overlays'' (``on which sub-slide{[}s{]} is +this to be shown\slash hidden\slash highlighted''), but also tasks +such as ``only show this in the presentation, not on the handout'' +or ``show this on the second screen only'' (so-called ``modes''). +\end{definition} + +\onslide<3> +\begin{alertblock}{Note to the \LaTeX{} aficionados} + +The mentioned overlay/action settings conform to those command/environment +options embraced by\alert{\ <\ldots >} and \alert{{[}<\ldots >{]}} +in the \LaTeX{} output. + +Note that LyX adds those braces on export, so you must not enter +them yourself. In other words, enter ``1'' or ``+-'' to the overlay/action +insets, not ``<1>'' or ``{[}<+->{]}''! +\end{alertblock} +\end{overprint} +\end{frame} +% +\begin{frame}{An example} + +Take for example a quote. In a \structure{Quote} environment, you +can specify the overlay settings via \alert{Insert \textrightarrow Overlay Specifications}. +If you do this and enter ``2'', the quote will only appear on (sub-)slide +2: +\begin{quote}<2> +Fear no more the heat o\textquoteright{} the sun + +Nor the furious winter\textquoteright s rages + +Thou thy worldly task hast done + +Home art gone, and ta\textquoteright en thy wages +\end{quote} +This is how the concept works, basically. +\end{frame} +% +\begin{frame}{Covering vs. hiding} + +The difference between ``covering'' and ``hiding'' is that hidden +content is treated as if it isn't there, while covered content is +just covered (and the space is reserved). If we would have hidden +the quote on the last slide and not covered, it would only have taken +space on appearance: +\begin{quote} +Fear no more the heat o\textquoteright{} the sun + +Nor the furious winter\textquoteright s rages + +Thou thy worldly task hast done + +Home art gone, and ta\textquoteright en thy wages +\end{quote} + +You can see how this text moves when the quote is un-hidden. +\end{frame} +% +\begin{frame}{Coverage degrees} + +\setbeamercovered{transparent} + +\structure{Beamer} offers several degrees of ``coverage'', which +can be set via the command \alert{\textbackslash setbeamercovered} +either globally (for the whole presentation) or locally (e.\,g. for +a single frame, as here). By default, content is completely covered. +In ``transparent'' mode, you can see covered text greyed-out: +\begin{quote}<2> +Fear no more the heat o\textquoteright{} the sun + +Nor the furious winter\textquoteright s rages + +Thou thy worldly task hast done + +Home art gone, and ta\textquoteright en thy wages +\end{quote} +Check the \structure{Beamer} manual for more possibilities. +\end{frame} +% +\begin{frame}{Default overlay/action specifications vs.\\ +(normal) overlay/action specifications} +\begin{itemize} +\item For some environments (such as lists and also frames), you can set +``default specifications'' additionally to normal overlay/action +specifications (or in the case of lists: ``overlay specifications'' +for the whole list and ``item overlay specifications'' for singular +items) +\item Default specifications apply to all content of the given environment, +if not individually specified otherwise +\item They use a placeholder syntax. E.\,g., ``+(1)-'' will uncover all +items in a list step by step (with a start offset of 1) if they have +no individual item specification: +\begin{itemize}[<+(1)->] +\item One +\item Two +\item Three +\item<1-> Always +\end{itemize} +\end{itemize} +Please consult the \structure{Beamer} manual for details on this +syntax. + +\end{frame} +% +\begin{frame}[<+->]{Default overlay/action specifications vs.\\ +(normal) overlay/action specifications} + +\noindent This frame uses a specific default overlay specification + +which causes each overlay-aware paragraph \ldots{} +\begin{itemize} +\item \ldots{} or list item \ldots{} +\item \ldots{} to appear \ldots{} +\item \ldots{} on a subsequent sub-slide \ldots{} +\end{itemize} +\begin{block}{A block} + +\ldots{} one after the other +\end{block} +\end{frame} +% +\begin{frame}[]{Default overlay/action specifications vs.\\ +(normal) overlay/action specifications} + +\noindent And this frame uses a specific default overlay specification +\ldots{} +\begin{itemize} +\item \ldots{} which causes each overlay-aware list item \ldots{} +\item \ldots{} to be highlighted \ldots{} +\item \ldots{} on respective sub-slides +\end{itemize} +\end{frame} +% +\begin{frame}{Pause} + +The \structure{Pause} layout lets you mark a point where all following +content will be covered (by default for one slide, with regard to +the content preceding the pause): + +\pause{} + +After first pause + +\pause{} + +After second pause + +\pause[2]{} + +By default, consecutive pauses also end consecutively. + +Via \alert{Insert \textrightarrow Pause Number}, however, you can specify +a specific sub-slide at which the given pause ends, independent from +the number of pauses inserted before this one. +\end{frame} +% +\begin{frame}{Paragraph-wide overlays} + +\structure{Beamer} and LyX provide you with paragraph layouts whose +purpose it is to show/hide whole paragraphs or sequences of paragraphs +on specific slides. These are particularly: +\begin{uncoverenv}<2-> + +The \structure{Uncovered} layout which uncovers all content on the +specified slides \ldots{} +\begin{itemize} +\item \ldots{} including nested paragraphs of other layout. +\end{itemize} +\end{uncoverenv} + +\begin{onlyenv}<3-> + +The \structure{Only} layout which un-hides content (note again how +the surrounding text ``moves'' when this gets visible). +\end{onlyenv} + +\begin{overprint} +\onslide<4> + +And the \structure{Overprint} environment which lets you enter \ldots{} +\onslide<5> + +\ldots{} alternative text taking a specific space on specified slides. + +\end{overprint} +as demonstrated here. +\end{frame} +% +\begin{frame}{Inline overlays} + +\setbeamercovered{transparent} + +\structure{Beamer} also supports inline overlays for text parts (as +opposed to whole paragraphs), which are accessible via \alert{Edit \textrightarrow Text Style} +in LyX: +\begin{itemize} +\item You can \structure{uncover} \uncover<2->{text} on specific slides +\item You can make \visible<3->{text} \structure{visible} (which makes +a difference to ``uncover'' only with ``transparent'' coverage +setting, as used locally on this slide) +\item You can show \only<4->{text }\structure{only} on specific slides +\item You can make \invisible<5->{text} \structure{invisible} +\item And you can show \alt<6->{different}{\structure{alternative}} text +\end{itemize} +As for the paragraph layouts, the overlay settings can be accessed +via the \alert{Insert} menu. +\end{frame} +% +\begin{frame}{Overlay-aware commands} + +Many ``inline'' commands (also to be found at \alert{Edit \textrightarrow Text Style}) +are overlay-aware. +\begin{itemize} +\item Thus, you can make for instance text on specific slides \emph<2>{emphasized}, +\textbf<3>{bold}, shown in \alert<4>{alert} or \structure<5>{structure} +color. +\end{itemize} +\begin{block}<6>{Tip} + +Use these Emphasize and Bold insets (instead of the usual respective +font settings) also if you do not need overlay specifications. Due +to the way emphasized and bold is defined in \structure{Beamer}, +normal emphasizing and boldface can lead to \LaTeX{} errors, e.\,g. +when used in section headings. +\end{block} +\end{frame} + +\section{Specific environments} +\begin{frame}{Specific environments} + +Specific environments, particularly suited for presentations are: +\begin{itemize} +\item Diverse ``blocks'' +\item Theorem-style environments +\item Columns +\end{itemize} +We sketch them briefly in what follows. +\end{frame} +% +\begin{frame}{Blocks} + +Blocks can contain all sorts of information. We used them here for +``tips'' and ``hints''. The class provides 3 pre-defined blocks +with different look: +\begin{block}<2->{Block} + +A general-purpose block +\end{block} +\begin{exampleblock}<3->{Example Block} + +A block for ``examples'' +\end{exampleblock} +\begin{alertblock}<4->{Alert Block} + +And an ``alert'' block for important remarks. +\end{alertblock} +\end{frame} +% +\begin{frame}{Handling Blocks} +\begin{itemize} +\item In LyX, blocks have a similar user interface to frames, which means +that +\begin{itemize} +\item Content inside blocks needs to be nested (if the paragraph layout +is not \structure{Block}) +\item Consecutive blocks of the same type must be separated by the \structure{Separator} +paragraph style +\begin{block}{Tip} + +Use \alert{Edit \textrightarrow Start New Environment} (\textsf{undefiniert}) +to quickly start a new block from within a previous block! +\end{block} +\end{itemize} +\item Blocks are overlay-aware +\end{itemize} +\end{frame} +% +\begin{frame}{Theorem-style environments} + +\framesubtitle{(Theorem, Corollary, Definition, Definitions, Example, Examples, +Fact, Proof)} + +Theorems look similar to blocks in the output, but they have a fixed +title (depending on the type). +\begin{theorem} +This is a theorem! +\end{theorem} + +\begin{fact} +This is a fact! +\end{fact} + + +\pause{} + +Via \alert{Insert \textrightarrow Additional Theorem Text}, you can add +some extra text to this fixed title +\begin{example}[a bad one!] + +An example with additional text (brackets added automatically) +\end{example} + +\end{frame} +% +\begin{frame}{Columns} + +Sometimes it is useful to divide a presentation into columns +\begin{columns}[t] + +\column{.4\textwidth} + +To do this, first select \structure{Columns} (note the plural) to +start the columns + +\pause{} + +\column{.4\textwidth} + +And then, in the following paragraph, select \structure{Column} (singular) +to start a specific column +\end{columns} + + +\pause{} + +\medskip{} + +Note: +\begin{itemize} +\item In the \structure{Column} (singular) environment, you need to specify +the width using \LaTeX{} syntax (but also something like ``3.5cm'' +will work) +\item Any (singular) \structure{Column} must be nested to the (plural) +\structure{Columns}. Likewise, column content can be any paragraph +style that is nested to a singular \structure{Column} +\end{itemize} +\end{frame} + +\section{Short remarks on modes} +\begin{frame}{Modes} + +In \structure{Beamer} terms, a ``mode'' is a specific output route. +There are several modes for different purposes. We just want to highlight +three: +\begin{enumerate} +\item The ``beamer'' mode +\item The ``presentation'' mode +\item The ``article'' mode +\end{enumerate} +The beamer mode is the default. Unless explicitly specified otherwise, +your \structure{Beamer} document is in ``beamer'' mode. +\end{frame} +% +\begin{frame}{Switching Modes} + +However, you can switch document parts, frames, headings and all ``action''-aware +environments to a different mode. For instance, we have switched this +frame to ``presentation'' mode. +\begin{itemize} +\item What does this mean? +\begin{itemize} +\item It means that this frame will only be visible in the presentation, +not in the accompanying ``article'', if you produce such an article +(we will elaborate on this a bit below) +\end{itemize} +\end{itemize} +\end{frame} +% +\begin{frame}
{Switching Modes} + +This frame will not be visible in the presentation, but only in the +article, since it is in ``article'' mode. +\end{frame} +% +\begin{frame}{So what?} + +This is actually pretty useful! You can set up a single document and +produce both a presentation and \textendash{} using the article mode +\textendash{} a handout. +\begin{itemize} +\item And we mean a \emph{real}, useful handout, not one of those scaled +slide printouts that are so common nowadays (but if you insist, you +can produce one of those as well) +\item Modes allow you to add extra text to the handout or hide parts from +it +\item You can use for instance different graphics for the presentation and +the handout +\item and so on \ldots{} +\end{itemize} +\end{frame} +% +\begin{frame}{Examples} + +As said, many elements are mode-aware. +\begin{itemize} +\item You can show particular text \only{only in the presentation}\only
{only in the article} +via \alert{\noindent Edit \textrightarrow Text Style \textrightarrow Only} +\end{itemize} +\mode
{\begin{itemize} +\item Or put all sorts of complex contents via \alert{Insert \textrightarrow Custom Insets \textrightarrow ArticleMode} +in an inset that will only be output in article mode +\end{itemize} +}\mode{\begin{itemize} +\item Or put all sorts of complex contents via \alert{Insert \textrightarrow Custom Insets \textrightarrow PresentationMode} +in an inset that will only be output in presentation mode +\end{itemize} +} +\begin{itemize} +\item Or you can define that an \emph{emphasizing} should +only apply to the presentation, \textbf
{a bold face} only +to article +\item You can also show section headings or frame titles\slash subtitles +only in the presentation\slash article (like we do for the ``Contents'' +and ``References'' frame titles in this presentation) +\item And much more of this sort \ldots{} +\end{itemize} +\end{frame} +% +\begin{frame}{Setting up an article} + +Setting up a beamer article with LyX is easy. +\begin{itemize} +\item Just create a new document with the class \structure{\noindent Beamer Article (Standard Class)} +or \structure{\noindent Beamer Article (KOMA-Script)} +\item Then add the presentation to this document as a child (via \alert{Insert \textrightarrow File \textrightarrow Child Document\ldots}) +\item And that's it. Now you can produce the handout and the presentation +by compiling one of these two documents, while you only need to edit +one, namely the presentation +\end{itemize} +Check out the accompanying beamer-article example document for this +presentation. You can find it in the same folder as this document. +\end{frame} + +\section{Changing the look} +\begin{frame}{Themes} +\begin{itemize} +\item \structure{Beamer} presentations are themeable. Themes determine +the colors used, the macro structure (use of sidebars, headlines etc.), +the fonts, the look of list items, blocks and in general the whole +look and feel of a presentation +\item \structure{Beamer} itself ships a number of different-looking themes +to chose from (we use the ``Berkeley'' theme in this presentation; +see \alert{Document \textrightarrow Settings \textrightarrow LaTeX~Preamble} for +how we activated and slightly tweaked the theme) +\item In addition to this standard set, you can get more themes from \href{http://www.ctan.org}{CTAN} +and other places at the Internet +\item If you still are not satisified or if you need a theme matching to +your University's or company's corporate design, the \structure{Beamer} +manual \cite{beamer-ug} explains how you can setup your own theme +\end{itemize} +\end{frame} +% +\begin{frame}{Themes can be modified} + +But you do not need to write a theme from scratch if you want to alter +the look. +\begin{itemize} +\item Existing themes can be modified both in details and in major areas +(such as the coloring) +\item Consult the \structure{Beamer} manual \cite{beamer-ug} for details +\end{itemize} +\end{frame} + +\section{And more \ldots} +\begin{frame}{\ldots{} much more!} + +Note that \structure{Beamer} can do much more than we have described +here. The \structure{Beamer} manual \cite{beamer-ug} provides a +comprehensive documentation. + +Also, have a look at the \structure{Beamer} examples and templates +shipped with LyX! +\end{frame} + +\appendix + +\section{Appendix} + +\begin{frame} + +\frametitle{References} +\begin{thebibliography}{1} +\bibitem{beamer-ug}Tantau, Till et al.:\newblock The beamer class. +\url{https://ctan.org/tex-archive/macros/latex/contrib/beamer/doc/beameruserguide.pdf}. +\end{thebibliography} +\end{frame} + +\end{document} diff --git a/src/tex2lyx/test/runtests.py b/src/tex2lyx/test/runtests.py index 74f5cf7972..7c82909ded 100755 --- a/src/tex2lyx/test/runtests.py +++ b/src/tex2lyx/test/runtests.py @@ -74,6 +74,7 @@ def main(argv): else: files = ['test.ltx', \ 'algo2e.tex', \ + 'beamer.tex', \ 'box-color-size-space-align.tex', \ 'CJK.tex', \ 'CJKutf8.tex', \ diff --git a/src/tex2lyx/test/test-insets-basic.lyx.lyx b/src/tex2lyx/test/test-insets-basic.lyx.lyx index 06999a6274..9b2ea80b1f 100644 --- a/src/tex2lyx/test/test-insets-basic.lyx.lyx +++ b/src/tex2lyx/test/test-insets-basic.lyx.lyx @@ -963,7 +963,7 @@ literal "false" \begin_layout Standard An URL: -\begin_inset Flex Flex:URL +\begin_inset Flex URL status collapsed \begin_layout Plain Layout @@ -986,7 +986,7 @@ literal "false" \begin_layout Standard An URL with strange characters: -\begin_inset Flex Flex:URL +\begin_inset Flex URL status collapsed \begin_layout Plain Layout diff --git a/src/tex2lyx/test/test-insets.lyx.lyx b/src/tex2lyx/test/test-insets.lyx.lyx index b8015cabf7..8af5bcdbce 100644 --- a/src/tex2lyx/test/test-insets.lyx.lyx +++ b/src/tex2lyx/test/test-insets.lyx.lyx @@ -996,7 +996,7 @@ literal "false" \begin_layout Standard An URL: -\begin_inset Flex Flex:URL +\begin_inset Flex URL status collapsed \begin_layout Plain Layout @@ -1019,7 +1019,7 @@ literal "false" \begin_layout Standard An URL with strange characters: -\begin_inset Flex Flex:URL +\begin_inset Flex URL status collapsed \begin_layout Plain Layout diff --git a/src/tex2lyx/test/test-structure.lyx.lyx b/src/tex2lyx/test/test-structure.lyx.lyx index 87d9f6b0d2..56a549ed85 100644 --- a/src/tex2lyx/test/test-structure.lyx.lyx +++ b/src/tex2lyx/test/test-structure.lyx.lyx @@ -215,7 +215,7 @@ A section with optional argument \begin_layout Standard This causes the -\begin_inset Flex Flex:Strong +\begin_inset Flex Strong status collapsed \begin_layout Plain Layout From aa8d047bb3d7092613a957d724e6e4cdb502e3c4 Mon Sep 17 00:00:00 2001 From: Juergen Spitzmueller Date: Sat, 17 Mar 2018 14:36:56 +0100 Subject: [PATCH 100/121] Update status --- status.23x | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/status.23x b/status.23x index 14989d5592..b0fa2fdf58 100644 --- a/status.23x +++ b/status.23x @@ -23,6 +23,8 @@ What's new - Add support for biblatex. +- Add support for beamer overlay arguments (bug 11068). + - Add support for chapterbib. - Add support for \includeonly. @@ -33,6 +35,8 @@ What's new * Try to be a bit smarter with ambiguous quotation marks, depending on the main quote style and the local context. +- Consider options passed via \PassOptionsToPackage. + - Add support for URW Classico, MinionPro and the new Libertine fonts. - Add support for the \t*{} (bottomtiebar) macro of TIPA. @@ -40,6 +44,9 @@ What's new - Implement better parsing of some command options (via "literate" function of some insets) (bug 9563). +- Add support for alignment pseudo-environments as used inside floats + (bug 7857). + * USER INTERFACE @@ -121,10 +128,9 @@ What's new - Import straight quotations marks (e.g. babel shorthands) as ERT (bug 75). -- Consider options passed via \PassOptionsToPackage. +- Do not add duplicate \makebeamertitle. -- Add support for alignment pseudo-environments as used inside floats - (bug 7857). +- Keep empty paragraph it keepempty is true (bug 11078). - Fix parsing issue in nested CJK (bug 9562). From ded23e1f9a67d5fa9cb392f65d51a5979e881b7a Mon Sep 17 00:00:00 2001 From: Juergen Spitzmueller Date: Sat, 10 Mar 2018 15:40:51 +0100 Subject: [PATCH 101/121] tex2lyx: add support for lstinputlisting (cherry picked from commit d325f79f5c782edcfa32e87579fb102763d8d29b) --- src/tex2lyx/text.cpp | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/tex2lyx/text.cpp b/src/tex2lyx/text.cpp index ce357ea031..1bee520b0e 100644 --- a/src/tex2lyx/text.cpp +++ b/src/tex2lyx/text.cpp @@ -4764,12 +4764,23 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, } if (t.cs() == "input" || t.cs() == "include" - || t.cs() == "verbatiminput") { + || t.cs() == "verbatiminput" + || t.cs() == "lstinputlisting") { string name = t.cs(); - if (t.cs() == "verbatiminput" + if (name == "verbatiminput" && p.next_token().asInput() == "*") name += p.get_token().asInput(); context.check_layout(os); + string lstparams; + bool literal = false; + if (name == "lstinputlisting" && p.hasOpt()) { + lstparams = p.getArg('[', ']'); + pair oa = convert_latexed_command_inset_arg(lstparams); + literal = !oa.first; + if (literal) + lstparams = subst(lstparams, "\n", " "); + } + string lit = literal ? "\"true\"" : "\"false\""; string filename(normalize_filename(p.getArg('{', '}'))); string const path = getMasterFilePath(true); // We want to preserve relative / absolute filenames, @@ -4877,6 +4888,9 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, outname = subst(outname, "\"", "\\\""); os << "preview false\n" "filename \"" << outname << "\"\n"; + if (!lstparams.empty()) + os << "lstparams \"" << lstparams << "\"\n"; + os << "literal " << lit << "\n"; if (t.cs() == "verbatiminput") preamble.registerAutomaticallyLoadedPackage("verbatim"); } From f711e44bcfc451ea04994d699a7a2a10e18fef96 Mon Sep 17 00:00:00 2001 From: Juergen Spitzmueller Date: Sat, 17 Mar 2018 16:44:09 +0100 Subject: [PATCH 102/121] tex2lyx: complete minted support (inputminted) Also fix some whitespace issues in minted inset import. (cherry picked from commit f3c5bcd2be4edc37dec4c78422f31e07b322b298) --- src/tex2lyx/test/test-insets-basic.lyx.lyx | 10 ++--- src/tex2lyx/test/test-insets.lyx.lyx | 10 ++--- src/tex2lyx/test/test-minted.lyx.lyx | 24 +++++------- src/tex2lyx/text.cpp | 43 ++++++++++++++++++---- status.23x | 2 + 5 files changed, 57 insertions(+), 32 deletions(-) diff --git a/src/tex2lyx/test/test-insets-basic.lyx.lyx b/src/tex2lyx/test/test-insets-basic.lyx.lyx index 9b2ea80b1f..540c80c5d6 100644 --- a/src/tex2lyx/test/test-insets-basic.lyx.lyx +++ b/src/tex2lyx/test/test-insets-basic.lyx.lyx @@ -1111,7 +1111,7 @@ Inline: \begin_inset listings lstparams "language={C++},keywordstyle={\color{green}}" inline true -status collapsed +status open \begin_layout Plain Layout int a=5; @@ -1131,7 +1131,7 @@ int a=5; \begin_inset listings lstparams "caption={Example Listing float},label={lst:Example-Listing},language=Python" inline false -status collapsed +status open \begin_layout Plain Layout # Example listing float @@ -1215,7 +1215,7 @@ symbol \begin_inset listings lstparams "extendedchars=true,firstline=3,language=Python,lastline=8,numbers=left,showspaces=true,stepnumber=3" inline false -status collapsed +status open \begin_layout Plain Layout def func(param): @@ -1263,7 +1263,7 @@ Special cases: \begin_inset listings lstparams "abovecaptionskip=2em,basicstyle={\large\ttfamily},breaklines=true,extendedchars=true,firstline=2,float=h,language={[R/3 3.1]ABAP},lastline=5,numbers=left,numberstyle={\scriptsize},showspaces=true,showstringspaces=false,stepnumber=3,tabsize=4" inline false -status collapsed +status open \begin_layout Plain Layout hello @@ -1279,7 +1279,7 @@ hello \begin_inset listings lstparams "language=TeX" inline true -status collapsed +status open \begin_layout Plain Layout diff --git a/src/tex2lyx/test/test-insets.lyx.lyx b/src/tex2lyx/test/test-insets.lyx.lyx index 8af5bcdbce..cebb68e2d9 100644 --- a/src/tex2lyx/test/test-insets.lyx.lyx +++ b/src/tex2lyx/test/test-insets.lyx.lyx @@ -1170,7 +1170,7 @@ Inline: \begin_inset listings lstparams "language={C++},keywordstyle={\color{green}}" inline true -status collapsed +status open \begin_layout Plain Layout int a=5; @@ -1190,7 +1190,7 @@ int a=5; \begin_inset listings lstparams "caption={Example Listing float},label={lst:Example-Listing},language=Python" inline false -status collapsed +status open \begin_layout Plain Layout # Example listing float @@ -1274,7 +1274,7 @@ symbol \begin_inset listings lstparams "extendedchars=true,firstline=3,language=Python,lastline=8,numbers=left,showspaces=true,stepnumber=3" inline false -status collapsed +status open \begin_layout Plain Layout def func(param): @@ -1322,7 +1322,7 @@ Special cases: \begin_inset listings lstparams "abovecaptionskip=2em,basicstyle={\large\ttfamily},breaklines=true,extendedchars=true,firstline=2,float=h,language={[R/3 3.1]ABAP},lastline=5,numbers=left,numberstyle={\scriptsize},showspaces=true,showstringspaces=false,stepnumber=3,tabsize=4" inline false -status collapsed +status open \begin_layout Plain Layout hello @@ -1338,7 +1338,7 @@ hello \begin_inset listings lstparams "language=TeX" inline true -status collapsed +status open \begin_layout Plain Layout diff --git a/src/tex2lyx/test/test-minted.lyx.lyx b/src/tex2lyx/test/test-minted.lyx.lyx index 0af108d2d3..426902b5bc 100644 --- a/src/tex2lyx/test/test-minted.lyx.lyx +++ b/src/tex2lyx/test/test-minted.lyx.lyx @@ -102,7 +102,7 @@ Inline: \begin_inset listings lstparams "style=bw,language=C++" inline true -status collapsed +status open \begin_layout Plain Layout int a=5; @@ -137,7 +137,7 @@ noprefix "false" \begin_inset listings lstparams "language=Python,float=h" inline false -status collapsed +status open \begin_layout Plain Layout # Example listing float @@ -216,7 +216,7 @@ symbol \begin_inset listings lstparams "firstline=4,numbers=left,showspaces=true,language=Python" inline false -status collapsed +status open \begin_layout Plain Layout def func(param): @@ -252,7 +252,7 @@ A floating one-liner with [h] placement and without caption: \begin_inset listings lstparams "fontfamily=tt,fontsize={\large},bgcolor=lightgray,language=ABAP,float=h" inline false -status collapsed +status open \begin_layout Plain Layout hello @@ -269,7 +269,7 @@ Another inline listing: \begin_inset listings lstparams "language=TeX" inline true -status collapsed +status open \begin_layout Plain Layout @@ -298,11 +298,11 @@ noprefix "false" \end_inset -): +): \begin_inset listings lstparams "numbers=left,frame=lines,language=C" inline false -status collapsed +status open \begin_layout Plain Layout @@ -372,7 +372,7 @@ noprefix "false" \begin_inset listings lstparams "numbers=left,frame=lines,language=Fortran" inline false -status collapsed +status open \begin_layout Plain Layout subroutine incr(i) @@ -417,10 +417,6 @@ A Fortran subroutine \end_inset - -\end_layout - -\begin_layout Standard A framed floating listing with a caption and a label (Listing \begin_inset space ~ @@ -440,7 +436,7 @@ noprefix "false" \begin_inset listings lstparams "frame=single,language=Python,float=h" inline false -status collapsed +status open \begin_layout Plain Layout def boring(args = None): @@ -495,7 +491,7 @@ noprefix "false" ): \begin_inset listings lstparams "frame=single,language=Python,float=h" inline false -status collapsed +status open \begin_layout Plain Layout def boring(args = None): diff --git a/src/tex2lyx/text.cpp b/src/tex2lyx/text.cpp index 1bee520b0e..333bdd61be 100644 --- a/src/tex2lyx/text.cpp +++ b/src/tex2lyx/text.cpp @@ -1483,7 +1483,7 @@ void parse_listings(Parser & p, ostream & os, Context & parent_context, os << "inline true\n"; else os << "inline false\n"; - os << "status collapsed\n"; + os << "status open\n"; Context context(true, parent_context.textclass); context.layout = &parent_context.textclass.plainLayout(); if (use_minted && prefixIs(minted_nonfloat_caption, "[t]")) { @@ -2001,6 +2001,7 @@ void parse_environment(Parser & p, ostream & os, bool outer, parse_text_snippet(p, FLAG_ITEM, false, parent_context); minted_nonfloat_caption = "[b]" + caption; + eat_whitespace(p, os, parent_context, true); } } p.popPosition(); @@ -4431,6 +4432,7 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, // so simply skip it. parse_text_snippet(p, FLAG_ITEM, false, context); } + eat_whitespace(p, os, context, true); continue; } @@ -4765,22 +4767,48 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, if (t.cs() == "input" || t.cs() == "include" || t.cs() == "verbatiminput" - || t.cs() == "lstinputlisting") { + || t.cs() == "lstinputlisting" + || t.cs() == "inputminted") { string name = t.cs(); if (name == "verbatiminput" && p.next_token().asInput() == "*") name += p.get_token().asInput(); context.check_layout(os); string lstparams; - bool literal = false; if (name == "lstinputlisting" && p.hasOpt()) { lstparams = p.getArg('[', ']'); - pair oa = convert_latexed_command_inset_arg(lstparams); - literal = !oa.first; - if (literal) + lstparams = subst(lstparams, "\n", " "); + } else if (name == "inputminted") { + name = "lstinputlisting"; + string const lang = p.getArg('{', '}'); + if (lang != "tex") { + string cmd = "\\inputminted{" + lang + "}{"; + cmd += p.getArg('{', '}') + "}"; + output_ert_inset(os, cmd, context); + continue; + } + if (prefixIs(minted_nonfloat_caption, "[t]")) { + minted_nonfloat_caption.erase(0,3); + // extract label and caption from the already produced LyX code + vector nfc = getVectorFromString(minted_nonfloat_caption, "\n"); + string const caption = nfc.front(); + string label; + vector::iterator it = + find(nfc.begin(), nfc.end(), "LatexCommand label"); + if (it != nfc.end()) { + ++it; + if (it != nfc.end()) + label = *it; + label = support::split(label, '"'); + label.pop_back(); + } + minted_nonfloat_caption.clear(); + lstparams = "caption=" + caption; + if (!label.empty()) + lstparams += ",label=" + label; lstparams = subst(lstparams, "\n", " "); + } } - string lit = literal ? "\"true\"" : "\"false\""; string filename(normalize_filename(p.getArg('{', '}'))); string const path = getMasterFilePath(true); // We want to preserve relative / absolute filenames, @@ -4890,7 +4918,6 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, "filename \"" << outname << "\"\n"; if (!lstparams.empty()) os << "lstparams \"" << lstparams << "\"\n"; - os << "literal " << lit << "\n"; if (t.cs() == "verbatiminput") preamble.registerAutomaticallyLoadedPackage("verbatim"); } diff --git a/status.23x b/status.23x index b0fa2fdf58..59ef0bf921 100644 --- a/status.23x +++ b/status.23x @@ -39,6 +39,8 @@ What's new - Add support for URW Classico, MinionPro and the new Libertine fonts. +- Add support for \lstinputlisting and \inputminted. + - Add support for the \t*{} (bottomtiebar) macro of TIPA. - Implement better parsing of some command options (via "literate" From eb172be29b3c9154abd8af376c0acdfa37211d71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20St=C3=B6hr?= Date: Thu, 2 Nov 2017 22:25:26 +0100 Subject: [PATCH 103/121] GuiDocument.cpp: fix bug 10777 - the column width must be as wide as the column header text - also center the radiobuttons in the table - also use alternating colors for the table rows (cherry picked from commit a69f1a9e161c87cc58e1a2dcec1e174136190b89) --- src/frontends/qt4/GuiDocument.cpp | 7 ++++++- src/frontends/qt4/ui/MathsUi.ui | 3 +++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/frontends/qt4/GuiDocument.cpp b/src/frontends/qt4/GuiDocument.cpp index 560883ec6a..e063545d9d 100644 --- a/src/frontends/qt4/GuiDocument.cpp +++ b/src/frontends/qt4/GuiDocument.cpp @@ -1213,7 +1213,7 @@ GuiDocument::GuiDocument(GuiView & lv) headers << qt_("Package") << qt_("Load automatically") << qt_("Load always") << qt_("Do not load"); mathsModule->packagesTW->setHorizontalHeaderLabels(headers); - setSectionResizeMode(mathsModule->packagesTW->horizontalHeader(), QHeaderView::Stretch); + setSectionResizeMode(mathsModule->packagesTW->horizontalHeader(), QHeaderView::ResizeToContents); map const & packages = BufferParams::auto_packages(); mathsModule->packagesTW->setRowCount(packages.size()); int i = 0; @@ -1252,6 +1252,11 @@ GuiDocument::GuiDocument(GuiView & lv) mathsModule->packagesTW->setCellWidget(i, 1, autoRB); mathsModule->packagesTW->setCellWidget(i, 2, alwaysRB); mathsModule->packagesTW->setCellWidget(i, 3, neverRB); + //center the table contents + pack->setTextAlignment(Qt::AlignHCenter); + autoRB->setStyleSheet("margin-left:50%; margin-right:50%;"); + alwaysRB->setStyleSheet("margin-left:50%; margin-right:50%;"); + neverRB->setStyleSheet("margin-left:50%; margin-right:50%;"); connect(autoRB, SIGNAL(clicked()), this, SLOT(change_adaptor())); diff --git a/src/frontends/qt4/ui/MathsUi.ui b/src/frontends/qt4/ui/MathsUi.ui index 8ee7c4e7ce..380d76a3a5 100644 --- a/src/frontends/qt4/ui/MathsUi.ui +++ b/src/frontends/qt4/ui/MathsUi.ui @@ -179,6 +179,9 @@ 0 + + true + 4 From 91a15383f99eb0981b33c491021f27ff654f1a14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20St=C3=B6hr?= Date: Sun, 5 Nov 2017 13:39:09 +0100 Subject: [PATCH 104/121] GuiDocument.cpp: change back alignment for column with package names - as discussed in bug #10777 the first column should be left-aligned (cherry picked from commit 56670d73224e3bc2b80943b789fa2364d00a552d) --- src/frontends/qt4/GuiDocument.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/frontends/qt4/GuiDocument.cpp b/src/frontends/qt4/GuiDocument.cpp index e063545d9d..7e40ff6cec 100644 --- a/src/frontends/qt4/GuiDocument.cpp +++ b/src/frontends/qt4/GuiDocument.cpp @@ -1252,8 +1252,7 @@ GuiDocument::GuiDocument(GuiView & lv) mathsModule->packagesTW->setCellWidget(i, 1, autoRB); mathsModule->packagesTW->setCellWidget(i, 2, alwaysRB); mathsModule->packagesTW->setCellWidget(i, 3, neverRB); - //center the table contents - pack->setTextAlignment(Qt::AlignHCenter); + //center the radio buttons autoRB->setStyleSheet("margin-left:50%; margin-right:50%;"); alwaysRB->setStyleSheet("margin-left:50%; margin-right:50%;"); neverRB->setStyleSheet("margin-left:50%; margin-right:50%;"); From 7927d71a08ee22ff43782e34ea9f4f94f65210e0 Mon Sep 17 00:00:00 2001 From: Juergen Spitzmueller Date: Sun, 18 Mar 2018 12:11:26 +0100 Subject: [PATCH 105/121] Properly fix math packages table in Document Settings Fixes: #10777 (cherry picked from commit 3face5e119e27bf297bbaf647e8941bc6babd0c3) --- src/frontends/qt4/GuiDocument.cpp | 62 ++++-- src/frontends/qt4/ui/MathsUi.ui | 328 +++++++++++++++--------------- status.23x | 3 + 3 files changed, 215 insertions(+), 178 deletions(-) diff --git a/src/frontends/qt4/GuiDocument.cpp b/src/frontends/qt4/GuiDocument.cpp index 7e40ff6cec..4020f17fa9 100644 --- a/src/frontends/qt4/GuiDocument.cpp +++ b/src/frontends/qt4/GuiDocument.cpp @@ -1213,10 +1213,10 @@ GuiDocument::GuiDocument(GuiView & lv) headers << qt_("Package") << qt_("Load automatically") << qt_("Load always") << qt_("Do not load"); mathsModule->packagesTW->setHorizontalHeaderLabels(headers); - setSectionResizeMode(mathsModule->packagesTW->horizontalHeader(), QHeaderView::ResizeToContents); + setSectionResizeMode(mathsModule->packagesTW->horizontalHeader(), QHeaderView::Stretch); map const & packages = BufferParams::auto_packages(); mathsModule->packagesTW->setRowCount(packages.size()); - int i = 0; + int packnum = 0; for (map::const_iterator it = packages.begin(); it != packages.end(); ++it) { docstring const package = from_ascii(it->first); @@ -1247,15 +1247,35 @@ GuiDocument::GuiDocument(GuiView & lv) autoRB->setToolTip(autoTooltip); alwaysRB->setToolTip(alwaysTooltip); neverRB->setToolTip(neverTooltip); + + // Pack the buttons in a layout in order to get proper alignment + QWidget * autoRBWidget = new QWidget(); + QHBoxLayout * autoRBLayout = new QHBoxLayout(autoRBWidget); + autoRBLayout->addWidget(autoRB); + autoRBLayout->setAlignment(Qt::AlignCenter); + autoRBLayout->setContentsMargins(0, 0, 0, 0); + autoRBWidget->setLayout(autoRBLayout); + + QWidget * alwaysRBWidget = new QWidget(); + QHBoxLayout * alwaysRBLayout = new QHBoxLayout(alwaysRBWidget); + alwaysRBLayout->addWidget(alwaysRB); + alwaysRBLayout->setAlignment(Qt::AlignCenter); + alwaysRBLayout->setContentsMargins(0, 0, 0, 0); + alwaysRBWidget->setLayout(alwaysRBLayout); + + QWidget * neverRBWidget = new QWidget(); + QHBoxLayout * neverRBLayout = new QHBoxLayout(neverRBWidget); + neverRBLayout->addWidget(neverRB); + neverRBLayout->setAlignment(Qt::AlignCenter); + neverRBLayout->setContentsMargins(0, 0, 0, 0); + neverRBWidget->setLayout(neverRBLayout); + QTableWidgetItem * pack = new QTableWidgetItem(toqstr(package)); - mathsModule->packagesTW->setItem(i, 0, pack); - mathsModule->packagesTW->setCellWidget(i, 1, autoRB); - mathsModule->packagesTW->setCellWidget(i, 2, alwaysRB); - mathsModule->packagesTW->setCellWidget(i, 3, neverRB); - //center the radio buttons - autoRB->setStyleSheet("margin-left:50%; margin-right:50%;"); - alwaysRB->setStyleSheet("margin-left:50%; margin-right:50%;"); - neverRB->setStyleSheet("margin-left:50%; margin-right:50%;"); + + mathsModule->packagesTW->setItem(packnum, 0, pack); + mathsModule->packagesTW->setCellWidget(packnum, 1, autoRBWidget); + mathsModule->packagesTW->setCellWidget(packnum, 2, alwaysRBWidget); + mathsModule->packagesTW->setCellWidget(packnum, 3, neverRBWidget); connect(autoRB, SIGNAL(clicked()), this, SLOT(change_adaptor())); @@ -1263,7 +1283,7 @@ GuiDocument::GuiDocument(GuiView & lv) this, SLOT(change_adaptor())); connect(neverRB, SIGNAL(clicked()), this, SLOT(change_adaptor())); - ++i; + ++packnum; } connect(mathsModule->allPackagesAutoPB, SIGNAL(clicked()), this, SLOT(allPackagesAuto())); @@ -3004,17 +3024,19 @@ void GuiDocument::applyView() if (!item) continue; int row = mathsModule->packagesTW->row(item); - QRadioButton * rb = (QRadioButton*)mathsModule->packagesTW->cellWidget(row, 1); + + QRadioButton * rb = + (QRadioButton*)mathsModule->packagesTW->cellWidget(row, 1)->layout()->itemAt(0)->widget(); if (rb->isChecked()) { bp_.use_package(it->first, BufferParams::package_auto); continue; } - rb = (QRadioButton*)mathsModule->packagesTW->cellWidget(row, 2); + rb = (QRadioButton*)mathsModule->packagesTW->cellWidget(row, 2)->layout()->itemAt(0)->widget(); if (rb->isChecked()) { bp_.use_package(it->first, BufferParams::package_on); continue; } - rb = (QRadioButton*)mathsModule->packagesTW->cellWidget(row, 3); + rb = (QRadioButton*)mathsModule->packagesTW->cellWidget(row, 3)->layout()->itemAt(0)->widget(); if (rb->isChecked()) bp_.use_package(it->first, BufferParams::package_off); } @@ -3549,17 +3571,20 @@ void GuiDocument::paramsToDialog() int row = mathsModule->packagesTW->row(item); switch (bp_.use_package(it->first)) { case BufferParams::package_off: { - QRadioButton * rb = (QRadioButton*)mathsModule->packagesTW->cellWidget(row, 3); + QRadioButton * rb = + (QRadioButton*)mathsModule->packagesTW->cellWidget(row, 3)->layout()->itemAt(0)->widget(); rb->setChecked(true); break; } case BufferParams::package_on: { - QRadioButton * rb = (QRadioButton*)mathsModule->packagesTW->cellWidget(row, 2); + QRadioButton * rb = + (QRadioButton*)mathsModule->packagesTW->cellWidget(row, 2)->layout()->itemAt(0)->widget(); rb->setChecked(true); break; } case BufferParams::package_auto: { - QRadioButton * rb = (QRadioButton*)mathsModule->packagesTW->cellWidget(row, 1); + QRadioButton * rb = + (QRadioButton*)mathsModule->packagesTW->cellWidget(row, 1)->layout()->itemAt(0)->widget(); rb->setChecked(true); break; } @@ -4569,7 +4594,8 @@ void GuiDocument::allPackagesNot() void GuiDocument::allPackages(int col) { for (int row = 0; row < mathsModule->packagesTW->rowCount(); ++row) { - QRadioButton * rb = (QRadioButton*)mathsModule->packagesTW->cellWidget(row, col); + QRadioButton * rb = + (QRadioButton*)mathsModule->packagesTW->cellWidget(row, col)->layout()->itemAt(0)->widget(); rb->setChecked(true); } } diff --git a/src/frontends/qt4/ui/MathsUi.ui b/src/frontends/qt4/ui/MathsUi.ui index 380d76a3a5..13f15dcc84 100644 --- a/src/frontends/qt4/ui/MathsUi.ui +++ b/src/frontends/qt4/ui/MathsUi.ui @@ -6,172 +6,15 @@ 0 0 - 500 + 569 367 - - - - - All packages: - - - - - - - Load A&utomatically - - - - - - - Load Alwa&ys - - - - - - - Do &Not Load - - - - - - - Indent displayed formulas instead of centering - - - Indent &Formulas - - - - - - - false - - - - 0 - 0 - - - - Size of the indentation - - - - - - - Qt::Horizontal - - - - 234 - 20 - - - - - - - - false - - - - - - - - - - - - - false - - - - 0 - 0 - - - - - - - - - - - Qt::Horizontal - - - - 153 - 20 - - - - - - - - - 0 - 0 - - - - - 115 - 18 - - - - Formula numbering side: - - - - - - - true - - - - 0 - 0 - - - - Side where formulas are numbered - - - - - - - Qt::Horizontal - - - - 234 - 17 - - - - - + + @@ -197,6 +40,171 @@ + + + + + + All packages: + + + + + + + Load A&utomatically + + + + + + + Load Alwa&ys + + + + + + + Do &Not Load + + + + + + + Indent displayed formulas instead of centering + + + Indent &Formulas + + + + + + + false + + + + 0 + 0 + + + + Size of the indentation + + + + + + + Qt::Horizontal + + + + 234 + 20 + + + + + + + + false + + + + + + + + + + + + + false + + + + 0 + 0 + + + + + + + + + + + Qt::Horizontal + + + + 153 + 20 + + + + + + + + + + + + + 0 + 0 + + + + + 115 + 18 + + + + Formula numbering side: + + + + + + + true + + + + 0 + 0 + + + + Side where formulas are numbered + + + + + + + Qt::Horizontal + + + + 234 + 17 + + + + + + diff --git a/status.23x b/status.23x index 59ef0bf921..ca88a24970 100644 --- a/status.23x +++ b/status.23x @@ -66,6 +66,9 @@ What's new - Allow unification of graphic groups inside marked block via context menu. +- Cosmetic polishment of the "Math Options" pane of Document Settings + (bug 10777). + * DOCUMENTATION AND LOCALIZATION From d9314d15dc427b9baa2f17fd744c67a279f99aac Mon Sep 17 00:00:00 2001 From: Juergen Spitzmueller Date: Fri, 13 Oct 2017 11:25:55 +0200 Subject: [PATCH 106/121] Some improvements to the graphics dialog * Describe the viewport/bb situation more accurate * Use generic term "coordinates", since bb and viewport are flavor-specific * Add some tooltips * Increase the width of the options widget. (cherry picked from commit c462fadff57373744e27ac38df04bac2c651b67c) --- src/frontends/qt4/ui/GraphicsUi.ui | 684 ++++++++++++++++------------- status.23x | 2 + 2 files changed, 373 insertions(+), 313 deletions(-) diff --git a/src/frontends/qt4/ui/GraphicsUi.ui b/src/frontends/qt4/ui/GraphicsUi.ui index 3942651e83..83d0d0965b 100644 --- a/src/frontends/qt4/ui/GraphicsUi.ui +++ b/src/frontends/qt4/ui/GraphicsUi.ui @@ -1,109 +1,133 @@ - + + GraphicsUi - - + + 0 0 - 482 - 383 + 654 + 512 - - - 0 - 0 + + 0 0 - + - + true - - + + 9 - + + 9 + + + 9 + + + 9 + + 6 - - - + + + - + 0 - - + + &Graphics - - + + 9 - + + 9 + + + 9 + + + 9 + + 6 - - - + + + Select an image file - + &Browse... - - - + + + Output Size - + true - - + + 9 - + + 9 + + + 9 + + + 9 + + 6 - - + + - - + + - - - + + + true - - - 0 - 0 + + 0 0 - + Width of image in output - + - + Qt::Horizontal - + 61 20 @@ -111,69 +135,67 @@ - - + + - - - + + + true - - - 0 - 0 + + 0 0 - + Height of image in output - - - + + + true - + Sets height of graphic. Leave unchecked to set automatically. - + Set &height: - - - + + + &Scale graphics (%): - - - + + + true - + Sets width of graphic. Leave unchecked to set automatically. - + Set &width: - - - + + + true - + Scale image to maximum size not exceeding width and height - + &Maintain aspect ratio @@ -181,75 +203,82 @@ - - - + + + Rotate Graphics - + true - - + + 9 - + + 9 + + + 9 + + + 9 + + 6 - - - + + + Check to change the order of rotating and scaling - + Ro&tate after scaling - - - + + + The origin of the rotation - - - + + + The origin of the rotation - + Or&igin: - + origin - - - - - 0 - 0 + + + + 0 0 - + Angle to rotate image by - - - + + + Angle to rotate image by - + A&ngle (degrees): - + angle @@ -257,45 +286,54 @@ - - - + + + File name of image - + &File: - + filename - - - + + + File name of image - - - &Clipping + + + &Coordinates and Clipping - - + + 9 - + + 9 + + + 9 + + + 9 + + 6 - + - + Qt::Vertical - + 20 40 @@ -303,114 +341,121 @@ - - - - Clip to bounding box values + + + + Clip to the coordinates specified below (bounding box for DVI/PS output, viewport for PDF output) - - Clip to &bounding box + + Clip to c&oordinates - - - + + + true - - - 0 - 0 + + 0 0 - + QFrame::StyledPanel - + QFrame::Plain - - + + 9 - + + 9 + + + 9 + + + 9 + + 6 - - - + + + &Left bottom: - + lbX - - + + - - + + - - + + - - - + + + - - + + - - + + - - + + - - + + - - - + + + Right &top: - + rtX - - - + + + y: - - - + + + y: - - - + + + x: - - - + + + x: @@ -418,12 +463,12 @@ - + - + Qt::Horizontal - + 181 20 @@ -431,76 +476,70 @@ - - - - Get bounding box from the (EPS) file + + + + Read coordinates from the file (bounding box value in case of PostScript files, graphic dimensions in case of other file types) - + &Get from File - - + + LaTe&X and LyX options - - + + 9 - + + 9 + + + 9 + + + 9 + + 6 - - - - Qt::Horizontal - - - - 161 - 20 - - - - - - - - - 0 - 0 + + + + 0 0 - + Additional LaTeX options - - - + + + Additional LaTeX options - + LaTeX &options: - + latexoptions - + - + Qt::Vertical - + 354 81 @@ -508,67 +547,74 @@ - - - + + + Qt::StrongFocus - + Enable LyX to preview this graphics, if graphics previewing is not disabled at application level (see Preferences dialog). - + Sho&w in LyX - + true - + true - - + + 9 - + + 9 + + + 9 + + + 9 + + 6 - - - + + + true - - - 0 - 0 + + 0 0 - + Percentage to scale by in LyX - - - + + + Percentage to scale by in LyX - + Sca&le on screen (%): - + displayscale - + - + Qt::Horizontal - + 40 20 @@ -579,30 +625,39 @@ - - - + + + Assign the graphic to a group of graphics that share the same settings - + Graphics Group - + true - - + + 9 - + + 9 + + + 9 + + + 9 + + 6 - + - + Qt::Horizontal - + 121 51 @@ -610,43 +665,41 @@ - - - - - 0 - 0 + + + + 0 0 - + - - A&ssigned to group: + + Assigned &to group: - + groupCO - - - + + + Click to define a new graphics group. - + O&pen new group... - - - + + + Select an existing group for the current graphics. - + false @@ -654,12 +707,12 @@ - - - + + + Draft mode - + &Draft mode @@ -668,36 +721,45 @@ - - - - 0 - - + + + 6 + + 0 + + + 0 + + + 0 + + + 0 + - - + + &Restore - + false - + false - + Qt::Horizontal - + QSizePolicy::MinimumExpanding - + 20 20 @@ -706,53 +768,49 @@ - - + + &OK - + true - + true - - - - 0 - 0 + + + 0 0 - + &Apply - + false - + false - - - - 0 - 0 + + + 0 0 - + Close - + false @@ -803,7 +861,7 @@ displayGB - qt_i18n.h + qt_i18n.h diff --git a/status.23x b/status.23x index ca88a24970..849f36cb8d 100644 --- a/status.23x +++ b/status.23x @@ -69,6 +69,8 @@ What's new - Cosmetic polishment of the "Math Options" pane of Document Settings (bug 10777). +- UI improvements in the graphics dialog (bug 10771). + * DOCUMENTATION AND LOCALIZATION From 977a0c403746aeff9ee529aed01966b1fdeea95b Mon Sep 17 00:00:00 2001 From: Jean-Marc Lasgouttes Date: Tue, 30 Jan 2018 14:32:53 +0100 Subject: [PATCH 107/121] Make it possible to select (not)native file dialogs at run time Add a new LyXRC variable use_native_filedialog (true by default) that allows to select the kind of FileDialog we want at runtime. (cherry picked from commit af795b80d8512926261e2457bc5f2e0ac017bec4) --- src/LyXRC.cpp | 16 +++ src/LyXRC.h | 3 + src/frontends/qt4/FileDialog.cpp | 163 +++++++++++++++---------------- status.23x | 5 + 4 files changed, 104 insertions(+), 83 deletions(-) diff --git a/src/LyXRC.cpp b/src/LyXRC.cpp index 7cfa2a3445..fb01e7918a 100644 --- a/src/LyXRC.cpp +++ b/src/LyXRC.cpp @@ -195,6 +195,7 @@ LexerKeyword lyxrcTags[] = { { "\\use_converter_needauth", LyXRC::RC_USE_CONVERTER_NEEDAUTH }, { "\\use_converter_needauth_forbidden", LyXRC::RC_USE_CONVERTER_NEEDAUTH_FORBIDDEN }, { "\\use_lastfilepos", LyXRC::RC_USELASTFILEPOS }, + { "\\use_native_filedialog", LyXRC::RC_USE_NATIVE_FILEDIALOG }, { "\\use_pixmap_cache", LyXRC::RC_USE_PIXMAP_CACHE }, { "\\use_qimage", LyXRC::RC_USE_QIMAGE }, // compatibility with versions older than 1.4.0 only @@ -273,6 +274,7 @@ void LyXRC::setDefaults() num_lastfiles = 20; check_lastfiles = true; use_lastfilepos = true; + use_native_filedialog = true; load_session = false; make_backup = true; save_compressed = false; @@ -873,6 +875,9 @@ LyXRC::ReturnValues LyXRC::read(Lexer & lexrc, bool check_format) case RC_ACCEPT_COMPOUND: lexrc >> spellchecker_accept_compound; break; + case RC_USE_NATIVE_FILEDIALOG: + lexrc >> use_native_filedialog; + break; case RC_USE_SYSTEM_COLORS: lexrc >> use_system_colors; break; @@ -2410,6 +2415,16 @@ void LyXRC::write(ostream & os, bool ignore_system_lyxrc, string const & name) c if (tag != RC_LAST) break; // fall through + case RC_USE_NATIVE_FILEDIALOG: + if (ignore_system_lyxrc || + use_native_filedialog != system_lyxrc.use_native_filedialog) { + os << "\\use_native_filedialog " + << convert(use_native_filedialog) + << '\n'; + } + if (tag != RC_LAST) + break; + // fall through case RC_USE_SYSTEM_COLORS: if (ignore_system_lyxrc || use_system_colors != system_lyxrc.use_system_colors) { @@ -3029,6 +3044,7 @@ void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new) case LyXRC::RC_USE_CONVERTER_CACHE: case LyXRC::RC_USE_CONVERTER_NEEDAUTH_FORBIDDEN: case LyXRC::RC_USE_CONVERTER_NEEDAUTH: + case LyXRC::RC_USE_NATIVE_FILEDIALOG: case LyXRC::RC_USE_SYSTEM_COLORS: case LyXRC::RC_USE_TOOLTIP: case LyXRC::RC_USE_PIXMAP_CACHE: diff --git a/src/LyXRC.h b/src/LyXRC.h index f2b0ab73e6..7049bf8d5e 100644 --- a/src/LyXRC.h +++ b/src/LyXRC.h @@ -172,6 +172,7 @@ public: RC_USE_CONVERTER_CACHE, RC_USE_CONVERTER_NEEDAUTH_FORBIDDEN, RC_USE_CONVERTER_NEEDAUTH, + RC_USE_NATIVE_FILEDIALOG, RC_USE_SYSTEM_COLORS, RC_USE_TOOLTIP, RC_USE_PIXMAP_CACHE, @@ -333,6 +334,8 @@ public: bool use_tooltip; /// Use the colors from current system theme? bool use_system_colors; + /// use native file dialog or our own ? + bool use_native_filedialog; /// Use pixmap cache? bool use_pixmap_cache; /// Use QImage backend? diff --git a/src/frontends/qt4/FileDialog.cpp b/src/frontends/qt4/FileDialog.cpp index f1156348d4..ee5f3503da 100644 --- a/src/frontends/qt4/FileDialog.cpp +++ b/src/frontends/qt4/FileDialog.cpp @@ -16,6 +16,8 @@ #include "LyXFileDialog.h" #include "qt_helpers.h" +#include "LyXRC.h" + #include "support/debug.h" #include "support/FileName.h" #include "support/filetools.h" @@ -24,7 +26,9 @@ #include -/** when this is defined, the code will use +#include + +/** when LyXRC::use_native_filedialog is true, we use * QFileDialog::getOpenFileName and friends to create filedialogs. * Effects: * - the dialog does not use the quick directory buttons (Button @@ -35,13 +39,6 @@ * * Therefore there is a tradeoff in enabling or disabling this (JMarc) */ -#if defined(Q_OS_MAC) || defined(Q_OS_WIN) -#define USE_NATIVE_FILEDIALOG 1 -#endif - -#ifdef USE_NATIVE_FILEDIALOG -#include -#endif namespace lyx { @@ -91,38 +88,38 @@ FileDialog::Result FileDialog::save(QString const & path, FileDialog::Result result; result.first = FileDialog::Chosen; -#ifdef USE_NATIVE_FILEDIALOG - QString const startsWith = makeAbsPath(suggested, path); - QString const name = - QFileDialog::getSaveFileName(qApp->focusWidget(), - title_, startsWith, filters.join(";;"), - selectedFilter, QFileDialog::DontConfirmOverwrite); - if (name.isNull()) - result.first = FileDialog::Later; - else - result.second = toqstr(os::internal_path(fromqstr(name))); -#else - LyXFileDialog dlg(title_, path, filters, private_->b1, private_->b2); - dlg.setFileMode(QFileDialog::AnyFile); - dlg.setAcceptMode(QFileDialog::AcceptSave); - dlg.setConfirmOverwrite(false); - if (selectedFilter != 0 && !selectedFilter->isEmpty()) - dlg.selectNameFilter(*selectedFilter); + if (lyxrc.use_native_filedialog) { + QString const startsWith = makeAbsPath(suggested, path); + QString const name = + QFileDialog::getSaveFileName(qApp->focusWidget(), + title_, startsWith, filters.join(";;"), + selectedFilter, QFileDialog::DontConfirmOverwrite); + if (name.isNull()) + result.first = FileDialog::Later; + else + result.second = toqstr(os::internal_path(fromqstr(name))); + } else { + LyXFileDialog dlg(title_, path, filters, private_->b1, private_->b2); + dlg.setFileMode(QFileDialog::AnyFile); + dlg.setAcceptMode(QFileDialog::AcceptSave); + dlg.setConfirmOverwrite(false); + if (selectedFilter != 0 && !selectedFilter->isEmpty()) + dlg.selectNameFilter(*selectedFilter); - if (!suggested.isEmpty()) - dlg.selectFile(suggested); + if (!suggested.isEmpty()) + dlg.selectFile(suggested); - LYXERR(Debug::GUI, "Synchronous FileDialog: "); - int res = dlg.exec(); - LYXERR(Debug::GUI, "result " << res); - if (res == QDialog::Accepted) - result.second = internalPath(dlg.selectedFiles()[0]); - else - result.first = FileDialog::Later; - if (selectedFilter != 0) - *selectedFilter = dlg.selectedNameFilter(); - dlg.hide(); -#endif + LYXERR(Debug::GUI, "Synchronous FileDialog: "); + int res = dlg.exec(); + LYXERR(Debug::GUI, "result " << res); + if (res == QDialog::Accepted) + result.second = internalPath(dlg.selectedFiles()[0]); + else + result.first = FileDialog::Later; + if (selectedFilter != 0) + *selectedFilter = dlg.selectedNameFilter(); + dlg.hide(); + } return result; } @@ -143,29 +140,29 @@ FileDialog::Result FileDialog::open(QString const & path, FileDialog::Result result; result.first = FileDialog::Chosen; -#ifdef USE_NATIVE_FILEDIALOG - QString const startsWith = makeAbsPath(suggested, path); - QString const file = QFileDialog::getOpenFileName(qApp->focusWidget(), - title_, startsWith, filters.join(";;")); - if (file.isNull()) - result.first = FileDialog::Later; - else - result.second = internalPath(file); -#else - LyXFileDialog dlg(title_, path, filters, private_->b1, private_->b2); + if (lyxrc.use_native_filedialog) { + QString const startsWith = makeAbsPath(suggested, path); + QString const file = QFileDialog::getOpenFileName(qApp->focusWidget(), + title_, startsWith, filters.join(";;")); + if (file.isNull()) + result.first = FileDialog::Later; + else + result.second = internalPath(file); + } else { + LyXFileDialog dlg(title_, path, filters, private_->b1, private_->b2); - if (!suggested.isEmpty()) - dlg.selectFile(suggested); + if (!suggested.isEmpty()) + dlg.selectFile(suggested); - LYXERR(Debug::GUI, "Synchronous FileDialog: "); - int res = dlg.exec(); - LYXERR(Debug::GUI, "result " << res); - if (res == QDialog::Accepted) - result.second = internalPath(dlg.selectedFiles()[0]); - else - result.first = FileDialog::Later; - dlg.hide(); -#endif + LYXERR(Debug::GUI, "Synchronous FileDialog: "); + int res = dlg.exec(); + LYXERR(Debug::GUI, "result " << res); + if (res == QDialog::Accepted) + result.second = internalPath(dlg.selectedFiles()[0]); + else + result.first = FileDialog::Later; + dlg.hide(); + } return result; } @@ -178,33 +175,33 @@ FileDialog::Result FileDialog::opendir(QString const & path, FileDialog::Result result; result.first = FileDialog::Chosen; -#ifdef USE_NATIVE_FILEDIALOG - QString const startsWith = toqstr(makeAbsPath(fromqstr(suggested), - fromqstr(path)).absFileName()); - QString const dir = QFileDialog::getExistingDirectory(qApp->focusWidget(), - title_, startsWith); - if (dir.isNull()) - result.first = FileDialog::Later; - else - result.second = toqstr(os::internal_path(fromqstr(dir))); -#else - LyXFileDialog dlg(title_, path, QStringList(qt_("Directories")), - private_->b1, private_->b2); + if (lyxrc.use_native_filedialog) { + QString const startsWith = + toqstr(makeAbsPath(fromqstr(suggested), fromqstr(path)).absFileName()); + QString const dir = + QFileDialog::getExistingDirectory(qApp->focusWidget(), title_, startsWith); + if (dir.isNull()) + result.first = FileDialog::Later; + else + result.second = toqstr(os::internal_path(fromqstr(dir))); + } else { + LyXFileDialog dlg(title_, path, QStringList(qt_("Directories")), + private_->b1, private_->b2); - dlg.setFileMode(QFileDialog::DirectoryOnly); + dlg.setFileMode(QFileDialog::DirectoryOnly); - if (!suggested.isEmpty()) - dlg.selectFile(suggested); + if (!suggested.isEmpty()) + dlg.selectFile(suggested); - LYXERR(Debug::GUI, "Synchronous FileDialog: "); - int res = dlg.exec(); - LYXERR(Debug::GUI, "result " << res); - if (res == QDialog::Accepted) - result.second = internalPath(dlg.selectedFiles()[0]); - else - result.first = FileDialog::Later; - dlg.hide(); -#endif + LYXERR(Debug::GUI, "Synchronous FileDialog: "); + int res = dlg.exec(); + LYXERR(Debug::GUI, "result " << res); + if (res == QDialog::Accepted) + result.second = internalPath(dlg.selectedFiles()[0]); + else + result.first = FileDialog::Later; + dlg.hide(); + } return result; } diff --git a/status.23x b/status.23x index 849f36cb8d..d86dbd5bff 100644 --- a/status.23x +++ b/status.23x @@ -57,6 +57,11 @@ What's new snappier, especially on repeated events. As an added bonus, subpixel aliasing is honored in the work area. +- Use native file dialogs on all platforms by default. It is now + possible to switch to LyX custom dialogs (which have extra shortcuts + to relevant directories) by setting the preference + \use_native_filedialog true + - Handle properly top/bottom of inset with mac-like cursor movement (bug 10701). From 953df3089463f3c240ba89adcf966064ebbc642a Mon Sep 17 00:00:00 2001 From: Juergen Spitzmueller Date: Mon, 26 Mar 2018 15:50:35 +0200 Subject: [PATCH 108/121] Fix use of default biblio_style Fixes: #11088 --- src/BufferParams.cpp | 5 ++++- status.23x | 3 +++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/BufferParams.cpp b/src/BufferParams.cpp index b709b16a54..827823d8ba 100644 --- a/src/BufferParams.cpp +++ b/src/BufferParams.cpp @@ -394,7 +394,7 @@ BufferParams::BufferParams() papersize = PAPER_DEFAULT; orientation = ORIENTATION_PORTRAIT; use_geometry = false; - biblio_style = "plain"; + biblio_style = string(); use_bibtopic = false; multibib = string(); use_indices = false; @@ -3426,6 +3426,9 @@ bool BufferParams::addCiteEngine(vector const & engine) string const & BufferParams::defaultBiblioStyle() const { + if (!biblio_style.empty()) + return biblio_style; + map const & bs = documentClass().defaultBiblioStyle(); auto cit = bs.find(theCiteEnginesList.getTypeAsString(citeEngineType())); if (cit != bs.end()) diff --git a/status.23x b/status.23x index d86dbd5bff..7f78e1dce3 100644 --- a/status.23x +++ b/status.23x @@ -122,6 +122,9 @@ What's new - Take actual font height into account when drawing placeholder box for graphics (bug 11048). +- Correctly set degault bibliography style in the Document Settings + dialog (bug 11088). + * INTERNALS From 82f9688c8145880d1070d3dd6b3564ce1fb7738e Mon Sep 17 00:00:00 2001 From: Juergen Spitzmueller Date: Mon, 26 Mar 2018 18:35:09 +0200 Subject: [PATCH 109/121] typo --- status.23x | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/status.23x b/status.23x index 7f78e1dce3..fdaaecf0c4 100644 --- a/status.23x +++ b/status.23x @@ -122,7 +122,7 @@ What's new - Take actual font height into account when drawing placeholder box for graphics (bug 11048). -- Correctly set degault bibliography style in the Document Settings +- Correctly set default bibliography style in the Document Settings dialog (bug 11088). From 5f4d678a7251458e0481da10fb25fbaaa0b449a8 Mon Sep 17 00:00:00 2001 From: Richard Kimberly Heck Date: Wed, 28 Mar 2018 15:46:39 -0400 Subject: [PATCH 110/121] Whitespace only. --- status.23x | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/status.23x b/status.23x index fdaaecf0c4..f0bcc2d275 100644 --- a/status.23x +++ b/status.23x @@ -84,6 +84,7 @@ What's new * BUILD/INSTALLATION + ** Bug fixes: ************* @@ -103,6 +104,7 @@ What's new * LYX2LYX + * USER INTERFACE - Fix crash with server-get-xy and tall inset (bug 8120). @@ -133,6 +135,7 @@ What's new * DOCUMENTATION AND LOCALIZATION + * LYXHTML @@ -153,5 +156,6 @@ What's new * ADVANCED FIND AND REPLACE + * BUILD/INSTALLATION From d5493307605b260117dc00d35aea8323c1744843 Mon Sep 17 00:00:00 2001 From: Juergen Spitzmueller Date: Thu, 22 Feb 2018 11:24:43 +0100 Subject: [PATCH 111/121] Handle comments in options Things like pdfpagemode=UseOutlines%None,UseOutlines,UseThumbs,FullScreen was not imported correctly (the comment was not stripped) Fixes the rest of #5737 (cherry picked from commit 820ec38da7ce04ec95b1a8e1e2d1aa9b7d0762fb) --- src/tex2lyx/Preamble.cpp | 4 ++-- status.23x | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/tex2lyx/Preamble.cpp b/src/tex2lyx/Preamble.cpp index 26824ddcd2..436c961545 100644 --- a/src/tex2lyx/Preamble.cpp +++ b/src/tex2lyx/Preamble.cpp @@ -281,7 +281,7 @@ vector split_options(string const & input) p.skip_spaces(true); if (p.next_token().asInput() == "{") option += '{' + p.getArg('{', '}') + '}'; - } else if (t.cat() != catSpace) + } else if (t.cat() != catSpace && t.cat() != catComment) option += t.asInput(); } @@ -584,7 +584,7 @@ Preamble::Preamble() : one_language(true), explicit_babel(false), h_use_geometry = "false"; h_use_default_options = "false"; h_use_hyperref = "false"; - h_use_microtype = "false"; + h_use_microtype = "false"; h_use_refstyle = false; h_use_minted = false; h_use_packages["amsmath"] = "1"; diff --git a/status.23x b/status.23x index f0bcc2d275..a8e29318c3 100644 --- a/status.23x +++ b/status.23x @@ -152,6 +152,8 @@ What's new - Fix parsing issue in nested CJK (bug 9562). +- Fix import of package options with comments (bug 5737). + * ADVANCED FIND AND REPLACE From bcd1814746ca8bfd66012d75fe1b5977a5fc2790 Mon Sep 17 00:00:00 2001 From: Juergen Spitzmueller Date: Sun, 18 Mar 2018 18:30:48 +0100 Subject: [PATCH 112/121] Open ExternalInset dialog on first tab for new insets Fixes: #11081 (cherry picked from commit 126e0c3dac5a6b223d609a7bfa29295f19992987) --- src/frontends/qt4/GuiExternal.cpp | 3 +++ status.23x | 3 +++ 2 files changed, 6 insertions(+) diff --git a/src/frontends/qt4/GuiExternal.cpp b/src/frontends/qt4/GuiExternal.cpp index f994aafaef..ba1c171ebf 100644 --- a/src/frontends/qt4/GuiExternal.cpp +++ b/src/frontends/qt4/GuiExternal.cpp @@ -493,6 +493,9 @@ static void getCrop(external::ClipData & data, void GuiExternal::updateContents() { + if (params_.filename.empty()) + tab->setCurrentIndex(0); + string const name = params_.filename.outputFileName(fromqstr(bufferFilePath())); fileED->setText(toqstr(name)); diff --git a/status.23x b/status.23x index a8e29318c3..f79f8604fb 100644 --- a/status.23x +++ b/status.23x @@ -127,6 +127,9 @@ What's new - Correctly set default bibliography style in the Document Settings dialog (bug 11088). +- Assure that the External Inset dialog is opened at first tab for + new insets (bug 11081). + * INTERNALS From 2bb9d495276b43db58c0eb1783df0cd47eac164b Mon Sep 17 00:00:00 2001 From: Richard Heck Date: Sun, 1 Apr 2018 22:18:04 -0400 Subject: [PATCH 113/121] Fix bug 11099. Adds simple search/find functionality to preamble. --- src/frontends/qt4/GuiDocument.cpp | 23 ++++++++++++++++ src/frontends/qt4/GuiDocument.h | 6 ++++- src/frontends/qt4/ui/PreambleUi.ui | 42 ++++++++++++++++++++++-------- 3 files changed, 59 insertions(+), 12 deletions(-) diff --git a/src/frontends/qt4/GuiDocument.cpp b/src/frontends/qt4/GuiDocument.cpp index 4020f17fa9..f5af06ede0 100644 --- a/src/frontends/qt4/GuiDocument.cpp +++ b/src/frontends/qt4/GuiDocument.cpp @@ -469,6 +469,29 @@ PreambleModule::PreambleModule(QWidget * parent) preambleTE->setWordWrapMode(QTextOption::NoWrap); setFocusProxy(preambleTE); connect(preambleTE, SIGNAL(textChanged()), this, SIGNAL(changed())); + connect(findLE, SIGNAL(textEdited(const QString &)), this, SLOT(checkFindButton())); + connect(findButtonPB, SIGNAL(clicked()), this, SLOT(findText())); + connect(findLE, SIGNAL(returnPressed()), this, SLOT(findText())); + checkFindButton(); +} + + +void PreambleModule::checkFindButton() +{ + findButtonPB->setEnabled(!findLE->text().isEmpty()); +} + + +void PreambleModule::findText() +{ + bool const found = preambleTE->find(findLE->text()); + if (!found) { + // wrap + QTextCursor qtcur = preambleTE->textCursor(); + qtcur.movePosition(QTextCursor::Start); + preambleTE->setTextCursor(qtcur); + preambleTE->find(findLE->text()); + } } diff --git a/src/frontends/qt4/GuiDocument.h b/src/frontends/qt4/GuiDocument.h index 1fe1dc74a1..e4f32e2570 100644 --- a/src/frontends/qt4/GuiDocument.h +++ b/src/frontends/qt4/GuiDocument.h @@ -332,10 +332,14 @@ private: void closeEvent(QCloseEvent *); void on_preambleTE_textChanged() { changed(); } -private: typedef std::map > Coords; Coords preamble_coords_; BufferId current_id_; + +private Q_SLOTS: + /// + void checkFindButton(); + void findText(); }; diff --git a/src/frontends/qt4/ui/PreambleUi.ui b/src/frontends/qt4/ui/PreambleUi.ui index b39f26173d..1bc1c52879 100644 --- a/src/frontends/qt4/ui/PreambleUi.ui +++ b/src/frontends/qt4/ui/PreambleUi.ui @@ -1,7 +1,8 @@ - + + PreambleUi - - + + 0 0 @@ -9,19 +10,38 @@ 278 - + - - + + 11 - + + 11 + + + 11 + + + 11 + + 6 - - - + + + + + + + Find + + + + + + false @@ -29,7 +49,7 @@ - qt_i18n.h + qt_i18n.h From d1fa6f10e595643c7a4220654c6eaee9d8920251 Mon Sep 17 00:00:00 2001 From: Richard Heck Date: Sun, 1 Apr 2018 22:18:37 -0400 Subject: [PATCH 114/121] Set preamble tab stop to 4 chars. --- src/frontends/qt4/GuiDocument.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/frontends/qt4/GuiDocument.cpp b/src/frontends/qt4/GuiDocument.cpp index f5af06ede0..0ff70a897c 100644 --- a/src/frontends/qt4/GuiDocument.cpp +++ b/src/frontends/qt4/GuiDocument.cpp @@ -473,6 +473,10 @@ PreambleModule::PreambleModule(QWidget * parent) connect(findButtonPB, SIGNAL(clicked()), this, SLOT(findText())); connect(findLE, SIGNAL(returnPressed()), this, SLOT(findText())); checkFindButton(); + // https://stackoverflow.com/questions/13027091/how-to-override-tab-width-in-qt + const int tabStop = 4; + QFontMetrics metrics(preambleTE->currentFont()); + preambleTE->setTabStopWidth(tabStop * metrics.width(' ')); } From 1696d26b207c8a361f15ea02c44497caa43d6864 Mon Sep 17 00:00:00 2001 From: Richard Heck Date: Sun, 1 Apr 2018 22:19:55 -0400 Subject: [PATCH 115/121] Status for last two commits. --- status.23x | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/status.23x b/status.23x index f79f8604fb..45136970ee 100644 --- a/status.23x +++ b/status.23x @@ -76,6 +76,10 @@ What's new - UI improvements in the graphics dialog (bug 10771). +- Set tab stop in preamble editor to four characters. + +- Provide simple search functionality in preamble (bug 11099). + * DOCUMENTATION AND LOCALIZATION From 935442aaba08136fa5bd8c7407c46951d0e9d084 Mon Sep 17 00:00:00 2001 From: Richard Heck Date: Tue, 3 Apr 2018 18:38:46 -0400 Subject: [PATCH 116/121] Fix bug #11102. Ignore deleted material when generating a proposed label. (cherry picked from commit d9ebf6e2c75eca0f192fef0b7d822644e3b62e64) --- src/Text.cpp | 2 +- status.23x | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Text.cpp b/src/Text.cpp index d5d729a277..ed3650b8df 100644 --- a/src/Text.cpp +++ b/src/Text.cpp @@ -1977,7 +1977,7 @@ docstring Text::getPossibleLabel(Cursor const & cur) const Layout const * layout = &(pars_[pit].layout()); docstring text; - docstring par_text = pars_[pit].asString(); + docstring par_text = pars_[pit].asString(AS_STR_SKIPDELETE); // The return string of math matrices might contain linebreaks par_text = subst(par_text, '\n', '-'); diff --git a/status.23x b/status.23x index 45136970ee..9141412d92 100644 --- a/status.23x +++ b/status.23x @@ -134,6 +134,8 @@ What's new - Assure that the External Inset dialog is opened at first tab for new insets (bug 11081). +- Ignore deleted material when generating a proposed label (bug 11102). + * INTERNALS From c690e8880b0f889a6b123c8d762a1f0e4da54707 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20St=C3=B6hr?= Date: Fri, 9 Mar 2018 04:53:33 +0100 Subject: [PATCH 117/121] tex2lyx: parse \xymatrix LyX's \xymatrix support relies on math therefore put it into math and parse its content fixes bug #10638 (cherry picked from commit 1174279967c4ee369d9de1438f18b7e5c748b127) --- lib/syntax.default | 1 - src/tex2lyx/text.cpp | 13 +++++++++++++ status.23x | 2 ++ 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/lib/syntax.default b/lib/syntax.default index d9596b6f86..550b6f16b7 100644 --- a/lib/syntax.default +++ b/lib/syntax.default @@ -705,7 +705,6 @@ $$ \vspace{} \vspace*{} \whiledo{}{} -\xymatrix{} % this is basically an array => the contents would be parsed badly (bug 8396) % LaTeX environments. % They have always one extra "argument": diff --git a/src/tex2lyx/text.cpp b/src/tex2lyx/text.cpp index 333bdd61be..47f5b13e6b 100644 --- a/src/tex2lyx/text.cpp +++ b/src/tex2lyx/text.cpp @@ -3407,6 +3407,19 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer, continue; } + if (t.cs() == "xymatrix") { + // we must open a new math because LyX's xy support is in math + context.check_layout(os); + begin_inset(os, "Formula "); + os << '$'; + os << "\\" << t.cs() << '{'; + parse_math(p, os, FLAG_ITEM, MATH_MODE); + os << '}' << '$'; + end_inset(os); + preamble.registerAutomaticallyLoadedPackage("xy"); + continue; + } + if (t.cs() == "includegraphics") { bool const clip = p.next_token().asInput() == "*"; if (clip) diff --git a/status.23x b/status.23x index 9141412d92..869cdee493 100644 --- a/status.23x +++ b/status.23x @@ -163,6 +163,8 @@ What's new - Fix import of package options with comments (bug 5737). +- Fix import of xymatrix (bug 10638). + * ADVANCED FIND AND REPLACE From 9df09d8cba0fed191ae9685e2105fb08024958c8 Mon Sep 17 00:00:00 2001 From: Juergen Spitzmueller Date: Sat, 7 Apr 2018 22:09:06 +0200 Subject: [PATCH 118/121] Set correct path to (biblatex) bibliography databases that are entered relative to child documents. Fixes: #11105 (cherry picked from commit 2ecc3b09c6a9c663bec87356b2ec512f37676c5c) --- src/Buffer.cpp | 22 ++++++++++++++++++++-- src/support/filetools.cpp | 11 +++++++---- src/support/filetools.h | 3 ++- status.23x | 5 ++++- 4 files changed, 33 insertions(+), 8 deletions(-) diff --git a/src/Buffer.cpp b/src/Buffer.cpp index a9f66a674c..fa5cad9522 100644 --- a/src/Buffer.cpp +++ b/src/Buffer.cpp @@ -3185,9 +3185,27 @@ vector const Buffer::prepareBibFilePaths(OutputParams const & runpara string utf8input = to_utf8(it->first); string database = prepareFileNameForLaTeX(utf8input, ".bib", runparams.nice); - FileName const try_in_file = + FileName try_in_file = makeAbsPath(database + ".bib", filePath()); - bool const not_from_texmf = try_in_file.isReadableFile(); + bool not_from_texmf = try_in_file.isReadableFile(); + // If the file has not been found, try with the real file name + // (it might come from a child in a sub-directory) + if (!not_from_texmf) { + try_in_file = it->second; + if (try_in_file.isReadableFile()) { + // Check if the file is in texmf + FileName kpsefile(findtexfile(changeExtension(utf8input, "bib"), "bib", true)); + not_from_texmf = kpsefile.empty() + || kpsefile.absFileName() != try_in_file.absFileName(); + if (not_from_texmf) + // If this exists, make path relative to the master + // FIXME Unicode + database = removeExtension( + prepareFileNameForLaTeX(to_utf8(makeRelPath(from_utf8(try_in_file.absFileName()), + from_utf8(filePath()))), + ".bib", runparams.nice)); + } + } if (!runparams.inComment && !runparams.dryrun && !runparams.nice && not_from_texmf) { diff --git a/src/support/filetools.cpp b/src/support/filetools.cpp index 12457cb3ae..3d2346c7cd 100644 --- a/src/support/filetools.cpp +++ b/src/support/filetools.cpp @@ -1094,7 +1094,8 @@ cmd_ret const runCommand(string const & cmd) } -FileName const findtexfile(string const & fil, string const & /*format*/) +FileName const findtexfile(string const & fil, string const & /*format*/, + bool const onlykpse) { /* There is no problem to extend this function too use other methods to look for files. It could be setup to look @@ -1107,9 +1108,11 @@ FileName const findtexfile(string const & fil, string const & /*format*/) // If the file can be found directly, we just return a // absolute path version of it. - FileName const absfile(makeAbsPath(fil)); - if (absfile.exists()) - return absfile; + if (!onlykpse) { + FileName const absfile(makeAbsPath(fil)); + if (absfile.exists()) + return absfile; + } // Now we try to find it using kpsewhich. // It seems from the kpsewhich manual page that it is safe to use diff --git a/src/support/filetools.h b/src/support/filetools.h index 0146474d07..96a884273b 100644 --- a/src/support/filetools.h +++ b/src/support/filetools.h @@ -282,7 +282,8 @@ bool readLink(FileName const & file, FileName & link); * \param format The file format as used by kpsewhich, e.g. "bib", "bst" etc. */ FileName const findtexfile(std::string const & fil, - std::string const & format); + std::string const & format, + bool const onlykpse = false); /** \param file1, file2 the two files to be compared. Must have absolute paths. * \returns 1 if \c file1 has a more recent timestamp than \c file2, diff --git a/status.23x b/status.23x index 869cdee493..f1c93081d5 100644 --- a/status.23x +++ b/status.23x @@ -94,7 +94,7 @@ What's new * DOCUMENT INPUT/OUTPUT -- Fix language settings annd line spacing in InPreamble-titles +- Fix language settings and line spacing in InPreamble-titles (bug 9332, 1049). - Respect 'literal' setting when calculating longest bibitem (bug 10817). @@ -104,6 +104,9 @@ What's new - Fix polyglossia language switches for Arabic (bug 11057). +- Set correct path to (biblatex) bibliography databases that are entered + relative to child documents (bug 11105). + * LYX2LYX From 1eceb1c574bbe9977c7c7d5e675de1506b2fe1bc Mon Sep 17 00:00:00 2001 From: Juergen Spitzmueller Date: Sun, 8 Apr 2018 19:02:01 +0200 Subject: [PATCH 119/121] Load hyperref with a suitable driver This is mandatory for some features (such as bookmarks,pdfusetitle) to work, and only a handful of drivers can be auto-detected by hyperref. Fixes: #6418 (cherry picked from commit 33bfbf89c4267ed8e37fad1681adce4cd5dfddf4) --- lib/configure.py | 12 +++---- lib/doc/Customization.lyx | 62 ++++++++++++++++++++++++++++++++++-- lib/doc/de/Customization.lyx | 27 ++++++++++++++-- src/Buffer.cpp | 1 + src/BufferParams.cpp | 4 +-- src/Converter.cpp | 14 ++++++++ src/Converter.h | 6 ++++ src/OutputParams.h | 4 +++ src/PDFOptions.cpp | 4 +++ status.23x | 2 ++ 10 files changed, 122 insertions(+), 14 deletions(-) diff --git a/lib/configure.py b/lib/configure.py index 23ec3c82dc..393ee7bdac 100644 --- a/lib/configure.py +++ b/lib/configure.py @@ -768,10 +768,10 @@ def checkFormatEntries(dtl_tools): def checkConverterEntries(): ''' Check all converters (\converter entries) ''' checkProg('the pdflatex program', ['pdflatex $$i'], - rc_entry = [ r'\converter pdflatex pdf2 "%%" "latex=pdflatex"' ]) + rc_entry = [ r'\converter pdflatex pdf2 "%%" "latex=pdflatex,hyperref-driver=pdftex"' ]) checkProg('XeTeX', ['xelatex $$i'], - rc_entry = [ r'\converter xetex pdf4 "%%" "latex=xelatex"' ]) + rc_entry = [ r'\converter xetex pdf4 "%%" "latex=xelatex,hyperref-driver=xetex"' ]) checkLuatex() @@ -923,7 +923,7 @@ def checkConverterEntries(): rc_entry = [ r'\converter rtf html "%%" ""' ]) # Do not define a converter to pdf6, ps is a pure export format checkProg('a PS to PDF converter', ['ps2pdf $$i $$o'], - rc_entry = [ r'\converter ps pdf "%%" ""' ]) + rc_entry = [ r'\converter ps pdf "%%" "hyperref-driver=dvips"' ]) # checkProg('a PS to TXT converter', ['pstotext $$i > $$o'], rc_entry = [ r'\converter ps text2 "%%" ""' ]) @@ -973,13 +973,13 @@ def checkConverterEntries(): rc_entry = [ r'\converter dvi text4 "%%" ""' ]) # checkProg('a DVI to PS converter', ['dvips -o $$o $$i'], - rc_entry = [ r'\converter dvi ps "%%" ""' ]) + rc_entry = [ r'\converter dvi ps "%%" "hyperref-driver=dvips"' ]) # checkProg('a DVI to cropped EPS converter', ['dvips -E -o $$o $$i'], rc_entry = [ r'\converter dvi eps3 "%%" ""' ]) # - checkProg('a DVI to PDF converter', ['dvipdfmx -o $$o $$i', 'dvipdfm -o $$o $$i'], - rc_entry = [ r'\converter dvi pdf3 "%%" ""' ]) + checkProg('a DVI to PDF converter', ['dvipdfmx', 'dvipdfm'], + rc_entry = [ r'\converter dvi pdf3 "%% -o $$o $$i" "hyperref-driver=%%"' ]) # checkProg('a fax program', ['kdeprintfax $$i', 'ksendfax $$i', 'hylapex $$i'], rc_entry = [ r'\converter ps fax "%%" ""']) diff --git a/lib/doc/Customization.lyx b/lib/doc/Customization.lyx index 40b32b4f15..7b81ff850e 100644 --- a/lib/doc/Customization.lyx +++ b/lib/doc/Customization.lyx @@ -124,11 +124,12 @@ logicalmkup \papercolumns 1 \papersides 2 \paperpagestyle headings -\tracking_changes false +\tracking_changes true \output_changes false \html_math_output 0 \html_css_as_file 0 \html_be_strict true +\author -712698321 "Jürgen Spitzmüller" \end_header \begin_body @@ -2515,6 +2516,35 @@ value format: \end_layout +\begin_layout Labeling +\labelwidthstring 00.00.0000 + +\change_inserted -712698321 1523206314 +\begin_inset Flex Code +status collapsed + +\begin_layout Plain Layout + +\change_inserted -712698321 1523206193 +hyperref-driver +\end_layout + +\end_inset + + The name of the driver that needs to be loaded with the +\family sans +hyperref +\family default + package for this converter. + The loading of the correct driver is necessary to get some PDF-specific + features. + See the +\family sans +hyperref +\family default + manual for details. +\end_layout + \begin_layout Labeling \labelwidthstring 00.00.0000 \begin_inset Flex Code @@ -2622,8 +2652,34 @@ $$b \end_layout \begin_layout Standard -None of these last three are presently used in any of the converters that - are installed with \SpecialChar LyX + +\change_inserted -712698321 1523206384 +A suitable hyperref-driver is set for some converters that are installed + with \SpecialChar LyX +. + +\change_deleted -712698321 1523206388 +None of these +\change_inserted -712698321 1523206389 +The +\change_unchanged + last three +\change_inserted -712698321 1523206400 + flags, however, +\change_unchanged + are presently +\change_inserted -712698321 1523206407 +not +\change_unchanged +used in any of the +\change_inserted -712698321 1523206437 +pre-installed +\change_unchanged +converters +\change_deleted -712698321 1523206442 + that are installed with \SpecialChar LyX + +\change_unchanged . \end_layout diff --git a/lib/doc/de/Customization.lyx b/lib/doc/de/Customization.lyx index 270e385de6..0420dad76e 100644 --- a/lib/doc/de/Customization.lyx +++ b/lib/doc/de/Customization.lyx @@ -1989,6 +1989,25 @@ key=value \begin_layout Labeling \labelwidthstring 00.00.0000 +\family typewriter +hyperref-driver +\family default +Der Name der Treiberdatei, die für diesen Konverter mit dem +\family sans +Hyperref +\family default +-Paket geladen werden soll. + Dies ist nötig, um bestimmte PDF-Features verwenden zu können. + Konsultieren Sie das +\family sans +Hyperref +\family default +-Handbuch für Einzelheiten. +\end_layout + +\begin_layout Labeling +\labelwidthstring 00.00.0000 + \family typewriter parselog \family default @@ -2082,9 +2101,11 @@ index \end_layout \begin_layout Standard -Keines dieser Flags wird zur Zeit in einem Konverter benutzt, der zusammen - mit \SpecialChar LyX - installiert wird. +Ein passender Hyperref-Treiber wird für einige mit \SpecialChar LyX + installierten Konverter + definiert. + Die zuletzt aufgeführten drei Flags hingegen werden zurzeit von keinem + der vorinstallierten Konverter verwendet. \end_layout \begin_layout Standard diff --git a/src/Buffer.cpp b/src/Buffer.cpp index fa5cad9522..c1d7648580 100644 --- a/src/Buffer.cpp +++ b/src/Buffer.cpp @@ -4319,6 +4319,7 @@ Buffer::ExportStatus Buffer::doExport(string const & target, bool put_in_tempdir return ExportNoPathToFormat; } runparams.flavor = converters.getFlavor(path, this); + runparams.hyperref_driver = converters.getHyperrefDriver(path); Graph::EdgePath::const_iterator it = path.begin(); Graph::EdgePath::const_iterator en = path.end(); for (; it != en; ++it) diff --git a/src/BufferParams.cpp b/src/BufferParams.cpp index 827823d8ba..60c7bb0c12 100644 --- a/src/BufferParams.cpp +++ b/src/BufferParams.cpp @@ -2094,8 +2094,8 @@ bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features, OutputParams tmp_params = features.runparams(); pdfoptions().writeLaTeX(tmp_params, os, features.isProvided("hyperref")); - // correctly break URLs with hyperref and dvi output - if (features.runparams().flavor == OutputParams::LATEX + // correctly break URLs with hyperref and dvi/ps output + if (features.runparams().hyperref_driver == "dvips" && features.isAvailable("breakurl")) os << "\\usepackage{breakurl}\n"; } else if (features.isRequired("nameref")) diff --git a/src/Converter.cpp b/src/Converter.cpp index 664a4bb718..e272d08a64 100644 --- a/src/Converter.cpp +++ b/src/Converter.cpp @@ -136,6 +136,8 @@ void Converter::readFlags() nice_ = true; else if (flag_name == "needauth") need_auth_ = true; + else if (flag_name == "hyperref-driver") + href_driver_ = flag_value; } if (!result_dir_.empty() && result_file_.empty()) result_file_ = "index." + theFormats().extension(to_); @@ -283,6 +285,18 @@ OutputParams::FLAVOR Converters::getFlavor(Graph::EdgePath const & path, } +string Converters::getHyperrefDriver(Graph::EdgePath const & path) +{ + for (Graph::EdgePath::const_iterator cit = path.begin(); + cit != path.end(); ++cit) { + Converter const & conv = converterlist_[*cit]; + if (!conv.hyperref_driver().empty()) + return conv.hyperref_driver(); + } + return string(); +} + + bool Converters::checkAuth(Converter const & conv, string const & doc_fname, bool use_shell_escape) { diff --git a/src/Converter.h b/src/Converter.h index 8f63aba512..e144ca2fa4 100644 --- a/src/Converter.h +++ b/src/Converter.h @@ -79,6 +79,8 @@ public: std::string const result_file() const { return result_file_; } /// std::string const parselog() const { return parselog_; } + /// + std::string const hyperref_driver() const { return href_driver_; } private: /// @@ -114,6 +116,8 @@ private: trivstring result_file_; /// Command to convert the program output to a LaTeX log file format trivstring parselog_; + /// The hyperref driver + trivstring href_driver_; }; @@ -159,6 +163,8 @@ public: /// OutputParams::FLAVOR getFlavor(Graph::EdgePath const & path, Buffer const * buffer = 0); + /// + std::string getHyperrefDriver(Graph::EdgePath const & path); /// Flags for converting files enum ConversionFlags { /// No special flags diff --git a/src/OutputParams.h b/src/OutputParams.h index 1631dac9d0..ff9491205b 100644 --- a/src/OutputParams.h +++ b/src/OutputParams.h @@ -172,6 +172,10 @@ public: */ std::string index_command; + /** Hyperref driver + */ + std::string hyperref_driver; + /** Line length to use with plaintext or LaTeX export. */ size_type linelen; diff --git a/src/PDFOptions.cpp b/src/PDFOptions.cpp index a4d23ee5a9..b030baa62e 100644 --- a/src/PDFOptions.cpp +++ b/src/PDFOptions.cpp @@ -97,6 +97,10 @@ void PDFOptions::writeLaTeX(OutputParams & runparams, otexstream & os, string opt; string hyperset; + // Driver needed by specific converters + if (!runparams.hyperref_driver.empty()) + opt += runparams.hyperref_driver + ","; + // since LyX uses unicode, also set the PDF strings to unicode strings with the // hyperref option "unicode" opt += "unicode=true,"; diff --git a/status.23x b/status.23x index f1c93081d5..cf7da01274 100644 --- a/status.23x +++ b/status.23x @@ -107,6 +107,8 @@ What's new - Set correct path to (biblatex) bibliography databases that are entered relative to child documents (bug 11105). +- Load hyperref with a suitable driver (bug 6418). + * LYX2LYX From d25762da35f594fde39091b14b560d26543202e5 Mon Sep 17 00:00:00 2001 From: "Joel A. Kulesza" Date: Wed, 24 Jan 2018 23:09:46 -0700 Subject: [PATCH 120/121] Changed Settings->Local Layout to FixedWidth & Nowrap This change is made in response to Ticket 10992. The change made is consistent with those captured in Ticket 9966. (cherry picked from commit 869e2fe9b9e5a6966665e1d82da0555ed03a2b5e) --- src/frontends/qt4/GuiDocument.cpp | 2 ++ status.23x | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/frontends/qt4/GuiDocument.cpp b/src/frontends/qt4/GuiDocument.cpp index 0ff70a897c..38ce23f065 100644 --- a/src/frontends/qt4/GuiDocument.cpp +++ b/src/frontends/qt4/GuiDocument.cpp @@ -555,6 +555,8 @@ void PreambleModule::closeEvent(QCloseEvent * e) LocalLayout::LocalLayout(QWidget * parent) : UiWidget(parent), current_id_(0), validated_(false) { + locallayoutTE->setFont(guiApp->typewriterSystemFont()); + locallayoutTE->setWordWrapMode(QTextOption::NoWrap); connect(locallayoutTE, SIGNAL(textChanged()), this, SLOT(textChanged())); connect(validatePB, SIGNAL(clicked()), this, SLOT(validatePressed())); connect(convertPB, SIGNAL(clicked()), this, SLOT(convertPressed())); diff --git a/status.23x b/status.23x index cf7da01274..d85e56d0fb 100644 --- a/status.23x +++ b/status.23x @@ -80,6 +80,8 @@ What's new - Provide simple search functionality in preamble (bug 11099). +- Change Settings -> Local Layout to Fixed-width Font and Nowrap (bug 10992). + * DOCUMENTATION AND LOCALIZATION From 10335b93b4e7190520f19c7c5fb8d816eb86ede2 Mon Sep 17 00:00:00 2001 From: Juergen Spitzmueller Date: Sat, 14 Apr 2018 10:35:59 +0200 Subject: [PATCH 121/121] Support new hunspell C++ ABI if LyX is built against hunspell >= 1.5 Fixes: #10547 --- 3rdparty/hunspell/Makefile.am | 2 +- INSTALL | 3 +++ config/lyxinclude.m4 | 1 + config/spell.m4 | 25 ++++++++++++++++++++ development/cmake/ConfigureChecks.cmake | 30 ++++++++++++++++++++++++ development/cmake/configCompiler.h.cmake | 3 +++ src/HunspellChecker.cpp | 16 +++++++++++++ status.23x | 3 +++ 8 files changed, 82 insertions(+), 1 deletion(-) diff --git a/3rdparty/hunspell/Makefile.am b/3rdparty/hunspell/Makefile.am index 7e0429d014..fe0502dd21 100644 --- a/3rdparty/hunspell/Makefile.am +++ b/3rdparty/hunspell/Makefile.am @@ -16,7 +16,7 @@ EXTRA_DIST = \ 1.6.2/src/hunspell/hunvisapi.h.in \ 1.6.2/src/hunspell/utf_info.cxx -AM_CPPFLAGS += -DHUNSPELL_STATIC +AM_CPPFLAGS += -DHUNSPELL_STATIC @STDLIB_DEBUG@ liblyxhunspell_a_SOURCES = \ 1.6.2/src/hunspell/affentry.cxx \ diff --git a/INSTALL b/INSTALL index 8d3b609c76..9e91367337 100644 --- a/INSTALL +++ b/INSTALL @@ -227,6 +227,9 @@ The following options allow you to tweak the generated code more precisely (see --without-included-boost is specified). You may have to use --disable-stdlib-debug when linking development versions against your system's boost library. + The same problem applies to hunspell (as of hunspell 1.5). So either + compile --with-included-hunspell or --disable-stdlib-debug when + linking development versions against your system's hunspell library. o --enable-monolithic-build[=boost,client,insets,mathed,core,tex2lyx,frontend-qt4] that enables monolithic build of the given parts of the source diff --git a/config/lyxinclude.m4 b/config/lyxinclude.m4 index ead704b166..2c1a9af12a 100644 --- a/config/lyxinclude.m4 +++ b/config/lyxinclude.m4 @@ -420,6 +420,7 @@ if test x$GXX = xyes; then lyx_flags="$lyx_flags stdlib-debug" AC_DEFINE(_GLIBCXX_DEBUG, 1, [libstdc++ debug mode]) AC_DEFINE(_GLIBCXX_DEBUG_PEDANTIC, 1, [libstdc++ pedantic debug mode]) + AC_SUBST(STDLIB_DEBUG, "-D_GLIBCXX_DEBUG -D_GLIBCXX_DEBUG_PEDANTIC") ;; esac fi diff --git a/config/spell.m4 b/config/spell.m4 index a15f9f6b3d..152e485ad7 100644 --- a/config/spell.m4 +++ b/config/spell.m4 @@ -43,6 +43,24 @@ AC_DEFUN([CHECK_WITH_ENCHANT], fi ]) +AC_DEFUN([LYX_HAVE_HUNSPELL_CXXABI], +[ + AC_MSG_CHECKING([whether hunspell C++ (rather than C) ABI is provided]) + save_CXXFLAGS=$CXXFLAGS + CXXFLAGS="$ENCHANT_CFLAGS $AM_CXXFLAGS $CXXFLAGS" + +# in the C++ ABI, stem() returns a vector, in the C ABI, it returns an int + AC_TRY_COMPILE([#include ], + [Hunspell sp("foo", "bar"); + int i = sp.stem("test").size();], + [AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_HUNSPELL_CXXABI, 1, [Define to 1 if hunspell C++ (rather than C) ABI is detected]) + have_hunspell_cxx_abi=yes + ], + [AC_MSG_RESULT(no)]) + CXXFLAGS=$save_CXXFLAGS +]) + # Macro to add for using hunspell spellchecker libraries! -*- sh -*- AC_DEFUN([CHECK_WITH_HUNSPELL], [ @@ -66,6 +84,12 @@ AC_DEFUN([CHECK_WITH_HUNSPELL], AC_MSG_RESULT(no) fi fi + LYX_HAVE_HUNSPELL_CXXABI + if test $enable_stdlib_debug = "yes" -a -n "$have_hunspell_cxx_abi" ; then + LYX_WARNING([Compiling LyX with stdlib-debug and system hunspell libraries may lead to + crashes. Consider using --disable-stdlib-debug or --with-included-hunspell.]) + fi + ]) dnl Usage: LYX_USE_INCLUDED_HUNSPELL : select if the included hunspell should @@ -96,6 +120,7 @@ AC_DEFUN([LYX_CHECK_SPELL_ENGINES], dnl the user wanted to use the included hunspell, so do not check for external hunspell lyx_use_hunspell=true AC_DEFINE(USE_HUNSPELL, 1, [Define as 1 to use the hunspell library]) + AC_DEFINE(HAVE_HUNSPELL_CXXABI, 1, [Define to 1 if hunspell C++ (rather than C) ABI is detected]) lyx_flags="$lyx_flags use-hunspell" else CHECK_WITH_HUNSPELL diff --git a/development/cmake/ConfigureChecks.cmake b/development/cmake/ConfigureChecks.cmake index f09ba8bd92..3d6d5880fb 100644 --- a/development/cmake/ConfigureChecks.cmake +++ b/development/cmake/ConfigureChecks.cmake @@ -72,6 +72,36 @@ check_type_size("long long" HAVE_LONG_LONG) check_type_size(wchar_t HAVE_WCHAR_T) check_type_size(wint_t HAVE_WINT_T) +if(HUNSPELL_FOUND) + # check whether hunspell C++ (rather than C) ABI is provided + set(HunspellTestFile "${CMAKE_BINARY_DIR}/hunspelltest.cpp") + file(WRITE "${HunspellTestFile}" + " + #include + + int main() + { + Hunspell sp(\"foo\", \"bar\"); + int i = sp.stem(\"test\").size(); + return(0); + } + " + ) + + try_compile(HAVE_HUNSPELL_CXXABI + "${CMAKE_BINARY_DIR}" + "${HunspellTestFile}" + CMAKE_FLAGS + "-DINCLUDE_DIRECTORIES:STRING=${HUNSPELL_INCLUDE_DIR}" + "-DCMAKE_CXX_LINK_EXECUTABLE='${CMAKE_COMMAD} echo not linking now...'" + OUTPUT_VARIABLE LOG2) + + message(STATUS "HAVE_HUNSPELL_CXXABI = ${HAVE_HUNSPELL_CXXABI}") + #message(STATUS "LOG2 = ${LOG2}") + if(LYX_EXTERNAL_HUNSPELL AND LYX_STDLIB_DEBUG AND HAVE_HUNSPELL_CXXABI) + message(WARNING "Compiling LyX with stdlib-debug and system hunspell libraries may lead to crashes. Consider using -DLYX_STDLIB_DEBUG=OFF or -DLYX_EXTERNAL_HUNSPELL=OFF.") + endif() +endif() #check_cxx_source_compiles( # " diff --git a/development/cmake/configCompiler.h.cmake b/development/cmake/configCompiler.h.cmake index 52f629e7bb..8934986cb0 100644 --- a/development/cmake/configCompiler.h.cmake +++ b/development/cmake/configCompiler.h.cmake @@ -66,6 +66,9 @@ #define HAVE_ALLOCA #endif +/* whether hunspell C++ (rather than C) ABI is provided */ +#cmakedefine HAVE_HUNSPELL_CXXABI 1 + #cmakedefine HAVE_ICONV_CONST 1 #ifdef HAVE_ICONV_CONST #define ICONV_CONST const diff --git a/src/HunspellChecker.cpp b/src/HunspellChecker.cpp index 6dc6647b5c..1c2612e78e 100644 --- a/src/HunspellChecker.cpp +++ b/src/HunspellChecker.cpp @@ -356,7 +356,11 @@ SpellChecker::Result HunspellChecker::check(WordLangTuple const & wl) LYXERR(Debug::GUI, "spellCheck: \"" << wl.word() << "\", lang = " << wl.lang()->lang()) ; +#ifdef HAVE_HUNSPELL_CXXABI + if (h->spell(word_to_check, &info)) +#else if (h->spell(word_to_check.c_str(), &info)) +#endif return d->learned(wl) ? LEARNED_WORD : WORD_OK; if (info & SPELL_COMPOUND) { @@ -411,6 +415,11 @@ void HunspellChecker::suggest(WordLangTuple const & wl, return; string const encoding = h->get_dic_encoding(); string const word_to_check = to_iconv_encoding(wl.word(), encoding); +#ifdef HAVE_HUNSPELL_CXXABI + vector wlst = h->suggest(word_to_check); + for (auto const s : wlst) + suggestions.push_back(from_iconv_encoding(s, encoding)); +#else char ** suggestion_list; int const suggestion_number = h->suggest(&suggestion_list, word_to_check.c_str()); if (suggestion_number <= 0) @@ -418,6 +427,7 @@ void HunspellChecker::suggest(WordLangTuple const & wl, for (int i = 0; i != suggestion_number; ++i) suggestions.push_back(from_iconv_encoding(suggestion_list[i], encoding)); h->free_list(&suggestion_list, suggestion_number); +#endif } @@ -430,6 +440,11 @@ void HunspellChecker::stem(WordLangTuple const & wl, return; string const encoding = h->get_dic_encoding(); string const word_to_check = to_iconv_encoding(wl.word(), encoding); +#ifdef HAVE_HUNSPELL_CXXABI + vector wlst = h->stem(word_to_check); + for (auto const s : wlst) + suggestions.push_back(from_iconv_encoding(s, encoding)); +#else char ** suggestion_list; int const suggestion_number = h->stem(&suggestion_list, word_to_check.c_str()); if (suggestion_number <= 0) @@ -437,6 +452,7 @@ void HunspellChecker::stem(WordLangTuple const & wl, for (int i = 0; i != suggestion_number; ++i) suggestions.push_back(from_iconv_encoding(suggestion_list[i], encoding)); h->free_list(&suggestion_list, suggestion_number); +#endif } diff --git a/status.23x b/status.23x index d85e56d0fb..265657be5b 100644 --- a/status.23x +++ b/status.23x @@ -89,6 +89,9 @@ What's new * BUILD/INSTALLATION +- Support new hunspell C++ ABI if LyX is built against hunspell >= 1.5 + (bug 10547). + ** Bug fixes: