File indexing completed on 2024-04-21 03:57:24
0001 /* 0002 SPDX-FileCopyrightText: 2017 Grzegorz Szymaszek <gszymaszek@short.pl> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "editorconfig.h" 0008 #include "kateconfig.h" 0009 #include "katedocument.h" 0010 #include "katepartdebug.h" 0011 0012 /** 0013 * @return whether a string value could be converted to a bool value as 0014 * supported. The value is put in *result. 0015 */ 0016 static bool checkBoolValue(QString val, bool *result) 0017 { 0018 val = val.trimmed().toLower(); 0019 static const QStringList trueValues{QStringLiteral("1"), QStringLiteral("on"), QStringLiteral("true")}; 0020 if (trueValues.contains(val)) { 0021 *result = true; 0022 return true; 0023 } 0024 0025 static const QStringList falseValues{QStringLiteral("0"), QStringLiteral("off"), QStringLiteral("false")}; 0026 if (falseValues.contains(val)) { 0027 *result = false; 0028 return true; 0029 } 0030 return false; 0031 } 0032 0033 /** 0034 * @return whether a string value could be converted to a integer value. The 0035 * value is put in *result. 0036 */ 0037 static bool checkIntValue(const QString &val, int *result) 0038 { 0039 bool ret(false); 0040 *result = val.toInt(&ret); 0041 return ret; 0042 } 0043 0044 EditorConfig::EditorConfig(KTextEditor::DocumentPrivate *document) 0045 : m_document(document) 0046 , m_handle(editorconfig_handle_init()) 0047 { 0048 } 0049 0050 EditorConfig::~EditorConfig() 0051 { 0052 editorconfig_handle_destroy(m_handle); 0053 } 0054 0055 int EditorConfig::parse() 0056 { 0057 const int code = editorconfig_parse(m_document->url().toLocalFile().toStdString().c_str(), m_handle); 0058 0059 if (code != 0) { 0060 if (code == EDITORCONFIG_PARSE_MEMORY_ERROR) { 0061 qCDebug(LOG_KTE) << "Failed to parse .editorconfig, memory error occurred"; 0062 } else if (code > 0) { 0063 qCDebug(LOG_KTE) << "Failed to parse .editorconfig, error in line" << code; 0064 } else { 0065 qCDebug(LOG_KTE) << "Failed to parse .editorconfig, unknown error"; 0066 } 0067 0068 return code; 0069 } 0070 0071 // count of found key-value pairs 0072 const unsigned int count = editorconfig_handle_get_name_value_count(m_handle); 0073 0074 // if indent_size=tab 0075 bool setIndentSizeAsTabWidth = false; 0076 0077 // whether corresponding fields were found in .editorconfig 0078 bool indentSizeSet = false; 0079 bool tabWidthSet = false; 0080 0081 // the following only applies if indent_size=tab and there isn’t tab_width 0082 int tabWidth = m_document->config()->tabWidth(); 0083 0084 for (unsigned int i = 0; i < count; ++i) { 0085 // raw values from EditorConfig library 0086 const char *rawKey = nullptr; 0087 const char *rawValue = nullptr; 0088 0089 // buffers for integer/boolean values 0090 int intValue; 0091 bool boolValue; 0092 0093 // fetch next key-value pair 0094 editorconfig_handle_get_name_value(m_handle, i, &rawKey, &rawValue); 0095 0096 // and convert to Qt strings 0097 const QLatin1String key = QLatin1String(rawKey); 0098 const QLatin1String value = QLatin1String(rawValue); 0099 0100 if (QLatin1String("charset") == key) { 0101 m_document->setEncoding(value); 0102 } else if (QLatin1String("end_of_line") == key) { 0103 QStringList eols; 0104 0105 // NOTE: EOLs are declared in Kate::TextBuffer::EndOfLineMode 0106 eols << QStringLiteral("lf") << QStringLiteral("crlf") << QStringLiteral("cr"); 0107 0108 if ((intValue = eols.indexOf(value)) != -1) { 0109 m_document->config()->setEol(intValue); 0110 m_document->config()->setAllowEolDetection(false); 0111 } else { 0112 qCDebug(LOG_KTE) << "End of line in .editorconfig other than unix/dos/mac"; 0113 } 0114 } else if (QLatin1String("indent_size") == key) { 0115 if (QLatin1String("tab") == value) { 0116 setIndentSizeAsTabWidth = true; 0117 } else if (checkIntValue(value, &intValue)) { 0118 m_document->config()->setIndentationWidth(intValue); 0119 indentSizeSet = true; 0120 } else { 0121 qCDebug(LOG_KTE) << "Indent size in .editorconfig not a number, nor tab"; 0122 } 0123 } else if (QLatin1String("indent_style") == key) { 0124 if (QLatin1String("tab") == value) { 0125 m_document->config()->setReplaceTabsDyn(false); 0126 } else if (QLatin1String("space") == value) { 0127 m_document->config()->setReplaceTabsDyn(true); 0128 } else { 0129 qCDebug(LOG_KTE) << "Indent style in .editorconfig other than tab or space"; 0130 } 0131 } else if (QLatin1String("insert_final_newline") == key && checkBoolValue(value, &boolValue)) { 0132 m_document->config()->setNewLineAtEof(boolValue); 0133 } else if (QLatin1String("max_line_length") == key && checkIntValue(value, &intValue)) { 0134 m_document->config()->setWordWrapAt(intValue); 0135 } else if (QLatin1String("tab_width") == key && checkIntValue(value, &intValue)) { 0136 m_document->config()->setTabWidth(intValue); 0137 tabWidth = intValue; 0138 tabWidthSet = true; 0139 } else if (QLatin1String("trim_trailing_whitespace") == key && checkBoolValue(value, &boolValue)) { 0140 if (boolValue) { 0141 m_document->config()->setRemoveSpaces(1 /* remove trailing spaces of modified lines (line modification system) */); 0142 } else { 0143 m_document->config()->setRemoveSpaces(0); 0144 } 0145 } 0146 } 0147 0148 if (setIndentSizeAsTabWidth) { 0149 m_document->config()->setIndentationWidth(tabWidth); 0150 } else if (!tabWidthSet && indentSizeSet) { 0151 m_document->config()->setTabWidth(m_document->config()->indentationWidth()); 0152 } 0153 0154 return 0; 0155 }