File indexing completed on 2025-01-05 05:19:43
0001 /* 0002 SPDX-FileCopyrightText: 2022 Waqar Ahmed <waqar.17a@gmail.com> 0003 SPDX-License-Identifier: LGPL-2.0-or-later 0004 */ 0005 #pragma once 0006 0007 #include <gitprocess.h> 0008 0009 #include <QDebug> 0010 #include <QFileInfo> 0011 #include <QProcess> 0012 #include <QString> 0013 0014 #include <charconv> 0015 #include <optional> 0016 #include <vector> 0017 0018 struct ModifiedLines { 0019 int startLine; 0020 int endline; 0021 }; 0022 0023 namespace __internal 0024 { 0025 static inline auto parseRange(std::string_view sv) -> std::optional<std::pair<int, int>> 0026 { 0027 if (sv.empty()) { 0028 return {}; 0029 } 0030 if (sv[0] == '+') { 0031 sv.remove_prefix(1); 0032 } 0033 0034 const std::size_t pos = sv.find(','); 0035 if (pos == std::string_view::npos) { 0036 // if comma not found, means line count == 1 0037 int s = 0; 0038 auto res = std::from_chars(sv.data(), sv.data() + sv.size(), s); 0039 if (res.ptr != (sv.data() + sv.size())) { 0040 return {}; 0041 } 0042 return std::pair<int, int>(s, s); 0043 } 0044 0045 int s = 0; 0046 auto res = std::from_chars(sv.data(), sv.data() + pos, s); 0047 if (res.ptr != (sv.data() + pos)) { 0048 return {}; 0049 } 0050 int c = 0; 0051 res = std::from_chars(sv.data() + pos + 1, sv.data() + sv.size(), c); 0052 if (res.ptr != (sv.data() + sv.size())) { 0053 return {}; 0054 } 0055 return std::pair<int, int>(s, s + c); 0056 } 0057 0058 static inline auto modifedLinesFromGitDiff(const QByteArray &out) -> std::optional<std::vector<ModifiedLines>> 0059 { 0060 int start = out.indexOf("@@ "); 0061 if (start == -1) { 0062 return std::nullopt; 0063 } 0064 start += 3; // skip @@ 0065 int next = 0; 0066 std::vector<ModifiedLines> ret; 0067 while (start > -1) { 0068 next = out.indexOf(" @@", start); 0069 if (next == -1) { 0070 return std::nullopt; 0071 } 0072 int space = out.indexOf(' ', start); 0073 if (space == -1) { 0074 return std::nullopt; 0075 } 0076 space++; 0077 std::string_view sv(out.constData() + space, next - space); 0078 const auto res = parseRange(sv); 0079 if (!res.has_value()) { 0080 return std::nullopt; 0081 } 0082 const auto [startLine, endLine] = res.value(); 0083 ret.push_back({startLine, endLine}); 0084 0085 start = next + 3; 0086 start = out.indexOf("@@ ", start); 0087 } 0088 return ret; 0089 } 0090 } 0091 0092 static inline std::optional<std::vector<ModifiedLines>> getModifiedLines(const QString &filePath) 0093 { 0094 if (!QFile::exists(filePath)) { 0095 qWarning() << "Doc doesn't exist, shouldn't happen!"; 0096 return std::nullopt; 0097 } 0098 0099 QProcess git; 0100 setupGitProcess(git, QFileInfo(filePath).absolutePath(), {QStringLiteral("diff"), QStringLiteral("--no-color"), QStringLiteral("-U0"), filePath}); 0101 startHostProcess(git, QProcess::ReadOnly); 0102 if (!git.waitForStarted() || !git.waitForFinished()) { 0103 return std::nullopt; 0104 } 0105 if (git.exitCode() != 0 || git.exitStatus() != QProcess::NormalExit) { 0106 return std::nullopt; 0107 } 0108 return __internal::modifedLinesFromGitDiff(git.readAllStandardOutput()); 0109 }