[LyX/master] Introduce "copy latex" lfun variant (#13331)

Juergen Spitzmueller <[email protected]>
Newsgroups gmane.editors.lyx.cvs
Message-ID <[email protected]>
commit 0768b232583facbd4fdff8d1cb5c744479366a32
Author: Juergen Spitzmueller <[email protected]>
Date:   Thu Aug 13 14:51:30 2026 +0200

    Introduce "copy latex" lfun variant (#13331)
    
    This copies the LaTeX output of the selection (rather than plaintext)
    to the external clipboard
    
    This is pretty basic and likely has rouzgh edges, so it should by
    carefully tested before the lfun is exposed to the UI.
---
 lib/RELEASE-NOTES           |  4 ++++
 src/BufferView.cpp          | 19 +++++++++++++++----
 src/Cursor.cpp              |  8 +++++++-
 src/Cursor.h                |  3 ++-
 src/CutAndPaste.cpp         |  4 ++--
 src/CutAndPaste.h           |  2 +-
 src/LyXAction.cpp           |  3 ++-
 src/Paragraph.cpp           | 17 +++++++++++++----
 src/Paragraph.h             |  3 ++-
 src/insets/InsetTabular.cpp | 28 ++++++++++++++++++++--------
 src/insets/InsetTabular.h   |  2 +-
 11 files changed, 69 insertions(+), 24 deletions(-)

diff --git a/lib/RELEASE-NOTES b/lib/RELEASE-NOTES
index 78621c7750..a6a24e82d3 100644
--- a/lib/RELEASE-NOTES
+++ b/lib/RELEASE-NOTES
@@ -65,6 +65,10 @@
 - The function language now accepts an additional "local" argument
   which ensures the language switch is an inline one (e.g. \foreignlanguage).
 
+- The function copy now accepts an optional argument "latex" which will cause
+  LyX to copy the selection in its LaTeX representation to the external clipboard.
+  The argument "plain" is equal to the default (copy as plain text string).
+
 !!!The following LyX functions have been removed in 2.6:
 
 - keymap-primary, keymap-secondary and keymap-toggle have been removed
diff --git a/src/BufferView.cpp b/src/BufferView.cpp
index 304a939c5b..8a57cf0e49 100644
--- a/src/BufferView.cpp
+++ b/src/BufferView.cpp
@@ -1420,9 +1420,15 @@ bool BufferView::getStatus(FuncRequest const & cmd, FuncStatus & flag)
 		break;
 	}
 
-	case LFUN_COPY:
+	case LFUN_COPY: {
+		string const arg = cmd.getArg(0);
+		if (!arg.empty() && arg != "latex" && arg != "plain") {
+			flag.setEnabled(false);
+			break;
+		}
 		flag.setEnabled(cur.selection());
 		break;
+	}
 
 	case LFUN_STATISTICS_REFERENCE_CLAMP: {
 		// disable optitem reset if clamp not used
@@ -2670,7 +2676,8 @@ void BufferView::dispatch(FuncRequest const & cmd, DispatchResult & dr)
 		break;
 	}
 
-	case LFUN_COPY:
+	case LFUN_COPY: {
+		bool const latex = cmd.getArg(0) == "latex";
 		// With multi-cell table content, we pass down to the inset
 		if (cur.inTexted() && cur.selection()
 		    && cur.selectionBegin().idx() != cur.selectionEnd().idx()) {
@@ -2678,9 +2685,13 @@ void BufferView::dispatch(FuncRequest const & cmd, DispatchResult & dr)
 			dispatched = dr.dispatched();
 			break;
 		}
-		cap::copySelection(cur);
-		cur.message(_("Copy"));
+		cap::copySelection(cur, latex);
+		if (latex)
+			cur.message(_("Copy as LaTeX"));
+		else
+			cur.message(_("Copy"));
 		break;
+	}
 
 	case LFUN_SERVER_GET_XY: {
 		Point const p = getPos(cursor());
diff --git a/src/Cursor.cpp b/src/Cursor.cpp
index 7683dcd1e2..09bd78c7ca 100644
--- a/src/Cursor.cpp
+++ b/src/Cursor.cpp
@@ -340,7 +340,8 @@ docstring parbreak(CursorData const * cur)
 }
 
 
-docstring CursorData::selectionAsString(bool const with_label, bool const skipdelete) const
+docstring CursorData::selectionAsString(bool const with_label, bool const skipdelete,
+					bool const latex) const
 {
 	if (!selection())
 		return docstring();
@@ -360,6 +361,11 @@ docstring CursorData::selectionAsString(bool const with_label, bool const skipde
 		seq_label = AS_STR_INSETS | AS_STR_SKIPDELETE;
 	}
 
+	if (latex) {
+		label |= AS_STR_LATEX;
+		seq_label |= AS_STR_LATEX;
+	}
+
 	idx_type const startidx = selBegin().idx();
 	idx_type const endidx = selEnd().idx();
 	if (startidx != endidx) {
diff --git a/src/Cursor.h b/src/Cursor.h
index 879dce1033..1307217338 100644
--- a/src/Cursor.h
+++ b/src/Cursor.h
@@ -160,7 +160,8 @@ public:
 
 	///
 	docstring selectionAsString(bool const with_label,
-				    bool const skipdelete = false) const;
+				    bool const skipdelete = false,
+				    bool const latex = false) const;
 	/// get some interesting description of top position
 	void info(odocstream & os, bool devel_mode) const;
 	///
diff --git a/src/CutAndPaste.cpp b/src/CutAndPaste.cpp
index 7dc654448b..81d73d6446 100644
--- a/src/CutAndPaste.cpp
+++ b/src/CutAndPaste.cpp
@@ -1045,9 +1045,9 @@ void cutSelectionToTemp(Cursor & cur, bool realcut)
 }
 
 
-void copySelection(Cursor const & cur)
+void copySelection(Cursor const & cur, bool const latex)
 {
-	copySelection(cur, cur.selectionAsString(true, true));
+	copySelection(cur, cur.selectionAsString(true, true, latex));
 }
 
 
diff --git a/src/CutAndPaste.h b/src/CutAndPaste.h
index e011e03466..bed6db326d 100644
--- a/src/CutAndPaste.h
+++ b/src/CutAndPaste.h
@@ -71,7 +71,7 @@ void cutSelection(Cursor & cur, bool realcut = true);
 void cutSelectionToTemp(Cursor & cur, bool realcut = true);
 
 /// Push the current selection to the cut buffer and the system clipboard.
-void copySelection(Cursor const & cur);
+void copySelection(Cursor const & cur, bool const latex = false);
 /// Like copySelection, but only put to temporary cut buffer
 void copySelectionToTemp(Cursor const & cur);
 ///
diff --git a/src/LyXAction.cpp b/src/LyXAction.cpp
index de5c69f4a8..9bb55913e2 100644
--- a/src/LyXAction.cpp
+++ b/src/LyXAction.cpp
@@ -1435,7 +1435,8 @@ void LyXAction::init()
 /*!
  * \var lyx::FuncCode lyx::LFUN_COPY
  * \li Action: Copies the current selection to the clipboard.
- * \li Syntax: copy
+ * \li Syntax: copy [<type>]
+ * \li Params: <type>: type of copy, possible values: plain (= default), latex
  * \endvar
  */
 		{ LFUN_COPY, "copy", ReadOnly, Edit },
diff --git a/src/Paragraph.cpp b/src/Paragraph.cpp
index 197d32ee42..b73074bb27 100644
--- a/src/Paragraph.cpp
+++ b/src/Paragraph.cpp
@@ -4599,6 +4599,7 @@ docstring Paragraph::asString(int options) const
 docstring Paragraph::asString(pos_type beg, pos_type end, int options, const OutputParams * runparams) const
 {
 	odocstringstream os;
+	otexstream ots(os);
 
 	if (beg == 0
 	    && options & AS_STR_LABEL
@@ -4617,9 +4618,12 @@ docstring Paragraph::asString(pos_type beg, pos_type end, int options, const Out
 			continue;
 		char_type const c = d->text_[i];
 		if (isPrintable(c) || c == '\t'
-		    || (c == '\n' && (options & AS_STR_NEWLINES)))
-			os.put(c);
-		else if (c == META_INSET && (options & AS_STR_INSETS)) {
+		    || (c == '\n' && (options & AS_STR_NEWLINES))) {
+			if (options & AS_STR_LATEX)
+				ots.put(c);
+			else
+				os.put(c);
+		} else if (c == META_INSET && (options & AS_STR_INSETS)) {
 			if (c == META_INSET && (options & AS_STR_PLAINTEXT)) {
 				LASSERT(runparams != nullptr, return docstring());
 				if (runparams->find_effective() && getInset(i)->findUsesToString())
@@ -4632,7 +4636,12 @@ docstring Paragraph::asString(pos_type beg, pos_type end, int options, const Out
 				OutputParams rp(&buf.params().encoding());
 				Font const font(inherit_font, buf.params().language);
 				rp.local_font = &font;
-				otexstream ots(os);
+				getInset(i)->latex(ots, rp);
+			} else if (c == META_INSET && (options & AS_STR_LATEX)) {
+				Buffer const & buf = getInset(i)->buffer();
+				OutputParams rp(&buf.params().encoding());
+				Font const font(inherit_font, buf.params().language);
+				rp.local_font = &font;
 				getInset(i)->latex(ots, rp);
 			} else {
 				getInset(i)->toString(os);
diff --git a/src/Paragraph.h b/src/Paragraph.h
index ce4e9ddce3..a77b50bcee 100644
--- a/src/Paragraph.h
+++ b/src/Paragraph.h
@@ -129,7 +129,8 @@ enum AsStringParameter
 	AS_STR_NEWLINES = 4, ///< Get also newline characters.
 	AS_STR_SKIPDELETE = 8, ///< Skip deleted text in change tracking.
 	AS_STR_PLAINTEXT = 16, ///< Don't export formatting when descending into insets.
-	AS_STR_MATHED = 32 ///< Use a format suitable for mathed (eg. for InsetRef).
+	AS_STR_MATHED = 32, ///< Use a format suitable for mathed (eg. for InsetRef).
+	AS_STR_LATEX = 64 ///< LaTeX output.
 };
 
 
diff --git a/src/insets/InsetTabular.cpp b/src/insets/InsetTabular.cpp
index cc68ce6d97..65b333e06a 100644
--- a/src/insets/InsetTabular.cpp
+++ b/src/insets/InsetTabular.cpp
@@ -5968,12 +5968,14 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd)
 		}
 		break;
 
-	case LFUN_COPY:
+	case LFUN_COPY: {
+		bool const latex = cmd.getArg(0) == "latex";
 		if (cur.selIsMultiCell())
-			copySelection(cur);
+			copySelection(cur, latex);
 		else
 			cell(cur.idx())->dispatch(cur, cmd);
 		break;
+	}
 
 	case LFUN_CUT:
 		if (cur.selIsMultiCell()) {
@@ -8127,7 +8129,7 @@ void InsetTabular::tabularFeatures(Cursor & cur,
 }
 
 
-bool InsetTabular::copySelection(Cursor & cur)
+bool InsetTabular::copySelection(Cursor & cur, bool const latex)
 {
 	if (!cur.selection())
 		return false;
@@ -8154,11 +8156,21 @@ bool InsetTabular::copySelection(Cursor & cur)
 
 	paste_tabular->setBuffer(tabular.buffer());
 
-	odocstringstream os;
-	OutputParams const runparams(nullptr);
-	paste_tabular->plaintext(os, runparams, 0, true, '\t', INT_MAX);
-	// Needed for the "Edit->Paste recent" menu and the system clipboard.
-	cap::copySelection(cur, os.str());
+	if (latex) {
+		otexstringstream ots;
+		Buffer const & buf = paste_tabular->buffer();
+		OutputParams runparams(&buf.params().encoding());
+		Font const font(inherit_font, buf.params().language);
+		runparams.local_font = &font;
+		paste_tabular->latex(ots, runparams);
+		cap::copySelection(cur, ots.str());
+	} else {
+		OutputParams const runparams(nullptr);
+		odocstringstream os;
+		paste_tabular->plaintext(os, runparams, 0, true, '\t', INT_MAX);
+		// Needed for the "Edit->Paste recent" menu and the system clipboard.
+		cap::copySelection(cur, os.str());
+	}
 
 	// mark tabular stack dirty
 	// FIXME: this is a workaround for bug 1919. Should be removed for 1.5,
diff --git a/src/insets/InsetTabular.h b/src/insets/InsetTabular.h
index 0b7c106cbb..556ae2d250 100644
--- a/src/insets/InsetTabular.h
+++ b/src/insets/InsetTabular.h
@@ -1311,7 +1311,7 @@ private:
 	///
 	int cellYPos(idx_type cell) const;
 	///
-	bool copySelection(Cursor & cur);
+	bool copySelection(Cursor & cur, bool const latex = false);
 	///
 	bool pasteClipboard(Cursor & cur);
 	///
-- 
lyx-cvs mailing list
[email protected]
https://lists.lyx.org/mailman/listinfo/lyx-cvs
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.