From f17f5617e05ea8a7f179586cc16c5bb05a0e9e2d Mon Sep 17 00:00:00 2001 From: Richard Heck Date: Sun, 1 Apr 2018 22:40:00 -0400 Subject: [PATCH] Fix bug #7404. This allows for external editing of ERT insets. Original patch by Georg Baum. Updated to 2.4dev by Riki Heck. --- lib/ui/stdcontext.inc | 3 ++ src/FuncCode.h | 2 + src/LyXAction.cpp | 16 +++++++ src/insets/InsetCollapsible.cpp | 1 + src/insets/InsetERT.cpp | 76 +++++++++++++++++++++++++++++++++ src/insets/InsetERT.h | 15 ++++++- 6 files changed, 112 insertions(+), 1 deletion(-) diff --git a/lib/ui/stdcontext.inc b/lib/ui/stdcontext.inc index a8a44da75c..7435dc3c91 100644 --- a/lib/ui/stdcontext.inc +++ b/lib/ui/stdcontext.inc @@ -664,6 +664,9 @@ Menuset Menu "context-ert" # repeat 1 is added as a work-around to not indicate this action as toggable Item "Wrap by Preview|y" "command-sequence repeat 1;inset-toggle;char-forward;char-backward;char-forward-select;preview-insert;char-backward;char-backward;inset-toggle" + Separator + Item "Edit Externally...|x" "inset-edit" + Item "End Editing Externally...|e" "inset-end-edit" End # diff --git a/src/FuncCode.h b/src/FuncCode.h index 6154cdd6a7..7b8fedc435 100644 --- a/src/FuncCode.h +++ b/src/FuncCode.h @@ -480,6 +480,8 @@ enum FuncCode LFUN_GRAPHICS_UNIFY, // sanda, 20180207 LFUN_MASTER_BUFFER_EXPORT, // rkh, 20180417 LFUN_LAYOUT_TOGGLE, // lasgouttes 20180514 + // 375 + LFUN_INSET_END_EDIT, // gb/rkh, 20180605 LFUN_LASTACTION // end of the table }; diff --git a/src/LyXAction.cpp b/src/LyXAction.cpp index c06a791772..6518013450 100644 --- a/src/LyXAction.cpp +++ b/src/LyXAction.cpp @@ -2027,6 +2027,11 @@ void LyXAction::init() * \var lyx::FuncCode lyx::LFUN_INSET_EDIT * \li Action: Edit the inset at cursor with an external application, if one is attributed. + If the inset is file based, the referenced file is edited. + Otherwise, the inset contents is written to a temporary file, + the inset is locked, and the temporary file is edited. + In this case, #LFUN_INSET_END_EDIT must be called to overtake + the changes and unlock the inset after editing is finished. * \li Syntax: inset-edit [] * \li Params: : Parameters for the inset. \n Currently only the filename will be considered. @@ -2036,6 +2041,17 @@ void LyXAction::init() { LFUN_INSET_EDIT, "inset-edit", ReadOnly | AtPoint, Edit }, + /*! + * \var lyx::FuncCode lyx::LFUN_INSET_END_EDIT + * \li Action: End editing the inset at cursor with an external application. + * This replaces the inset contents with the contents of the + * temporary file, deletes the file and unlocks the inset. + * \li Syntax: inset-end-edit + * \li Origin: gb, 11 Oct 2015 + * \endvar + */ + { LFUN_INSET_END_EDIT, "inset-end-edit", ReadOnly | AtPoint, Edit }, + /*! * \var lyx::FuncCode lyx::LFUN_INSET_END * \li Action: Move the cursor to the end of the current inset if it diff --git a/src/insets/InsetCollapsible.cpp b/src/insets/InsetCollapsible.cpp index 078e2dede3..76b0bc72f3 100644 --- a/src/insets/InsetCollapsible.cpp +++ b/src/insets/InsetCollapsible.cpp @@ -454,6 +454,7 @@ Inset * InsetCollapsible::editXY(Cursor & cur, int x, int y) { //lyxerr << "InsetCollapsible: edit xy" << endl; if (geometry(cur.bv()) == ButtonOnly + || !editable() || (view_[&cur.bv()].button_dim_.contains(x, y) && geometry(cur.bv()) != NoButton)) return this; diff --git a/src/insets/InsetERT.cpp b/src/insets/InsetERT.cpp index 2d96f952f6..2566547103 100644 --- a/src/insets/InsetERT.cpp +++ b/src/insets/InsetERT.cpp @@ -17,7 +17,9 @@ #include "BufferParams.h" #include "BufferView.h" #include "Cursor.h" +#include "CutAndPaste.h" #include "DispatchResult.h" +#include "Format.h" #include "FuncRequest.h" #include "FuncStatus.h" #include "Language.h" @@ -29,8 +31,11 @@ #include "Paragraph.h" #include "TextClass.h" +#include "support/docstream.h" +#include "support/FileName.h" #include "support/gettext.h" #include "support/lstrings.h" +#include "support/TempFile.h" #include @@ -46,6 +51,21 @@ InsetERT::InsetERT(Buffer * buf, CollapseStatus status) } +// Do not copy the temp file on purpose: If a copy of an inset which is +// currently being edited is made, then we simply copy the current contents. +InsetERT::InsetERT(InsetERT const & that) : InsetCollapsible(that) +{} + + +InsetERT & InsetERT::operator=(InsetERT const & that) +{ + if (&that == this) + return *this; + tempfile_.reset(); + return *this; +} + + void InsetERT::write(ostream & os) const { os << "ERT" << "\n"; @@ -109,6 +129,40 @@ int InsetERT::docbook(odocstream & os, OutputParams const &) const void InsetERT::doDispatch(Cursor & cur, FuncRequest & cmd) { switch (cmd.action()) { + case LFUN_INSET_EDIT: { + cur.push(*this); + text().selectAll(cur); + string const format = + cur.buffer()->params().documentClass().outputFormat(); + string const ext = theFormats().extension(format); + tempfile_.reset(new TempFile("ert_editXXXXXX." + ext)); + FileName const tempfilename = tempfile_->name(); + string const name = tempfilename.toFilesystemEncoding(); + ofdocstream os(name.c_str()); + os << cur.selectionAsString(false); + os.close(); + // Since we lock the inset while the external file is edited, + // we need to move the cursor outside and clear any selection inside + cur.clearSelection(); + cur.pop(); + cur.leaveInset(*this); + theFormats().edit(buffer(), tempfilename, format); + break; + } + case LFUN_INSET_END_EDIT: { + FileName const tempfilename = tempfile_->name(); + docstring const s = tempfilename.fileContents("UTF-8"); + cur.recordUndoInset(this); + cur.push(*this); + text().selectAll(cur); + cap::replaceSelection(cur); + cur.text()->insertStringAsLines(cur, s, cur.current_font); + // FIXME it crashes without this + cur.fixIfBroken(); + tempfile_.reset(); + cur.pop(); + break; + } case LFUN_INSET_MODIFY: if (cmd.getArg(0) == "ert") { cur.recordUndoInset(this); @@ -128,6 +182,12 @@ bool InsetERT::getStatus(Cursor & cur, FuncRequest const & cmd, FuncStatus & status) const { switch (cmd.action()) { + case LFUN_INSET_EDIT: + status.setEnabled(tempfile_ == 0); + return true; + case LFUN_INSET_END_EDIT: + status.setEnabled(tempfile_ != 0); + return true; case LFUN_INSET_MODIFY: if (cmd.getArg(0) == "ert") { status.setEnabled(true); @@ -141,6 +201,22 @@ bool InsetERT::getStatus(Cursor & cur, FuncRequest const & cmd, } +bool InsetERT::editable() const +{ + if (tempfile_) + return false; + return InsetCollapsible::editable(); +} + + +bool InsetERT::descendable(BufferView const & bv) const +{ + if (tempfile_) + return false; + return InsetCollapsible::descendable(bv); +} + + docstring const InsetERT::buttonLabel(BufferView const & bv) const { if (decoration() == InsetLayout::CLASSIC) diff --git a/src/insets/InsetERT.h b/src/insets/InsetERT.h index 87ed11616a..bfe15126da 100644 --- a/src/insets/InsetERT.h +++ b/src/insets/InsetERT.h @@ -15,7 +15,6 @@ #include "InsetCollapsible.h" - namespace lyx { /** A collapsible text inset for LaTeX insertions. @@ -29,10 +28,18 @@ namespace lyx { class Language; +namespace support { + class TempFile; +} + class InsetERT : public InsetCollapsible { public: /// InsetERT(Buffer *, CollapseStatus status = Open); + /// + InsetERT(InsetERT const &); + /// + InsetERT & operator=(InsetERT const &); /// static CollapseStatus string2params(std::string const &); /// @@ -62,12 +69,18 @@ private: void doDispatch(Cursor & cur, FuncRequest & cmd); /// bool getStatus(Cursor & cur, FuncRequest const & cmd, FuncStatus &) const; + /// + bool editable() const; + /// + bool descendable(BufferView const &) const; /// Inset * clone() const { return new InsetERT(*this); } /// docstring const buttonLabel(BufferView const & bv) const; /// bool allowSpellCheck() const { return false; } + /// + unique_ptr tempfile_; };