gitdiff.cpp 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. #include "gitdiff.h"
  2. #include <gitrepository.h>
  3. #include <QDebug>
  4. #include <git2/types.h>
  5. #include <git2/diff.h>
  6. #include <git2/commit.h>
  7. GitDiff::GitDiff(git_commit* a, git_commit* b, GitRepository *repository) : QObject()
  8. ,m_repository(repository)
  9. {
  10. Q_ASSERT_X(m_repository, "GitDiff", "Repository of NULL");
  11. connect(m_repository, &GitRepository::destroyed, this, &GitDiff::deleteLater);
  12. readBody(a, b);
  13. }
  14. GitDiff::~GitDiff()
  15. {
  16. reset();
  17. }
  18. void GitDiff::readBody(git_commit *a, git_commit *b)
  19. {
  20. git_diff *diff = nullptr;
  21. git_tree *aTree = nullptr;
  22. git_tree *bTree = nullptr;
  23. git_diff_find_options similarityOpts;
  24. if(a != nullptr) {
  25. git_commit_tree(&aTree, a);
  26. }
  27. if(b != nullptr) {
  28. git_commit_tree(&bTree, b);
  29. }
  30. git_diff_tree_to_tree(&diff, m_repository->raw(), aTree, bTree, nullptr);
  31. git_diff_find_init_options(&similarityOpts, GIT_DIFF_FIND_OPTIONS_VERSION);
  32. git_diff_find_similar(diff, &similarityOpts);
  33. git_diff_print(diff,
  34. GIT_DIFF_FORMAT_PATCH,
  35. [](const git_diff_delta *delta, const git_diff_hunk *hunk,
  36. const git_diff_line *line, void *payload) -> int
  37. {
  38. Q_UNUSED(hunk)
  39. QString prefix("<font color=\"%1\">%2");
  40. QString suffix("</font><br/>");
  41. GitDiff* diff = static_cast<GitDiff*>(payload);
  42. QString newFileName(delta->new_file.path);
  43. QString oldFileName(delta->old_file.path);
  44. QString diffData;
  45. switch(line->origin) {
  46. case GIT_DIFF_LINE_ADDITION:
  47. prefix = prefix.arg("#00ff00");
  48. break;
  49. case GIT_DIFF_LINE_DELETION:
  50. prefix = prefix.arg("#ff0000");
  51. break;
  52. case GIT_DIFF_LINE_HUNK_HDR:
  53. prefix = "<br/><b>";
  54. suffix = "</b><br/>";
  55. break;
  56. default:
  57. prefix = prefix.arg("#000000").arg("&nbsp;");
  58. break;
  59. }
  60. if ( line->origin == GIT_DIFF_LINE_ADDITION ||
  61. line->origin == GIT_DIFF_LINE_DELETION) {
  62. prefix = prefix.arg(line->origin);
  63. }
  64. if(!diff->m_diffList.contains(newFileName)) {
  65. diff->m_diffList.insert(newFileName, QPointer<DiffModel>(new DiffModel(newFileName, diff)));
  66. }
  67. if(line->origin != GIT_DIFF_LINE_FILE_HDR) { //Add line only in case if origin is not file header
  68. diffData = QString::fromUtf8(line->content, line->content_len);
  69. } else if(delta->status == GIT_DELTA_RENAMED){ //else check the similarity
  70. if(delta->similarity == 100) {
  71. diffData = QString(oldFileName + " -> " + newFileName);
  72. }
  73. diff->m_diffList[newFileName]->setSimilarity(delta->similarity);
  74. }
  75. if(!diffData.isEmpty()) {
  76. diff->m_diffList[newFileName]->append(prefix);
  77. diff->m_diffList[newFileName]->append(diffData.toHtmlEscaped().replace(" ", "&nbsp;"));
  78. diff->m_diffList[newFileName]->append(suffix);
  79. }
  80. diff->m_diffList[newFileName]->setType(delta->status);
  81. return 0;
  82. }, this);
  83. git_diff_free(diff);
  84. git_tree_free(aTree);
  85. git_tree_free(bTree);
  86. }
  87. void GitDiff::reset()
  88. {
  89. foreach (QPointer<DiffModel> model, m_diffList) {
  90. model.clear();
  91. }
  92. m_diffList.clear();
  93. }
  94. QStringList GitDiff::files()
  95. {
  96. return m_diffList.keys();
  97. }
  98. DiffModel* GitDiff::model(const QString& file)
  99. {
  100. DiffModel* model = m_diffList.value(file).data();
  101. return model;
  102. }