diff --git a/imports/NeoChat/Component/ChatTextInput.qml b/imports/NeoChat/Component/ChatTextInput.qml index 7557f1302..71b45f6a4 100644 --- a/imports/NeoChat/Component/ChatTextInput.qml +++ b/imports/NeoChat/Component/ChatTextInput.qml @@ -133,6 +133,7 @@ ToolBar { keyNavigationWraps: true delegate: Control { + property string autoCompleteText: modelData.displayName ? ("[" + modelData.displayName + "](https://matrix.to/#/" + modelData.id + "):") : modelData.unicode property string displayText: modelData.displayName ?? modelData.unicode property bool isEmoji: modelData.unicode != null readonly property bool highlighted: autoCompleteListView.currentIndex == index @@ -176,7 +177,7 @@ ToolBar { anchors.fill: parent onClicked: { autoCompleteListView.currentIndex = index - documentHandler.replaceAutoComplete(displayText) + inputField.autoComplete(); } } } @@ -303,6 +304,7 @@ ToolBar { wrapMode: Text.Wrap placeholderText: i18n("Write your message...") + textFormat: TextEdit.MarkdownText topPadding: 0 bottomPadding: 0 leftPadding: Kirigami.Units.smallSpacing @@ -342,7 +344,8 @@ ToolBar { Keys.onReturnPressed: { if (isAutoCompleting) { - documentHandler.replaceAutoComplete(autoCompleteListView.currentItem.displayText) + inputField.autoComplete(); + isAutoCompleting = false; return; } @@ -397,7 +400,7 @@ ToolBar { autoAppeared = false; } - documentHandler.replaceAutoComplete(autoCompleteListView.currentItem.displayText) + inputField.autoComplete(); } onTextChanged: { @@ -434,10 +437,33 @@ ToolBar { } function postMessage() { - documentHandler.postMessage(inputField.text, attachmentPath, replyEventID); + // Qt wraps lines so we need to use a small hack + // to remove the wrapped lines but not break the empty + // lines. + const updatedText = inputField.text.trim() + .replace(/\n{2,}/g, '

') + .replace(/\n/g, '') + documentHandler.postMessage(updatedText, attachmentPath, replyEventID); clearAttachment(); currentRoom.markAllMessagesAsRead(); clear(); + text = Qt.binding(function() { + return currentRoom != null ? currentRoom.cachedInput : ""; + }); + } + + // HACK apply markdown, we are setting the text attribute to + // force the text field to rerender. Because the cursor position + // will be reset, we save the old one and substract the now hidden + // markdown markup. + function autoComplete() { + documentHandler.replaceAutoComplete(autoCompleteListView.currentItem.autoCompleteText) + const oldCursorPosition = cursorPosition; + const oldText = text; + const oldLength = inputField.length; + text = ""; + text = oldText; + cursorPosition = oldCursorPosition - (oldLength - inputField.length); } } diff --git a/src/neochatroom.cpp b/src/neochatroom.cpp index 4e0320032..af6119762 100644 --- a/src/neochatroom.cpp +++ b/src/neochatroom.cpp @@ -467,6 +467,8 @@ QString NeoChatRoom::markdownToHTML(const QString &markdown) auto result = QString::fromStdString(html).trimmed(); + result.replace("", "
"); + result.replace(QRegularExpression("(
)*$"), ""); result.replace("

", ""); result.replace("

", "");