-
-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Summary: Add the markdown entry to Cantor. Markdown support enables users to write a document with runnable code in Markdown style. This implementation supports LaTeX just like the text entry. A third-party library Discount is linked in order to convert markdown into HTML. Update CMakeLists.txt A screenshot for preview: {F6186425} Reviewers: pino, #cantor, filipesaraiva, sirgienko Reviewed By: #cantor, filipesaraiva, sirgienko Subscribers: sirgienko, filipesaraiva, pino, asemke, kde-edu Tags: #kde_edu Maniphest Tasks: T9108 Closes T9108 Differential Revision: https://phabricator.kde.org/D14738
- Loading branch information
1 parent
a441853
commit ea6b09e
Showing
12 changed files
with
414 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
# - Find Discount | ||
# Find the Discount markdown library. | ||
# | ||
# This module defines | ||
# Discount_FOUND - whether the Discount library was found | ||
# Discount_LIBRARIES - the Discount library | ||
# Discount_INCLUDE_DIR - the include path of the Discount library | ||
|
||
# Copyright (c) 2017, Julian Wolff, <wolff@julianwolff.de> | ||
# Copyright (c) 2018, Sune Vuorela, <sune@kde.org> | ||
# | ||
# Redistribution and use is allowed according to the terms of the BSD license. | ||
# For details see the accompanying COPYING-CMAKE-SCRIPTS file. | ||
|
||
|
||
if (Discount_INCLUDE_DIR AND Discount_LIBRARIES) | ||
|
||
# Already in cache | ||
set (Discount_FOUND TRUE) | ||
|
||
else (Discount_INCLUDE_DIR AND Discount_LIBRARIES) | ||
|
||
find_library (Discount_LIBRARIES | ||
NAMES markdown libmarkdown | ||
) | ||
|
||
find_path (Discount_INCLUDE_DIR | ||
NAMES mkdio.h | ||
) | ||
|
||
include (FindPackageHandleStandardArgs) | ||
find_package_handle_standard_args (Discount DEFAULT_MSG Discount_LIBRARIES Discount_INCLUDE_DIR) | ||
|
||
endif (Discount_INCLUDE_DIR AND Discount_LIBRARIES) | ||
|
||
mark_as_advanced(Discount_INCLUDE_DIR Discount_LIBRARIES) | ||
|
||
if (Discount_FOUND) | ||
add_library(Discount::Lib UNKNOWN IMPORTED) | ||
set_target_properties(Discount::Lib PROPERTIES INTERFACE_INCLUDE_DIRECTORIES ${Discount_INCLUDE_DIR} IMPORTED_LOCATION ${Discount_LIBRARIES}) | ||
endif() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,239 @@ | ||
/* | ||
This program is free software; you can redistribute it and/or | ||
modify it under the terms of the GNU General Public License | ||
as published by the Free Software Foundation; either version 2 | ||
of the License, or (at your option) any later version. | ||
This program is distributed in the hope that it will be useful, | ||
but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
GNU General Public License for more details. | ||
You should have received a copy of the GNU General Public License | ||
along with this program; if not, write to the Free Software | ||
Foundation, Inc., 51 Franklin Street, Fifth Floor, | ||
Boston, MA 02110-1301, USA. | ||
--- | ||
Copyright (C) 2018 Yifei Wu <kqwyfg@gmail.com> | ||
*/ | ||
|
||
#include "markdownentry.h" | ||
|
||
#include "config-cantor.h" | ||
|
||
#ifdef Discount_FOUND | ||
extern "C" { | ||
#include <mkdio.h> | ||
} | ||
#endif | ||
|
||
#include <QDebug> | ||
|
||
MarkdownEntry::MarkdownEntry(Worksheet* worksheet) : WorksheetEntry(worksheet), m_textItem(new WorksheetTextItem(this, Qt::TextEditorInteraction)), rendered(false) | ||
{ | ||
m_textItem->enableRichText(false); | ||
m_textItem->installEventFilter(this); | ||
connect(m_textItem, &WorksheetTextItem::moveToPrevious, this, &MarkdownEntry::moveToPreviousEntry); | ||
connect(m_textItem, &WorksheetTextItem::moveToNext, this, &MarkdownEntry::moveToNextEntry); | ||
connect(m_textItem, SIGNAL(execute()), this, SLOT(evaluate())); | ||
} | ||
|
||
MarkdownEntry::~MarkdownEntry() | ||
{ | ||
} | ||
|
||
bool MarkdownEntry::isEmpty() | ||
{ | ||
return m_textItem->document()->isEmpty(); | ||
} | ||
|
||
int MarkdownEntry::type() const | ||
{ | ||
return Type; | ||
} | ||
|
||
bool MarkdownEntry::acceptRichText() | ||
{ | ||
return false; | ||
} | ||
|
||
bool MarkdownEntry::focusEntry(int pos, qreal xCoord) | ||
{ | ||
if (aboutToBeRemoved()) | ||
return false; | ||
m_textItem->setFocusAt(pos, xCoord); | ||
return true; | ||
} | ||
|
||
void MarkdownEntry::setContent(const QString& content) | ||
{ | ||
rendered = false; | ||
plain = content; | ||
QTextDocument* doc = m_textItem->document(); | ||
doc->setPlainText(plain); | ||
m_textItem->setDocument(doc); | ||
} | ||
|
||
void MarkdownEntry::setContent(const QDomElement& content, const KZip& file) | ||
{ | ||
Q_UNUSED(file); | ||
|
||
rendered = content.attribute(QLatin1String("rendered"), QLatin1String("1")) == QLatin1String("1"); | ||
QDomElement htmlEl = content.firstChildElement(QLatin1String("HTML")); | ||
if(!htmlEl.isNull()) | ||
html = htmlEl.text(); | ||
else | ||
{ | ||
html = QLatin1String(""); | ||
rendered = false; // No html provided. Assume that it hasn't been rendered. | ||
} | ||
QDomElement plainEl = content.firstChildElement(QLatin1String("Plain")); | ||
if(!plainEl.isNull()) | ||
plain = plainEl.text(); | ||
else | ||
{ | ||
plain = QLatin1String(""); | ||
html = QLatin1String(""); // No plain text provided. The entry shouldn't render anything, or the user can't re-edit it. | ||
} | ||
if(rendered) | ||
m_textItem->setHtml(html); | ||
else | ||
m_textItem->setPlainText(plain); | ||
} | ||
|
||
QDomElement MarkdownEntry::toXml(QDomDocument& doc, KZip* archive) | ||
{ | ||
Q_UNUSED(archive); | ||
|
||
if(!rendered) | ||
plain = m_textItem->toPlainText(); | ||
|
||
QDomElement el = doc.createElement(QLatin1String("Markdown")); | ||
el.setAttribute(QLatin1String("rendered"), (int)rendered); | ||
|
||
QDomElement plainEl = doc.createElement(QLatin1String("Plain")); | ||
plainEl.appendChild(doc.createTextNode(plain)); | ||
el.appendChild(plainEl); | ||
if(rendered) | ||
{ | ||
QDomElement htmlEl = doc.createElement(QLatin1String("HTML")); | ||
htmlEl.appendChild(doc.createTextNode(html)); | ||
el.appendChild(htmlEl); | ||
} | ||
return el; | ||
} | ||
|
||
QString MarkdownEntry::toPlain(const QString& commandSep, const QString& commentStartingSeq, const QString& commentEndingSeq) | ||
{ | ||
Q_UNUSED(commandSep); | ||
|
||
if (commentStartingSeq.isEmpty()) | ||
return QString(); | ||
|
||
if(!rendered) | ||
plain = m_textItem->toPlainText(); | ||
|
||
QString text = QString(plain); | ||
|
||
if (!commentEndingSeq.isEmpty()) | ||
return commentStartingSeq + text + commentEndingSeq + QLatin1String("\n"); | ||
return commentStartingSeq + text.replace(QLatin1String("\n"), QLatin1String("\n") + commentStartingSeq) + QLatin1String("\n"); | ||
} | ||
|
||
void MarkdownEntry::interruptEvaluation() | ||
{ | ||
} | ||
|
||
bool MarkdownEntry::evaluate(EvaluationOption evalOp) | ||
{ | ||
if(!rendered) | ||
{ | ||
plain = m_textItem->toPlainText(); | ||
rendered = renderMarkdown(plain); | ||
} | ||
|
||
evaluateNext(evalOp); | ||
return true; | ||
} | ||
|
||
bool MarkdownEntry::renderMarkdown(QString& plain) | ||
{ | ||
#ifdef Discount_FOUND | ||
QByteArray mdCharArray = plain.toUtf8(); | ||
MMIOT* mdHandle = mkd_string(mdCharArray.data(), mdCharArray.size()+1, 0); | ||
if(!mkd_compile(mdHandle, MKD_FENCEDCODE | MKD_GITHUBTAGS)) | ||
{ | ||
qDebug()<<"Failed to compile the markdown document"; | ||
mkd_cleanup(mdHandle); | ||
return false; | ||
} | ||
char *htmlDocument; | ||
int htmlSize = mkd_document(mdHandle, &htmlDocument); | ||
html = QString::fromUtf8(htmlDocument, htmlSize); | ||
mkd_cleanup(mdHandle); | ||
|
||
m_textItem->setHtml(html); | ||
return true; | ||
#else | ||
Q_UNUSED(plain); | ||
|
||
return false; | ||
#endif | ||
} | ||
|
||
void MarkdownEntry::updateEntry() | ||
{ | ||
} | ||
|
||
WorksheetCursor MarkdownEntry::search(const QString& pattern, unsigned flags, | ||
QTextDocument::FindFlags qt_flags, | ||
const WorksheetCursor& pos) | ||
{ | ||
if (!(flags & WorksheetEntry::SearchText) || | ||
(pos.isValid() && pos.entry() != this)) | ||
return WorksheetCursor(); | ||
|
||
QTextCursor textCursor = m_textItem->search(pattern, qt_flags, pos); | ||
if (textCursor.isNull()) | ||
return WorksheetCursor(); | ||
else | ||
return WorksheetCursor(this, m_textItem, textCursor); | ||
} | ||
|
||
void MarkdownEntry::layOutForWidth(qreal w, bool force) | ||
{ | ||
if (size().width() == w && !force) | ||
return; | ||
|
||
m_textItem->setGeometry(0, 0, w); | ||
setSize(QSizeF(m_textItem->width(), m_textItem->height() + VerticalMargin)); | ||
} | ||
|
||
bool MarkdownEntry::eventFilter(QObject* object, QEvent* event) | ||
{ | ||
if(object == m_textItem) | ||
{ | ||
if(event->type() == QEvent::GraphicsSceneMouseDoubleClick) | ||
{ | ||
QGraphicsSceneMouseEvent* mouseEvent = dynamic_cast<QGraphicsSceneMouseEvent*>(event); | ||
if(!mouseEvent) return false; | ||
if(mouseEvent->button() == Qt::LeftButton && rendered) | ||
{ | ||
QTextDocument* doc = m_textItem->document(); | ||
doc->setPlainText(plain); | ||
m_textItem->setDocument(doc); | ||
m_textItem->setCursorPosition(mouseEvent->pos()); | ||
m_textItem->textCursor().clearSelection(); | ||
rendered = false; | ||
return true; | ||
} | ||
} | ||
} | ||
return false; | ||
} | ||
|
||
bool MarkdownEntry::wantToEvaluate() | ||
{ | ||
return !rendered; | ||
} |
Oops, something went wrong.