File indexing completed on 2024-04-28 04:39:08
0001 /* 0002 SPDX-FileCopyrightText: 2013 Milian Wolff <mail@milianw.de> 0003 0004 SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0005 */ 0006 0007 #include "filter.h" 0008 0009 #include <KConfigGroup> 0010 0011 #include <array> 0012 0013 using namespace KDevelop; 0014 0015 Filter::Filter() 0016 : targets(Files | Folders) 0017 { 0018 } 0019 0020 Filter::Filter(const SerializedFilter& filter) 0021 : pattern(QString(), Qt::CaseSensitive, QRegExp::WildcardUnix) 0022 , targets(filter.targets) 0023 , type(filter.type) 0024 { 0025 QString pattern = filter.pattern; 0026 if (!filter.pattern.startsWith(QLatin1Char('/')) && !filter.pattern.startsWith(QLatin1Char('*'))) { 0027 // implicitly match against trailing relative path 0028 pattern.prepend(QLatin1String("*/")); 0029 } 0030 if (pattern.endsWith(QLatin1Char('/')) && targets != Filter::Files) { 0031 // implicitly match against folders 0032 targets = Filter::Folders; 0033 pattern.chop(1); 0034 } 0035 this->pattern.setPattern(pattern); 0036 } 0037 0038 SerializedFilter::SerializedFilter() 0039 : targets(Filter::Files | Filter::Folders) 0040 0041 { 0042 0043 } 0044 0045 SerializedFilter::SerializedFilter(const QString& pattern, Filter::Targets targets, Filter::Type type) 0046 : pattern(pattern) 0047 , targets(targets) 0048 , type(type) 0049 { 0050 0051 } 0052 0053 namespace KDevelop { 0054 0055 SerializedFilters defaultFilters() 0056 { 0057 SerializedFilters ret; 0058 ret.reserve(41); 0059 0060 // filter hidden files 0061 ret << SerializedFilter(QStringLiteral(".*"), Filter::Targets(Filter::Files | Filter::Folders)); 0062 // but do show some with special meaning 0063 0064 static const std::array<QString, 19> configFiles = { 0065 // Version control 0066 QStringLiteral(".gitignore"), 0067 QStringLiteral(".gitmodules"), 0068 // https://pre-commit.com/ 0069 QStringLiteral(".pre-commit-config.yaml"), 0070 0071 // CI config files 0072 0073 // https://docs.gitlab.com/ee/ci/yaml/ 0074 QStringLiteral(".gitlab-ci.yml"), 0075 // https://travis-ci.org/ 0076 QStringLiteral(".travis.yml"), 0077 0078 // Code quality configs 0079 0080 // https://github.com/c4urself/bump2version/ 0081 QStringLiteral(".bumpversion.cfg"), 0082 // https://clang.llvm.org/docs/ClangFormat.html 0083 QStringLiteral(".clang-format"), 0084 // https://github.com/rust-lang/rust-clippy#configure-the-behavior-of-some-lints 0085 QStringLiteral(".clippy.toml"), 0086 // https://github.com/codespell-project/codespell#using-a-config-file 0087 QStringLiteral(".codespellrc"), 0088 // https://editorconfig.org/ 0089 QStringLiteral(".editorconfig"), 0090 // https://pycqa.github.io/isort/docs/configuration/config_files.html 0091 QStringLiteral(".isort.cfg"), 0092 // https://mypy.readthedocs.io/en/stable/config_file.html 0093 QStringLiteral(".mypy.ini"), 0094 // https://pep8.readthedocs.io 0095 QStringLiteral(".pep8"), 0096 // https://prettier.io/ 0097 QStringLiteral(".prettierignore"), 0098 QStringLiteral(".prettierrc*"), 0099 // https://www.pydocstyle.org/en/stable/usage.html#configuration-files 0100 QStringLiteral(".pydocstyle*"), 0101 // https://pylint.readthedocs.io/en/stable/user_guide/usage/run.html#command-line-options 0102 QStringLiteral(".pylintrc"), 0103 // https://docs.readthedocs.io/en/stable/config-file/v2.html 0104 QStringLiteral(".readthedocs.y*ml"), 0105 // https://yamllint.readthedocs.io/en/stable/configuration.html#configuration 0106 QStringLiteral(".yamllint*"), 0107 }; 0108 for (const QString& file : configFiles) { 0109 ret << SerializedFilter(file, Filter::Files, Filter::Inclusive); 0110 } 0111 0112 static const std::array<QString, 1> configFolders = { 0113 // CI config folders 0114 0115 // https://circleci.com/docs/ 0116 QStringLiteral(".circleci"), 0117 }; 0118 for (const QString& folder : configFolders) { 0119 ret << SerializedFilter(folder, Filter::Folders, Filter::Inclusive); 0120 } 0121 0122 // common vcs folders which we want to hide 0123 static const std::array<QString, 9> invalidFolders = { 0124 QStringLiteral(".git"), QStringLiteral("CVS"), QStringLiteral(".svn"), QStringLiteral("_svn"), 0125 QStringLiteral("SCCS"), QStringLiteral("_darcs"), QStringLiteral(".hg"), QStringLiteral(".bzr"), QStringLiteral("__pycache__") 0126 }; 0127 for (const QString& folder : invalidFolders) { 0128 ret << SerializedFilter(folder, Filter::Folders); 0129 } 0130 0131 // common files which we want to hide 0132 static const std::array<QString, 20> filePatterns = { 0133 // binary files (Unix) 0134 QStringLiteral("*.o"), QStringLiteral("*.a"), QStringLiteral("*.so"), QStringLiteral("*.so.*"), 0135 // binary files (Windows) 0136 QStringLiteral("*.obj"), QStringLiteral("*.lib"), QStringLiteral("*.dll"), QStringLiteral("*.exp"), QStringLiteral("*.pdb"), 0137 // generated files 0138 QStringLiteral("moc_*.cpp"), QStringLiteral("*.moc"), QStringLiteral("ui_*.h"), QStringLiteral("*.qmlc"), QStringLiteral("qrc_*.cpp"), 0139 // backup files 0140 QStringLiteral("*~"), QStringLiteral("*.orig"), QStringLiteral(".*.kate-swp"), QStringLiteral(".*.swp"), 0141 // python cache and object files 0142 QStringLiteral("*.pyc"), QStringLiteral("*.pyo") 0143 }; 0144 for (const QString& filePattern : filePatterns) { 0145 ret << SerializedFilter(filePattern, Filter::Files); 0146 } 0147 0148 return ret; 0149 } 0150 0151 SerializedFilters readFilters(const KSharedConfigPtr& config) 0152 { 0153 if (!config->hasGroup("Filters")) { 0154 return defaultFilters(); 0155 } 0156 const KConfigGroup& group = config->group("Filters"); 0157 const int size = group.readEntry("size", -1); 0158 if (size == -1) { 0159 // fallback 0160 return defaultFilters(); 0161 } 0162 0163 SerializedFilters filters; 0164 filters.reserve(size); 0165 for (int i = 0; i < size; ++i) { 0166 const QByteArray subGroup = QByteArray::number(i); 0167 if (!group.hasGroup(subGroup)) { 0168 continue; 0169 } 0170 const KConfigGroup& subConfig = group.group(subGroup); 0171 const QString pattern = subConfig.readEntry("pattern", QString()); 0172 Filter::Targets targets(subConfig.readEntry("targets", 0)); 0173 Filter::Type type = static_cast<Filter::Type>(subConfig.readEntry("inclusive", 0)); 0174 filters << SerializedFilter(pattern, targets, type); 0175 } 0176 0177 return filters; 0178 } 0179 0180 void writeFilters(const SerializedFilters& filters, KSharedConfigPtr config) 0181 { 0182 // clear existing 0183 config->deleteGroup("Filters"); 0184 0185 // write new 0186 KConfigGroup group = config->group("Filters"); 0187 group.writeEntry("size", filters.size()); 0188 int i = 0; 0189 for (const SerializedFilter& filter : filters) { 0190 KConfigGroup subGroup = group.group(QByteArray::number(i++)); 0191 subGroup.writeEntry("pattern", filter.pattern); 0192 subGroup.writeEntry("targets", static_cast<int>(filter.targets)); 0193 subGroup.writeEntry("inclusive", static_cast<int>(filter.type)); 0194 } 0195 config->sync(); 0196 } 0197 0198 Filters deserialize(const SerializedFilters& filters) 0199 { 0200 Filters ret; 0201 ret.reserve(filters.size()); 0202 for (const SerializedFilter& filter : filters) { 0203 ret << Filter(filter); 0204 } 0205 return ret; 0206 } 0207 0208 }