refactor: replace hoedown markdown parser with cmark

Signed-off-by: Joshua Goins <josh@redstrate.com>
This commit is contained in:
Joshua Goins 2023-01-06 15:26:26 -05:00
parent 9901ecda49
commit 24a4bd3a1c
10 changed files with 50 additions and 114 deletions

View File

@ -617,7 +617,7 @@ SET(LAUNCHER_SOURCES
DesktopServices.cpp DesktopServices.cpp
VersionProxyModel.h VersionProxyModel.h
VersionProxyModel.cpp VersionProxyModel.cpp
HoeDown.h Markdown.h
# Super secret! # Super secret!
KonamiCode.h KonamiCode.h
@ -1043,7 +1043,7 @@ target_link_libraries(Launcher_logic
) )
target_link_libraries(Launcher_logic target_link_libraries(Launcher_logic
QuaZip::QuaZip QuaZip::QuaZip
hoedown cmark
LocalPeer LocalPeer
Launcher_rainbow Launcher_rainbow
) )

View File

@ -1,76 +0,0 @@
/* Copyright 2013-2021 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <hoedown/html.h>
#include <hoedown/document.h>
#include <QString>
#include <QByteArray>
/**
* hoedown wrapper, because dealing with resource lifetime in C is stupid
*/
class HoeDown
{
public:
class buffer
{
public:
buffer(size_t unit = 4096)
{
buf = hoedown_buffer_new(unit);
}
~buffer()
{
hoedown_buffer_free(buf);
}
const char * cstr()
{
return hoedown_buffer_cstr(buf);
}
void put(QByteArray input)
{
hoedown_buffer_put(buf, reinterpret_cast<uint8_t *>(input.data()), input.size());
}
const uint8_t * data() const
{
return buf->data;
}
size_t size() const
{
return buf->size;
}
hoedown_buffer * buf;
} ib, ob;
HoeDown()
{
renderer = hoedown_html_renderer_new((hoedown_html_flags) 0,0);
document = hoedown_document_new(renderer, (hoedown_extensions) 0, 8);
}
~HoeDown()
{
hoedown_document_free(document);
hoedown_html_renderer_free(renderer);
}
QString process(QByteArray input)
{
ib.put(input);
hoedown_document_render(document, ob.buf, ib.data(), ib.size());
return ob.cstr();
}
private:
hoedown_document * document;
hoedown_renderer * renderer;
};

34
launcher/Markdown.h Normal file
View File

@ -0,0 +1,34 @@
// SPDX-License-Identifier: GPL-3.0-only
/*
* Prism Launcher - Minecraft Launcher
* Copyright (C) 2023 Joshua Goins <josh@redstrate.com>
*
* 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, version 3.
*
* 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, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include <QString>
#include <cmark.h>
static QString markdownToHTML(const QString& markdown)
{
const QByteArray markdownData = markdown.toUtf8();
char* buffer = cmark_markdown_to_html(markdownData.constData(), markdownData.length(), CMARK_OPT_NOBREAKS | CMARK_OPT_UNSAFE);
QString htmlStr(buffer);
free(buffer);
return htmlStr;
}

View File

@ -39,12 +39,11 @@
#include <QIcon> #include <QIcon>
#include "Application.h" #include "Application.h"
#include "BuildConfig.h" #include "BuildConfig.h"
#include "Markdown.h"
#include <net/NetJob.h> #include <net/NetJob.h>
#include <qobject.h> #include <qobject.h>
#include "HoeDown.h"
namespace { namespace {
QString getLink(QString link, QString name) { QString getLink(QString link, QString name) {
return QString("&lt;<a href='%1'>%2</a>&gt;").arg(link).arg(name); return QString("&lt;<a href='%1'>%2</a>&gt;").arg(link).arg(name);
@ -114,10 +113,9 @@ QString getCreditsHtml()
QString getLicenseHtml() QString getLicenseHtml()
{ {
HoeDown hoedown;
QFile dataFile(":/documents/COPYING.md"); QFile dataFile(":/documents/COPYING.md");
dataFile.open(QIODevice::ReadOnly); dataFile.open(QIODevice::ReadOnly);
QString output = hoedown.process(dataFile.readAll()); QString output = markdownToHTML(dataFile.readAll());
return output; return output;
} }

View File

@ -7,6 +7,7 @@
#include "FileSystem.h" #include "FileSystem.h"
#include "Json.h" #include "Json.h"
#include "Markdown.h"
#include "tasks/ConcurrentTask.h" #include "tasks/ConcurrentTask.h"
@ -17,7 +18,6 @@
#include "modplatform/flame/FlameCheckUpdate.h" #include "modplatform/flame/FlameCheckUpdate.h"
#include "modplatform/modrinth/ModrinthCheckUpdate.h" #include "modplatform/modrinth/ModrinthCheckUpdate.h"
#include <HoeDown.h>
#include <QTextBrowser> #include <QTextBrowser>
#include <QTreeWidgetItem> #include <QTreeWidgetItem>
@ -369,14 +369,7 @@ void ModUpdateDialog::appendMod(CheckUpdateTask::UpdatableMod const& info)
QString text = info.changelog; QString text = info.changelog;
switch (info.provider) { switch (info.provider) {
case ModPlatform::Provider::MODRINTH: { case ModPlatform::Provider::MODRINTH: {
HoeDown h; text = markdownToHTML(info.changelog.toUtf8());
// HoeDown bug?: \n aren't converted to <br>
text = h.process(info.changelog.toUtf8());
// Don't convert if there's an HTML tag right after (Qt rendering weirdness)
text.remove(QRegularExpression("(\n+)(?=<)"));
text.replace('\n', "<br>");
break; break;
} }
default: default:

View File

@ -41,7 +41,7 @@
#include <Json.h> #include <Json.h>
#include "BuildConfig.h" #include "BuildConfig.h"
#include "HoeDown.h" #include "Markdown.h"
UpdateDialog::UpdateDialog(bool hasUpdate, QWidget *parent) : QDialog(parent), ui(new Ui::UpdateDialog) UpdateDialog::UpdateDialog(bool hasUpdate, QWidget *parent) : QDialog(parent), ui(new Ui::UpdateDialog)
{ {
@ -89,8 +89,7 @@ void UpdateDialog::loadChangelog()
QString reprocessMarkdown(QByteArray markdown) QString reprocessMarkdown(QByteArray markdown)
{ {
HoeDown hoedown; QString output = markdownToHTML(markdown);
QString output = hoedown.process(markdown);
// HACK: easier than customizing hoedown // HACK: easier than customizing hoedown
output.replace(QRegularExpression("GH-([0-9]+)"), "<a href=\"https://github.com/PrismLauncher/PrismLauncher/issues/\\1\">GH-\\1</a>"); output.replace(QRegularExpression("GH-([0-9]+)"), "<a href=\"https://github.com/PrismLauncher/PrismLauncher/issues/\\1\">GH-\\1</a>");

View File

@ -9,14 +9,13 @@
#include <QProxyStyle> #include <QProxyStyle>
#include <QStyleFactory> #include <QStyleFactory>
#include <HoeDown.h>
#include "Application.h" #include "Application.h"
#include "BuildConfig.h" #include "BuildConfig.h"
#include "InstanceImportTask.h" #include "InstanceImportTask.h"
#include "InstanceList.h" #include "InstanceList.h"
#include "InstanceTask.h" #include "InstanceTask.h"
#include "Json.h" #include "Json.h"
#include "Markdown.h"
#include "modplatform/modrinth/ModrinthPackManifest.h" #include "modplatform/modrinth/ModrinthPackManifest.h"
@ -263,8 +262,7 @@ void ModrinthManagedPackPage::suggestVersion()
auto index = ui->versionsComboBox->currentIndex(); auto index = ui->versionsComboBox->currentIndex();
auto version = m_pack.versions.at(index); auto version = m_pack.versions.at(index);
HoeDown md_parser; ui->changelogTextBrowser->setHtml(markdownToHTML(version.changelog.toUtf8()));
ui->changelogTextBrowser->setHtml(md_parser.process(version.changelog.toUtf8()));
ManagedPackPage::suggestVersion(); ManagedPackPage::suggestVersion();
} }

View File

@ -43,13 +43,11 @@
#include <QRegularExpression> #include <QRegularExpression>
#include <memory> #include <memory>
#include <HoeDown.h>
#include "minecraft/MinecraftInstance.h" #include "minecraft/MinecraftInstance.h"
#include "minecraft/PackProfile.h" #include "minecraft/PackProfile.h"
#include "ui/dialogs/ModDownloadDialog.h" #include "ui/dialogs/ModDownloadDialog.h"
#include "ui/widgets/ProjectItem.h" #include "ui/widgets/ProjectItem.h"
#include "Markdown.h"
ModPage::ModPage(ModDownloadDialog* dialog, BaseInstance* instance, ModAPI* api) ModPage::ModPage(ModDownloadDialog* dialog, BaseInstance* instance, ModAPI* api)
: QWidget(dialog) : QWidget(dialog)
@ -427,11 +425,6 @@ void ModPage::updateUi()
text += "<hr>"; text += "<hr>";
HoeDown h; ui->packDescription->setHtml(text + (current.extraData.body.isEmpty() ? current.description : markdownToHTML(current.extraData.body)));
// hoedown bug: it doesn't handle markdown surrounded by block tags (like center, div) so strip them
current.extraData.body.remove(QRegularExpression("<[^>]*(?:center|div)\\W*>"));
ui->packDescription->setHtml(text + (current.extraData.body.isEmpty() ? current.description : h.process(current.extraData.body.toUtf8())));
ui->packDescription->flush(); ui->packDescription->flush();
} }

View File

@ -43,7 +43,7 @@
#include "ui/dialogs/NewInstanceDialog.h" #include "ui/dialogs/NewInstanceDialog.h"
#include "modplatform/modpacksch/FTBPackInstallTask.h" #include "modplatform/modpacksch/FTBPackInstallTask.h"
#include "HoeDown.h" #include "Markdown.h"
FtbPage::FtbPage(NewInstanceDialog* dialog, QWidget *parent) FtbPage::FtbPage(NewInstanceDialog* dialog, QWidget *parent)
: QWidget(parent), ui(new Ui::FtbPage), dialog(dialog) : QWidget(parent), ui(new Ui::FtbPage), dialog(dialog)
@ -175,8 +175,7 @@ void FtbPage::onSelectionChanged(QModelIndex first, QModelIndex second)
selected = filterModel->data(first, Qt::UserRole).value<ModpacksCH::Modpack>(); selected = filterModel->data(first, Qt::UserRole).value<ModpacksCH::Modpack>();
HoeDown hoedown; QString output = markdownToHTML(selected.description.toUtf8());
QString output = hoedown.process(selected.description.toUtf8());
ui->packDescription->setHtml(output); ui->packDescription->setHtml(output);
// reverse foreach, so that the newest versions are first // reverse foreach, so that the newest versions are first

View File

@ -42,11 +42,10 @@
#include "BuildConfig.h" #include "BuildConfig.h"
#include "InstanceImportTask.h" #include "InstanceImportTask.h"
#include "Json.h" #include "Json.h"
#include "Markdown.h"
#include "ui/widgets/ProjectItem.h" #include "ui/widgets/ProjectItem.h"
#include <HoeDown.h>
#include <QComboBox> #include <QComboBox>
#include <QKeyEvent> #include <QKeyEvent>
#include <QPushButton> #include <QPushButton>
@ -280,8 +279,7 @@ void ModrinthPage::updateUI()
text += "<hr>"; text += "<hr>";
HoeDown h; text += markdownToHTML(current.extra.body.toUtf8());
text += h.process(current.extra.body.toUtf8());
ui->packDescription->setHtml(text + current.description); ui->packDescription->setHtml(text + current.description);
ui->packDescription->flush(); ui->packDescription->flush();