1
0
mirror of https://github.com/qTox/qTox.git synced 2024-03-22 14:00:36 +08:00

feat(textstyle): Change markdown syntax to be more intuitive

BREAKING CHANGE: Current markdown syntax is unintuitive, and thus we have agreed on switching to @SkyzohKey's implementation. Replaces all instances of Markdown with Text Styling. Closes #3404.
This commit is contained in:
Andrew Morgan 2016-07-07 20:07:22 -07:00
parent 1bd86f7eee
commit 32e48a979c
No known key found for this signature in database
GPG Key ID: 174BEAB009FD176D
8 changed files with 67 additions and 58 deletions

View File

@ -220,15 +220,15 @@ Videochats and file transfers are currently unsupported in groupchats.
## Message Styling ## Message Styling
Similar to other messaging applications, qTox supports stylized text formatting. Similar to other messaging applications, qTox supports stylized text formatting.
Formatting follows
[Markdown syntax](https://daringfireball.net/projects/markdown/syntax), thus:
* For **Bold**, surround text in double asterisks or underscores: `**text**` * For **Bold**, surround text in single or double asterisks: `*text*`
or `__text__` or `**text**`
* For **Italics**, surround text in single asterisks or underscores: `*text*` * For **Italics**, surround text in single or double forward slashes: `/text/`
or `_text_` or `//text//`
* For **Strikethrough**, surround text in single tilde's: `~text~` * For **Strikethrough**, surround text in single or double tilde's: `~text~`
* For **Underline**, surround text in single dashes: `-text-` or `~~text~~`
* For **Underline**, surround text in single or double underscores: `_text_`
or `__text__`
* For **Code**, surround your code in in single backticks: `` `text` `` * For **Code**, surround your code in in single backticks: `` `text` ``
Additionally, qTox supports three modes of Markdown parsing: Additionally, qTox supports three modes of Markdown parsing:

View File

@ -55,9 +55,9 @@ ChatMessage::Ptr ChatMessage::createChatMessage(const QString &sender, const QSt
//quotes (green text) //quotes (green text)
text = detectQuotes(detectAnchors(text), type); text = detectQuotes(detectAnchors(text), type);
//markdown //text styling
if (Settings::getInstance().getMarkdownPreference() != NONE) if (Settings::getInstance().getStylePreference() != NONE)
text = detectMarkdown(text); text = detectStyle(text);
switch(type) switch(type)
{ {
@ -198,19 +198,21 @@ void ChatMessage::hideDate()
c->hide(); c->hide();
} }
QString ChatMessage::detectMarkdown(const QString &str) QString ChatMessage::detectStyle(const QString &str)
{ {
QString out = str; QString out = str;
// Create regex for certain markdown syntax // Create regex for text styling syntax
QRegExp exp("(\\*\\*)([^\\*\\*]{2,})(\\*\\*)" // Bold **text** QRegExp exp("(\\*)([^\\*]{2,})(\\*)" // Bold *text*
"|(\\*)([^\\*]{2,})(\\*)" // Italics *text* "|(\\*\\*)([^\\*\\*]{2,})(\\*\\*)" // Bold **text**
"|(\\_)([^\\_]{2,})(\\_)" // Italics _text_ "|(\\/)([^\\/]{2,})(\\/)" // Italics /text/
"|(\\_\\_)([^\\_\\_]{2,})(\\_\\_)" // Bold __text__ "|(\\/\\/)([^\\/\\/]{2,})(\\/\\/)" // Italics //text//
"|(\\-)([^\\-]{2,})(\\-)" // Underline -text- "|(\\_)([^\\_]{2,})(\\_)" // Underline _text_
"|(\\~)([^\\~]{2,})(\\~)" // Strike ~text~ "|(\\_\\_)([^\\_\\_]{2,})(\\_\\_)" // Underline __text__
"|(\\~~)([^\\~\\~]{2,})(\\~~)" // Strike ~~text~~ "|(\\~)([^\\~]{2,})(\\~)" // Strike ~text~
"|(\\`)([^\\`]{2,})(\\`)" // Codeblock `text` "|(\\~\\~)([^\\~\\~]{2,})(\\~\\~)" // Strike ~~text~~
"|(\\`)([^\\`]{2,})(\\`)" // Codeblock `text`
"|(\\`\\`\\`)([^\\`\\`\\`]{2,})(\\`\\`\\`)" // Codeblock ```\ntext\n```
); );
int offset = 0; int offset = 0;
@ -224,28 +226,32 @@ QString ChatMessage::detectMarkdown(const QString &str)
if ((snipCheck.startsWith(' ') || snipCheck.startsWith('>') || offset == 0) if ((snipCheck.startsWith(' ') || snipCheck.startsWith('>') || offset == 0)
&& ((snipCheck.endsWith(' ') || snipCheck.endsWith('<')) || offset + snippet.length() == out.length())) && ((snipCheck.endsWith(' ') || snipCheck.endsWith('<')) || offset + snippet.length() == out.length()))
{ {
int mul = 0; // Determines how many characters to strip from markdown text int mul = 0; // Determines how many characters to strip from text
// Set mul depending on markdownPreference // Set mul depending on styleownPreference
if (Settings::getInstance().getMarkdownPreference() == WITHOUT_CHARS) if (Settings::getInstance().getStylePreference() == WITHOUT_CHARS)
mul = 2; mul = 2;
// Match captured string to corresponding md format // Match captured string to corresponding style format
if (exp.cap(1) == "**") // Bold **text** if (exp.cap(1) == "*" && snippet.length() > 2) // Bold *text*
htmledSnippet = QString("<b>%1</b>").arg(snippet.mid(mul/2,snippet.length()-mul));
else if (exp.cap(4) == "**" && snippet.length() > 4) // Bold **text**
htmledSnippet = QString("<b>%1</b>").arg(snippet.mid(mul,snippet.length()-2*mul)); htmledSnippet = QString("<b>%1</b>").arg(snippet.mid(mul,snippet.length()-2*mul));
else if (exp.cap(4) == "*" && snippet.length() > 2) // Italics *text* else if (exp.cap(7) == "/" && snippet.length() > 2) // Italics /text/
htmledSnippet = QString("<i>%1</i>").arg(snippet.mid(mul/2,snippet.length()-mul)); htmledSnippet = QString("<i>%1</i>").arg(snippet.mid(mul/2,snippet.length()-mul));
else if (exp.cap(7) == "_" && snippet.length() > 2) // Italics _text_ else if (exp.cap(10) == "//" && snippet.length() > 4) // Italics //text//
htmledSnippet = QString("<i>%1</i>").arg(snippet.mid(mul/2,snippet.length()-mul)); htmledSnippet = QString("<i>%1</i>").arg(snippet.mid(mul,snippet.length()-2*mul));
else if (exp.cap(10) == "__"&& snippet.length() > 4) // Bold __text__ else if (exp.cap(13) == "_"&& snippet.length() > 2) // Underline _text_
htmledSnippet = QString("<b>%1</b>").arg(snippet.mid(mul,snippet.length()-2*mul));
else if (exp.cap(13) == "-" && snippet.length() > 2) // Underline -text-
htmledSnippet = QString("<u>%1</u>").arg(snippet.mid(mul/2,snippet.length()-mul)); htmledSnippet = QString("<u>%1</u>").arg(snippet.mid(mul/2,snippet.length()-mul));
else if (exp.cap(16) == "~" && snippet.length() > 2) // Strikethrough ~text~ else if (exp.cap(16) == "__" && snippet.length() > 4) // Underline __text__
htmledSnippet = QString("<u>%1</u>").arg(snippet.mid(mul,snippet.length()-2*mul));
else if (exp.cap(19) == "~" && snippet.length() > 2) // Strike ~text~
htmledSnippet = QString("<s>%1</s>").arg(snippet.mid(mul/2,snippet.length()-mul)); htmledSnippet = QString("<s>%1</s>").arg(snippet.mid(mul/2,snippet.length()-mul));
else if (exp.cap(19) == "~~" && snippet.length() > 4) // Strikethrough ~~text~~ else if (exp.cap(22) == "~~" && snippet.length() > 4) // Strike ~~text~~
htmledSnippet = QString("<s>%1</s>").arg(snippet.mid(mul,snippet.length()-2*mul)); htmledSnippet = QString("<s>%1</s>").arg(snippet.mid(mul,snippet.length()-2*mul));
else if (exp.cap(22) == "`" && snippet.length() > 2) // Codeblock `text` else if (exp.cap(25) == "`" && snippet.length() > 2) // Codeblock `text`
htmledSnippet = QString("<font color=#595959><code>%1</code></font>").arg(snippet.mid(mul/2,snippet.length()-mul)); htmledSnippet = QString("<font color=#595959><code>%1</code></font>").arg(snippet.mid(mul/2,snippet.length()-mul));
else if (exp.cap(28) == "```" && snippet.length() > 6) // Codeblock ```text```
htmledSnippet = QString("<font color=#595959><code>%1</code></font>").arg(snippet.mid(4*mul,snippet.length()-8*mul));
else else
htmledSnippet = snippet; htmledSnippet = snippet;
out.replace(offset, exp.cap().length(), htmledSnippet); out.replace(offset, exp.cap().length(), htmledSnippet);

View File

@ -61,7 +61,7 @@ public:
void hideDate(); void hideDate();
protected: protected:
static QString detectMarkdown(const QString& str); static QString detectStyle(const QString& str);
static QString detectAnchors(const QString& str); static QString detectAnchors(const QString& str);
static QString detectQuotes(const QString& str, MessageType type); static QString detectQuotes(const QString& str, MessageType type);
static QString wrapDiv(const QString& str, const QString& div); static QString wrapDiv(const QString& str, const QString& div);

View File

@ -182,7 +182,7 @@ void Settings::loadGlobal()
separateWindow = s.value("separateWindow", false).toBool(); separateWindow = s.value("separateWindow", false).toBool();
dontGroupWindows = s.value("dontGroupWindows", true).toBool(); dontGroupWindows = s.value("dontGroupWindows", true).toBool();
groupchatPosition = s.value("groupchatPosition", true).toBool(); groupchatPosition = s.value("groupchatPosition", true).toBool();
markdownPreference = static_cast<MarkdownType>(s.value("markdownPreference", 1).toInt()); stylePreference = static_cast<StyleType>(s.value("stylePreference", 1).toInt());
s.endGroup(); s.endGroup();
s.beginGroup("Advanced"); s.beginGroup("Advanced");
@ -434,7 +434,7 @@ void Settings::saveGlobal()
s.setValue("groupchatPosition", groupchatPosition); s.setValue("groupchatPosition", groupchatPosition);
s.setValue("autoSaveEnabled", autoSaveEnabled); s.setValue("autoSaveEnabled", autoSaveEnabled);
s.setValue("globalAutoAcceptDir", globalAutoAcceptDir); s.setValue("globalAutoAcceptDir", globalAutoAcceptDir);
s.setValue("markdownPreference", static_cast<int>(markdownPreference)); s.setValue("stylePreference", static_cast<int>(stylePreference));
s.endGroup(); s.endGroup();
s.beginGroup("Advanced"); s.beginGroup("Advanced");
@ -1249,16 +1249,16 @@ void Settings::setDateFormat(const QString &format)
dateFormat = format; dateFormat = format;
} }
MarkdownType Settings::getMarkdownPreference() const StyleType Settings::getStylePreference() const
{ {
QMutexLocker locker{&bigLock}; QMutexLocker locker{&bigLock};
return markdownPreference; return stylePreference;
} }
void Settings::setMarkdownPreference(MarkdownType newValue) void Settings::setStylePreference(StyleType newValue)
{ {
QMutexLocker locker{&bigLock}; QMutexLocker locker{&bigLock};
markdownPreference = newValue; stylePreference = newValue;
} }
QByteArray Settings::getWindowGeometry() const QByteArray Settings::getWindowGeometry() const

View File

@ -36,7 +36,7 @@ namespace Db { enum class syncType; }
enum ProxyType {ptNone, ptSOCKS5, ptHTTP}; enum ProxyType {ptNone, ptSOCKS5, ptHTTP};
enum MarkdownType {NONE, WITH_CHARS, WITHOUT_CHARS}; enum StyleType {NONE, WITH_CHARS, WITHOUT_CHARS};
class Settings : public QObject class Settings : public QObject
{ {
@ -212,8 +212,8 @@ public:
int getThemeColor() const; int getThemeColor() const;
void setThemeColor(const int& value); void setThemeColor(const int& value);
MarkdownType getMarkdownPreference() const; StyleType getStylePreference() const;
void setMarkdownPreference(MarkdownType newValue); void setStylePreference(StyleType newValue);
bool isCurstomEmojiFont() const; bool isCurstomEmojiFont() const;
void setCurstomEmojiFont(bool value); void setCurstomEmojiFont(bool value);
@ -426,7 +426,7 @@ private:
// ChatView // ChatView
QFont chatMessageFont; QFont chatMessageFont;
MarkdownType markdownPreference; StyleType stylePreference;
int firstColumnHandlePos; int firstColumnHandlePos;
int secondColumnHandlePosFromRight; int secondColumnHandlePosFromRight;
QString timestampFormat; QString timestampFormat;

View File

@ -124,7 +124,7 @@ GeneralForm::GeneralForm(SettingsWidget *myParent) :
const QFont chatBaseFont = s.getChatMessageFont(); const QFont chatBaseFont = s.getChatMessageFont();
bodyUI->txtChatFontSize->setValue(QFontInfo(chatBaseFont).pixelSize()); bodyUI->txtChatFontSize->setValue(QFontInfo(chatBaseFont).pixelSize());
bodyUI->txtChatFont->setCurrentFont(chatBaseFont); bodyUI->txtChatFont->setCurrentFont(chatBaseFont);
bodyUI->markdownComboBox->setCurrentIndex(s.getMarkdownPreference()); bodyUI->textStyleComboBox->setCurrentIndex(s.getStylePreference());
bodyUI->cbAutorun->setChecked(s.getAutorun()); bodyUI->cbAutorun->setChecked(s.getAutorun());
bool showSystemTray = s.getShowSystemTray(); bool showSystemTray = s.getShowSystemTray();
@ -233,7 +233,7 @@ GeneralForm::GeneralForm(SettingsWidget *myParent) :
connect(bodyUI->showInFront, &QCheckBox::stateChanged, this, &GeneralForm::onSetShowInFront); connect(bodyUI->showInFront, &QCheckBox::stateChanged, this, &GeneralForm::onSetShowInFront);
connect(bodyUI->notifySound, &QCheckBox::stateChanged, this, &GeneralForm::onSetNotifySound); connect(bodyUI->notifySound, &QCheckBox::stateChanged, this, &GeneralForm::onSetNotifySound);
connect(bodyUI->busySound, &QCheckBox::stateChanged, this, &GeneralForm::onSetBusySound); connect(bodyUI->busySound, &QCheckBox::stateChanged, this, &GeneralForm::onSetBusySound);
connect(bodyUI->markdownComboBox, &QComboBox::currentTextChanged, this, &GeneralForm::onMarkdownUpdated); connect(bodyUI->textStyleComboBox, &QComboBox::currentTextChanged, this, &GeneralForm::onStyleUpdated);
connect(bodyUI->groupAlwaysNotify, &QCheckBox::stateChanged, this, &GeneralForm::onSetGroupAlwaysNotify); connect(bodyUI->groupAlwaysNotify, &QCheckBox::stateChanged, this, &GeneralForm::onSetGroupAlwaysNotify);
connect(bodyUI->autoacceptFiles, &QCheckBox::stateChanged, this, &GeneralForm::onAutoAcceptFileChange); connect(bodyUI->autoacceptFiles, &QCheckBox::stateChanged, this, &GeneralForm::onAutoAcceptFileChange);
connect(bodyUI->autoSaveFilesDir, SIGNAL(clicked()), this, SLOT(onAutoSaveDirChange())); connect(bodyUI->autoSaveFilesDir, SIGNAL(clicked()), this, SLOT(onAutoSaveDirChange()));
@ -396,9 +396,9 @@ void GeneralForm::onUseEmoticonsChange()
bodyUI->smileyPackBrowser->setEnabled(bodyUI->useEmoticons->isChecked()); bodyUI->smileyPackBrowser->setEnabled(bodyUI->useEmoticons->isChecked());
} }
void GeneralForm::onMarkdownUpdated() void GeneralForm::onStyleUpdated()
{ {
Settings::getInstance().setMarkdownPreference(static_cast<MarkdownType>(bodyUI->markdownComboBox->currentIndex())); Settings::getInstance().setStylePreference(static_cast<StyleType>(bodyUI->textStyleComboBox->currentIndex()));
} }
void GeneralForm::onSetStatusChange() void GeneralForm::onSetStatusChange()

View File

@ -53,7 +53,7 @@ private slots:
void onStyleSelected(QString style); void onStyleSelected(QString style);
void onTimestampSelected(int index); void onTimestampSelected(int index);
void onDateFormatSelected(int index); void onDateFormatSelected(int index);
void onMarkdownUpdated(); void onStyleUpdated();
void onSetStatusChange(); void onSetStatusChange();
void onAutoAwayChanged(); void onAutoAwayChanged();
void onUseEmoticonsChange(); void onUseEmoticonsChange();

View File

@ -39,8 +39,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>1270</width> <width>1278</width>
<height>1468</height> <height>1382</height>
</rect> </rect>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout_4" stretch="0,0,0,1"> <layout class="QVBoxLayout" name="verticalLayout_4" stretch="0,0,0,1">
@ -336,12 +336,12 @@ instead of closing itself.</string>
</widget> </widget>
</item> </item>
<item row="1" column="0"> <item row="1" column="0">
<widget class="QLabel" name="transLabel_2"> <widget class="QLabel" name="textStyleLabel">
<property name="toolTip"> <property name="toolTip">
<string>New Markdown preference may not load until qTox restarts.</string> <string>New text styling preference may not load until qTox restarts.</string>
</property> </property>
<property name="text"> <property name="text">
<string>Markdown format:</string> <string>Text Style format:</string>
</property> </property>
<property name="alignment"> <property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
@ -375,7 +375,7 @@ instead of closing itself.</string>
</spacer> </spacer>
</item> </item>
<item row="1" column="1" colspan="2"> <item row="1" column="1" colspan="2">
<widget class="QComboBox" name="markdownComboBox"> <widget class="QComboBox" name="textStyleComboBox">
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed"> <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch> <horstretch>0</horstretch>
@ -383,7 +383,10 @@ instead of closing itself.</string>
</sizepolicy> </sizepolicy>
</property> </property>
<property name="toolTip"> <property name="toolTip">
<string>Select Markdown preference.</string> <string>Select text styling preference.</string>
</property>
<property name="currentIndex">
<number>1</number>
</property> </property>
<item> <item>
<property name="text"> <property name="text">