[rkward-cvs] SF.net SVN: rkward:[3535] trunk/rkward

tfry at users.sourceforge.net tfry at users.sourceforge.net
Thu May 5 16:04:37 UTC 2011


Revision: 3535
          http://rkward.svn.sourceforge.net/rkward/?rev=3535&view=rev
Author:   tfry
Date:     2011-05-05 16:04:37 +0000 (Thu, 05 May 2011)

Log Message:
-----------
Add function rk.print.code() to print _highlighted_ R code to the output window.
Note: Much of the implementation details is stolen from the katepart export plugin (LGPL v2)

Modified Paths:
--------------
    trunk/rkward/ChangeLog
    trunk/rkward/rkward/rbackend/rinterface.cpp
    trunk/rkward/rkward/rbackend/rpackages/rkward/R/public.R
    trunk/rkward/rkward/rbackend/rpackages/rkward/man/rk.results.Rd
    trunk/rkward/rkward/windows/rkcommandeditorwindow.cpp
    trunk/rkward/rkward/windows/rkcommandeditorwindow.h

Modified: trunk/rkward/ChangeLog
===================================================================
--- trunk/rkward/ChangeLog	2011-04-27 18:23:48 UTC (rev 3534)
+++ trunk/rkward/ChangeLog	2011-05-05 16:04:37 UTC (rev 3535)
@@ -1,3 +1,4 @@
+- Added function rk.print.code() to write highlighted R code to the output window		# TODO: Next, implement the 'carbon copy' feature
 - Box plot plugin gains support for grouped outcome data
 - Fixed: Pressing Ctrl+C would not reset syntactically incomplete commands in the R console
 - Crosstabs N to 1 plugin gains options to compute proportions and margins (thanks to Andrés Necochea)

Modified: trunk/rkward/rkward/rbackend/rinterface.cpp
===================================================================
--- trunk/rkward/rkward/rbackend/rinterface.cpp	2011-04-27 18:23:48 UTC (rev 3534)
+++ trunk/rkward/rkward/rbackend/rinterface.cpp	2011-05-05 16:04:37 UTC (rev 3535)
@@ -624,6 +624,8 @@
 		} else {
 			RK_ASSERT (false);
 		}
+	} else if (call == "highlightRCode") {
+		issueCommand (".rk.set.reply (" + RObject::rQuote (RKCommandHighlighter::commandToHTML (calllist.value (1))) + ")", RCommand::App | RCommand::Sync, QString::null, 0, 0, in_chain);
 	} else if (call == "getWorkspaceUrl") {
 		KUrl url = RObjectList::getObjectList ()->getWorkspaceURL ();
 		if (!url.isEmpty ()) issueCommand (".rk.set.reply (" + RObject::rQuote (url.url ()) + ")", RCommand::App | RCommand::Sync, QString::null, 0, 0, in_chain);

Modified: trunk/rkward/rkward/rbackend/rpackages/rkward/R/public.R
===================================================================
--- trunk/rkward/rkward/rbackend/rpackages/rkward/R/public.R	2011-04-27 18:23:48 UTC (rev 3534)
+++ trunk/rkward/rkward/rbackend/rpackages/rkward/R/public.R	2011-05-05 16:04:37 UTC (rev 3535)
@@ -193,6 +193,10 @@
 	}
 }
 
+"rk.print.code" <- function(code) {
+	.rk.cat.output (.rk.do.call ("highlightRCode", as.character (code)))
+}
+
 "rk.header" <- function (title, parameters=list (), level=1) {
 	sink (rk.get.output.html.file(), append=TRUE)
 	on.exit (sink ())

Modified: trunk/rkward/rkward/rbackend/rpackages/rkward/man/rk.results.Rd
===================================================================
--- trunk/rkward/rkward/rbackend/rpackages/rkward/man/rk.results.Rd	2011-04-27 18:23:48 UTC (rev 3534)
+++ trunk/rkward/rkward/rbackend/rpackages/rkward/man/rk.results.Rd	2011-05-05 16:04:37 UTC (rev 3535)
@@ -1,5 +1,6 @@
 \name{rk.results}
 \alias{rk.print}
+\alias{rk.print.code}
 \alias{rk.print.literal}
 \alias{rk.header}
 \alias{rk.results}
@@ -14,6 +15,7 @@
 \usage{
 rk.print(x, ...)
 rk.print.literal(x)
+rk.print.code(code)
 rk.header(title, parameters = list(), level = 1)
 rk.results(x, titles = NULL)
 rk.describe.alternative(x)
@@ -21,6 +23,7 @@
 
 \arguments{
 \item{x}{any R object to be printed/exported. A suitable list in case of \code{rk.describe.alternative}.}
+\item{code}{a character vector (single string) of R code}
 \item{title}{a string, used as a header for the html output}
 \item{level}{an integer, header level. For example, \code{level=2} creates the header with \code{<h2></h>} tag.}
 \item{parameters}{a list, preferably named, giving a list of "parameters" to be printed to the output}
@@ -32,8 +35,10 @@
 
 \code{rk.print.literal} prints/exports the given object using a \code{paste(x, collapse="\n")} construct to the output (html) file.
 
-\code{rk.header} prints a html header, possibly with parameters, to the output file. See example.
+\code{rk.print.code} applies syntax highlighting to the given code string, and writes it to the output (html) file.
 
+\code{rk.header} prints a header / caption, possibly with parameters, to the output file. See example.
+
 \code{rk.results} is similar to \code{rk.print} but prints in a more tabulated fashion. This has been implemented only for certain types of \code{x}: tables, lists (or data.frames), and vectors. See example.
 
 \code{rk.describe.alternatives} describes the alternative (H1) hypothesis of a \code{htest}. This is similar to \code{stats:::print.htext} and makes sense only when \code{x$alternatives} exists.
@@ -61,6 +66,7 @@
 nm <- rk.get.description (x1,x2)
 
 result <- t.test (x1, x2, alternative="less")
+rk.print.code ("result <- t.test (x1, x2, alternative=\"less\")")
 
 rk.header (result$method,
   parameters=list ("Comparing", paste (nm[1], "against", nm[2]),

Modified: trunk/rkward/rkward/windows/rkcommandeditorwindow.cpp
===================================================================
--- trunk/rkward/rkward/windows/rkcommandeditorwindow.cpp	2011-04-27 18:23:48 UTC (rev 3534)
+++ trunk/rkward/rkward/windows/rkcommandeditorwindow.cpp	2011-05-05 16:04:37 UTC (rev 3535)
@@ -80,6 +80,13 @@
 #define GET_HELP_URL 1
 #define NUM_BLOCK_RECORDS 6
 
+/** set syntax highlighting-mode to R syntax. Outside of class, in order to allow use from the on demand code highlighter */
+void setRHighlighting (KTextEditor::Document *doc) {
+	RK_TRACE (COMMANDEDITOR);
+
+	if (!doc->setHighlightingMode("R Script")) RK_DO (qDebug ("R syntax highlighting defintion not found!"), COMMANDEDITOR, DL_ERROR);
+}
+
 RKCommandEditorWindow::RKCommandEditorWindow (QWidget *parent, bool use_r_highlighting) : RKMDIWindow (parent, RKMDIWindow::CommandEditorWindow) {
 	RK_TRACE (COMMANDEDITOR);
 
@@ -128,7 +135,7 @@
 	cc_iface = 0;
 	hinter = 0;
 	if (use_r_highlighting) {
-		setRHighlighting ();
+		setRHighlighting (m_doc);
 		cc_iface = qobject_cast<KTextEditor::CodeCompletionInterface*> (m_view);
 		if (cc_iface) {
 			cc_iface->setAutomaticInvocationEnabled (true);
@@ -324,14 +331,6 @@
 	QWidget::closeEvent (e);
 }
 
-// KDE4 TODO: inline
-void RKCommandEditorWindow::setRHighlighting () {
-	RK_TRACE (COMMANDEDITOR);
-
-	// set syntax-highlighting for R
-	if (!m_doc->setHighlightingMode("R Script")) RK_DO (qDebug ("R syntax highlighting defintion not found!"), COMMANDEDITOR, DL_ERROR);
-}
-
 void RKCommandEditorWindow::copy () {
 	RK_TRACE (COMMANDEDITOR);
 
@@ -350,7 +349,7 @@
 	// encoding must be set *before* loading the file
 	if (!encoding.isEmpty ()) m_doc->setEncoding (encoding);
 	if (m_doc->openUrl (url)){
-		if (use_r_highlighting) setRHighlighting ();
+		if (use_r_highlighting) setRHighlighting (m_doc);
 		setReadOnly (read_only);
 
 		updateCaption ();
@@ -1034,4 +1033,130 @@
 	return QVariant ();
 }
 
+
+
+// static
+KTextEditor::Document* RKCommandHighlighter::_doc = 0;
+KTextEditor::Document* RKCommandHighlighter::getDoc () {
+	if (_doc) return _doc;
+
+	RK_TRACE (COMMANDEDITOR);
+	KTextEditor::Editor* editor = KTextEditor::editor("katepart");
+	RK_ASSERT (editor);
+
+	_doc = editor->createDocument (RKWardMainWindow::getMain ());
+// NOTE: In KDE 4.4.5, a (dummy) view is needed to access highlighting attributes. According to a katepart error message, this will be fixed, eventually.
+// TODO: check whether this is fixed in some later version of KDE
+	QWidget* view = _doc->createView (0);
+	view->hide ();
+	RK_ASSERT (_doc);
+	setRHighlighting (_doc);
+	return _doc;
+}
+
+#if KDE_IS_VERSION(4,4,0)
+#	include <ktexteditor/highlightinterface.h>
+#include <QTextDocument>
+
+//////////
+// NOTE: Most of the exporting code is copied from the katepart HTML exporter plugin more or less verbatim! (Source license: LGPL v2)
+//////////
+QString exportText(const QString& text, const KTextEditor::Attribute::Ptr& attrib, const KTextEditor::Attribute::Ptr& m_defaultAttribute) {
+	if ( !attrib || !attrib->hasAnyProperty() || attrib == m_defaultAttribute ) {
+		return (Qt::escape(text));
+	}
+
+	QString ret;
+	if ( attrib->fontBold() ) {
+		ret.append ("<b>");
+	}
+	if ( attrib->fontItalic() ) {
+		ret.append ("<i>");
+	}
+
+	bool writeForeground = attrib->hasProperty(QTextCharFormat::ForegroundBrush)
+		&& (!m_defaultAttribute || attrib->foreground().color() != m_defaultAttribute->foreground().color());
+	bool writeBackground = attrib->hasProperty(QTextCharFormat::BackgroundBrush)
+		&& (!m_defaultAttribute || attrib->background().color() != m_defaultAttribute->background().color());
+
+	if ( writeForeground || writeBackground ) {
+		ret.append (QString("<span style='%1%2'>")
+					.arg(writeForeground ? QString(QLatin1String("color:") + attrib->foreground().color().name() + QLatin1Char(';')) : QString())
+					.arg(writeBackground ? QString(QLatin1String("background:") + attrib->background().color().name() + QLatin1Char(';')) : QString()));
+	}
+
+	ret.append (Qt::escape(text));
+
+	if ( writeBackground || writeForeground ) {
+		ret.append ("</span>");
+	}
+	if ( attrib->fontItalic() ) {
+		ret.append ("</i>");
+	}
+	if ( attrib->fontBold() ) {
+		ret.append ("</b>");
+	}
+
+	return ret;
+}
+
+QString RKCommandHighlighter::commandToHTML (const QString r_command) {
+	KTextEditor::Document* doc = getDoc ();
+	KTextEditor::HighlightInterface *iface = qobject_cast<KTextEditor::HighlightInterface*> (_doc);
+	RK_ASSERT (iface);
+	if (!iface) return (QString ("<pre>") + r_command + "</pre>");
+
+	doc->setText (r_command);
+	setRHighlighting (doc);
+	QString ret;
+	KTextEditor::Attribute::Ptr m_defaultAttribute = iface->defaultStyle(KTextEditor::HighlightInterface::dsNormal);
+	if ( !m_defaultAttribute ) {
+		ret = "<pre>";
+	} else {
+		ret = QString("<pre style='%1%2%3%4'>")
+				.arg(m_defaultAttribute->fontBold() ? "font-weight:bold;" : "")
+				.arg(m_defaultAttribute->fontItalic() ? "text-style:italic;" : "")
+				.arg("color:" + m_defaultAttribute->foreground().color().name() + ';');
+//				.arg("background-color:" + m_defaultAttribute->background().color().name() + ';');
+	}
+
+	const KTextEditor::Attribute::Ptr noAttrib(0);
+
+	for (int i = 0; i < doc->lines (); ++i)
+	{
+		const QString &line = doc->line(i);
+
+		QList<KTextEditor::HighlightInterface::AttributeBlock> attribs = iface->lineAttributes(i);
+
+		int lineStart = 0;
+		int remainingChars = line.length();
+		int handledUntil = lineStart;
+
+		foreach ( const KTextEditor::HighlightInterface::AttributeBlock& block, attribs ) {
+			int start = qMax(block.start, lineStart);
+			if ( start > handledUntil ) {
+				ret += exportText( line.mid( handledUntil, start - handledUntil ), noAttrib, m_defaultAttribute );
+			}
+			int length = qMin(block.length, remainingChars);
+			ret += exportText( line.mid( start, length ), block.attribute, m_defaultAttribute);
+			handledUntil = start + length;
+		}
+
+		if ( handledUntil < lineStart + remainingChars ) {
+			ret += exportText( line.mid( handledUntil, remainingChars ), noAttrib, m_defaultAttribute );
+		}
+
+		if (i < (doc->lines () - 1)) ret.append ("\n");
+	}
+	ret.append ("</pre>\n");
+
+	return ret;
+}
+
+#else	// KDE < 4.4: No Highlighting Interface
+QString RKCommandHighlighter::commandToHTML (const QString r_command) {
+	return (QString ("<pre>") + r_command + "</pre>");
+}
+#endif
+
 #include "rkcommandeditorwindow.moc"

Modified: trunk/rkward/rkward/windows/rkcommandeditorwindow.h
===================================================================
--- trunk/rkward/rkward/windows/rkcommandeditorwindow.h	2011-04-27 18:23:48 UTC (rev 3534)
+++ trunk/rkward/rkward/windows/rkcommandeditorwindow.h	2011-05-05 16:04:37 UTC (rev 3535)
@@ -251,8 +251,6 @@
 	RKCodeCompletionModel *completion_model;
 
 	QTimer *completion_timer;
-/** set syntax highlighting-mode to R syntax */
-	void setRHighlighting ();
 
 	void initializeActions (KActionCollection* ac);
 
@@ -293,4 +291,13 @@
 	KUrl delete_on_close;
 };
 
+/** Simple class to provide HTML highlighting for arbitrary R code. */
+class RKCommandHighlighter {
+public:
+	static QString commandToHTML (const QString r_command);
+private:
+	static KTextEditor::Document* getDoc ();
+	static KTextEditor::Document* _doc;
+};
+
 #endif


This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.




More information about the rkward-tracker mailing list