浏览代码

Editor: support line ending

Le Tan 4 年之前
父节点
当前提交
0d8bb7eebd

+ 1 - 1
libs/vtextedit

@@ -1 +1 @@
-Subproject commit 59e53f2cdc2f5a4b9dc44cbf28c483cca07559ba
+Subproject commit 0733259fed01ecaa11678fac00fd67397ff7c39c

+ 54 - 0
src/core/editorconfig.cpp

@@ -95,6 +95,11 @@ void EditorConfig::loadCore(const QJsonObject &p_app, const QJsonObject &p_user)
     if (m_spellCheckDefaultDictionary.isEmpty()) {
         m_spellCheckDefaultDictionary = QStringLiteral("en_US");
     }
+
+    {
+        auto lineEnding = READSTR(QStringLiteral("line_ending"));
+        m_lineEnding = stringToLineEndingPolicy(lineEnding);
+    }
 }
 
 QJsonObject EditorConfig::saveCore() const
@@ -107,6 +112,7 @@ QJsonObject EditorConfig::saveCore() const
     obj[QStringLiteral("shortcuts")] = saveShortcuts();
     obj[QStringLiteral("spell_check_auto_detect_language")] = m_spellCheckAutoDetectLanguageEnabled;
     obj[QStringLiteral("spell_check_default_dictionary")] = m_spellCheckDefaultDictionary;
+    obj[QStringLiteral("line_ending")] = lineEndingPolicyToString(m_lineEnding);
     return obj;
 }
 
@@ -211,6 +217,44 @@ EditorConfig::AutoSavePolicy EditorConfig::stringToAutoSavePolicy(const QString
     }
 }
 
+QString EditorConfig::lineEndingPolicyToString(LineEndingPolicy p_ending) const
+{
+    switch (p_ending) {
+    case LineEndingPolicy::Platform:
+        return QStringLiteral("platform");
+
+    case LineEndingPolicy::File:
+        return QStringLiteral("file");
+
+    case LineEndingPolicy::LF:
+        return QStringLiteral("lf");
+
+    case LineEndingPolicy::CRLF:
+        return QStringLiteral("crlf");
+
+    case LineEndingPolicy::CR:
+        return QStringLiteral("cr");
+    }
+
+    return QStringLiteral("platform");
+}
+
+LineEndingPolicy EditorConfig::stringToLineEndingPolicy(const QString &p_str) const
+{
+    auto ending = p_str.toLower();
+    if (ending == QStringLiteral("file")) {
+        return LineEndingPolicy::File;
+    } else if (ending == QStringLiteral("lf")) {
+        return LineEndingPolicy::LF;
+    } else if (ending == QStringLiteral("crlf")) {
+        return LineEndingPolicy::CRLF;
+    } else if (ending == QStringLiteral("cr")) {
+        return LineEndingPolicy::CR;
+    } else {
+        return LineEndingPolicy::Platform;
+    }
+}
+
 EditorConfig::AutoSavePolicy EditorConfig::getAutoSavePolicy() const
 {
     return m_autoSavePolicy;
@@ -221,6 +265,16 @@ void EditorConfig::setAutoSavePolicy(EditorConfig::AutoSavePolicy p_policy)
     updateConfig(m_autoSavePolicy, p_policy, this);
 }
 
+LineEndingPolicy EditorConfig::getLineEndingPolicy() const
+{
+    return m_lineEnding;
+}
+
+void EditorConfig::setLineEndingPolicy(LineEndingPolicy p_ending)
+{
+    updateConfig(m_lineEnding, p_ending, this);
+}
+
 const QString &EditorConfig::getBackupFileDirectory() const
 {
     return m_backupFileDirectory;

+ 10 - 0
src/core/editorconfig.h

@@ -8,6 +8,8 @@
 #include <QObject>
 #include <QVector>
 
+#include "global.h"
+
 namespace vte
 {
     class ViConfig;
@@ -127,6 +129,9 @@ namespace vnotex
 
         const QSharedPointer<vte::ViConfig> &getViConfig() const;
 
+        LineEndingPolicy getLineEndingPolicy() const;
+        void setLineEndingPolicy(LineEndingPolicy p_ending);
+
     private:
         friend class MainConfig;
 
@@ -141,6 +146,9 @@ namespace vnotex
         QString autoSavePolicyToString(AutoSavePolicy p_policy) const;
         AutoSavePolicy stringToAutoSavePolicy(const QString &p_str) const;
 
+        QString lineEndingPolicyToString(LineEndingPolicy p_ending) const;
+        LineEndingPolicy stringToLineEndingPolicy(const QString &p_str) const;
+
         void loadImageHost(const QJsonObject &p_app, const QJsonObject &p_user);
 
         QJsonObject saveImageHost() const;
@@ -174,6 +182,8 @@ namespace vnotex
         bool m_clearObsoleteImageAtImageHost = false;
 
         QSharedPointer<vte::ViConfig> m_viConfig;
+
+        LineEndingPolicy m_lineEnding = LineEndingPolicy::LF;
     };
 }
 

+ 8 - 0
src/core/global.h

@@ -133,6 +133,14 @@ namespace vnotex
         int m_length = -1;
     };
 
+    enum class LineEndingPolicy
+    {
+        Platform,
+        File,
+        LF,
+        CRLF,
+        CR
+    };
 } // ns vnotex
 
 Q_DECLARE_OPERATORS_FOR_FLAGS(vnotex::FindOptions);

+ 2 - 2
src/core/historymgr.cpp

@@ -145,8 +145,8 @@ void HistoryMgr::add(const QString &p_path,
         file.m_mode = p_mode;
         file.m_readOnly = p_readOnly;
 
-        if (m_lastClosedFiles.size() > 100) {
-            m_lastClosedFiles.remove(0, m_lastClosedFiles.size() - 100);
+        if (m_lastClosedFiles.size() > s_maxHistoryCount) {
+            m_lastClosedFiles.remove(0, m_lastClosedFiles.size() - s_maxHistoryCount);
         }
     }
 

+ 3 - 1
src/data/core/vnotex.json

@@ -119,7 +119,9 @@
                 "ApplySnippet" : "Ctrl+G, I"
             },
             "spell_check_auto_detect_language" : false,
-            "spell_check_default_dictionary" : "en_US"
+            "spell_check_default_dictionary" : "en_US",
+            "//comment" : "platform/file/lf/crlf/cr",
+            "line_ending" : "lf"
         },
         "text_editor" : {
             "theme" : "",

+ 6 - 3
src/utils/fileutils.cpp

@@ -6,7 +6,9 @@
 #include <QTemporaryFile>
 #include <QJsonDocument>
 
-#include "../core/exception.h"
+#include <core/exception.h>
+#include <core/global.h>
+
 #include "pathutils.h"
 
 using namespace vnotex;
@@ -25,11 +27,12 @@ QByteArray FileUtils::readFile(const QString &p_filePath)
 QString FileUtils::readTextFile(const QString &p_filePath)
 {
     QFile file(p_filePath);
-    if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
+    if (!file.open(QIODevice::ReadOnly)) {
         Exception::throwOne(Exception::Type::FailToReadFile,
                             QString("failed to read file: %1").arg(p_filePath));
     }
 
+    // TODO: determine the encoding of the text.
     QString text(file.readAll());
     file.close();
     return text;
@@ -55,7 +58,7 @@ void FileUtils::writeFile(const QString &p_filePath, const QByteArray &p_data)
 void FileUtils::writeFile(const QString &p_filePath, const QString &p_text)
 {
     QFile file(p_filePath);
-    if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
+    if (!file.open(QIODevice::WriteOnly)) {
         Exception::throwOne(Exception::Type::FailToWriteFile,
                             QString("failed to write to file: %1").arg(p_filePath));
     }

+ 28 - 0
src/widgets/dialogs/settings/editorpage.cpp

@@ -42,6 +42,23 @@ void EditorPage::setupUI()
                 this, &EditorPage::pageIsChanged);
     }
 
+    {
+        m_lineEndingComboBox = WidgetsFactory::createComboBox(this);
+        m_lineEndingComboBox->setToolTip(tr("Line ending"));
+
+        m_lineEndingComboBox->addItem(tr("Follow Platform"), (int)LineEndingPolicy::Platform);
+        m_lineEndingComboBox->addItem(tr("Follow File"), (int)LineEndingPolicy::File);
+        m_lineEndingComboBox->addItem(tr("LF (Linux/macOS)"), (int)LineEndingPolicy::LF);
+        m_lineEndingComboBox->addItem(tr("CR LF (Windows)"), (int)LineEndingPolicy::CRLF);
+        m_lineEndingComboBox->addItem(tr("CR"), (int)LineEndingPolicy::CR);
+
+        const QString label(tr("Line ending:"));
+        mainLayout->addRow(label, m_lineEndingComboBox);
+        addSearchItem(label, m_lineEndingComboBox->toolTip(), m_lineEndingComboBox);
+        connect(m_lineEndingComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged),
+                this, &EditorPage::pageIsChanged);
+    }
+
     {
         m_toolBarIconSizeSpinBox = WidgetsFactory::createSpinBox(this);
         m_toolBarIconSizeSpinBox->setToolTip(tr("Icon size of the editor tool bar"));
@@ -105,6 +122,12 @@ void EditorPage::loadInternal()
         m_autoSavePolicyComboBox->setCurrentIndex(idx);
     }
 
+    {
+        int idx = m_lineEndingComboBox->findData(static_cast<int>(editorConfig.getLineEndingPolicy()));
+        Q_ASSERT(idx != -1);
+        m_lineEndingComboBox->setCurrentIndex(idx);
+    }
+
     m_toolBarIconSizeSpinBox->setValue(editorConfig.getToolBarIconSize());
 
     {
@@ -122,6 +145,11 @@ bool EditorPage::saveInternal()
         editorConfig.setAutoSavePolicy(static_cast<EditorConfig::AutoSavePolicy>(policy));
     }
 
+    {
+        auto ending = m_lineEndingComboBox->currentData().toInt();
+        editorConfig.setLineEndingPolicy(static_cast<LineEndingPolicy>(ending));
+    }
+
     editorConfig.setToolBarIconSize(m_toolBarIconSizeSpinBox->value());
 
     {

+ 2 - 0
src/widgets/dialogs/settings/editorpage.h

@@ -32,6 +32,8 @@ namespace vnotex
         QSpinBox *m_toolBarIconSizeSpinBox = nullptr;
 
         QComboBox *m_spellCheckDictComboBox = nullptr;
+
+        QComboBox *m_lineEndingComboBox = nullptr;
     };
 }
 

+ 2 - 1
src/widgets/markdownviewwindow.cpp

@@ -863,7 +863,8 @@ QSharedPointer<vte::MarkdownEditorConfig> MarkdownViewWindow::createMarkdownEdit
     auto textEditorConfig = TextViewWindowHelper::createTextEditorConfig(p_config.getTextEditorConfig(),
                                                                          p_editorConfig.getViConfig(),
                                                                          themeMgr.getFile(Theme::File::MarkdownEditorStyle),
-                                                                         themeMgr.getMarkdownEditorHighlightTheme());
+                                                                         themeMgr.getMarkdownEditorHighlightTheme(),
+                                                                         p_editorConfig.getLineEndingPolicy());
 
     auto editorConfig = QSharedPointer<vte::MarkdownEditorConfig>::create(textEditorConfig);
     editorConfig->overrideTextFontFamily(p_config.getEditorOverriddenFontFamily());

+ 2 - 1
src/widgets/textviewwindow.cpp

@@ -176,7 +176,8 @@ QSharedPointer<vte::TextEditorConfig> TextViewWindow::createTextEditorConfig(con
     auto config = TextViewWindowHelper::createTextEditorConfig(p_config,
                                                                p_editorConfig.getViConfig(),
                                                                themeMgr.getFile(Theme::File::TextEditorStyle),
-                                                               themeMgr.getEditorHighlightTheme());
+                                                               themeMgr.getEditorHighlightTheme(),
+                                                               p_editorConfig.getLineEndingPolicy());
     return config;
 }
 

+ 20 - 1
src/widgets/textviewwindowhelper.h

@@ -66,7 +66,8 @@ namespace vnotex
         static QSharedPointer<vte::TextEditorConfig> createTextEditorConfig(const TextEditorConfig &p_config,
                                                                             const QSharedPointer<vte::ViConfig> &p_viConfig,
                                                                             const QString &p_themeFile,
-                                                                            const QString &p_syntaxTheme)
+                                                                            const QString &p_syntaxTheme,
+                                                                            LineEndingPolicy p_lineEndingPolicy)
         {
             auto editorConfig = QSharedPointer<vte::TextEditorConfig>::create();
 
@@ -141,6 +142,24 @@ namespace vnotex
             editorConfig->m_expandTab = p_config.getExpandTabEnabled();
             editorConfig->m_tabStopWidth = p_config.getTabStopWidth();
 
+            switch (p_lineEndingPolicy) {
+            case LineEndingPolicy::Platform:
+                editorConfig->m_lineEndingPolicy = vte::LineEndingPolicy::Platform;
+                break;
+            case LineEndingPolicy::File:
+                editorConfig->m_lineEndingPolicy = vte::LineEndingPolicy::File;
+                break;
+            case LineEndingPolicy::LF:
+                editorConfig->m_lineEndingPolicy = vte::LineEndingPolicy::LF;
+                break;
+            case LineEndingPolicy::CRLF:
+                editorConfig->m_lineEndingPolicy = vte::LineEndingPolicy::CRLF;
+                break;
+            case LineEndingPolicy::CR:
+                editorConfig->m_lineEndingPolicy = vte::LineEndingPolicy::CR;
+                break;
+            }
+
             return editorConfig;
         }