From 70f1f97beb4b0e50b24e2ccfe4bba327f260cc57 Mon Sep 17 00:00:00 2001 From: Takashi Sawanaka Date: Wed, 20 Sep 2023 20:48:28 +0900 Subject: [PATCH] Improve line filters and substitution filters (#2032) --- Src/CompareEngines/Wrap_DiffUtils.cpp | 29 +- Src/DiffWrapper.cpp | 515 ++++++++++++++++++++------ Src/DiffWrapper.h | 6 +- 3 files changed, 403 insertions(+), 147 deletions(-) diff --git a/Src/CompareEngines/Wrap_DiffUtils.cpp b/Src/CompareEngines/Wrap_DiffUtils.cpp index 3bbb8acfb6b..be9b6c4cc7c 100644 --- a/Src/CompareEngines/Wrap_DiffUtils.cpp +++ b/Src/CompareEngines/Wrap_DiffUtils.cpp @@ -144,32 +144,19 @@ int DiffUtils::CompareFiles(DiffFileData* diffData) /* Determine range of line numbers involved in each file. */ int first0 = 0, last0 = 0, first1 = 0, last1 = 0, deletes = 0, inserts = 0; analyze_hunk (thisob, &first0, &last0, &first1, &last1, &deletes, &inserts, diffData->m_inf); + + /* Reconnect the script so it will all be freed properly. */ + end->link = next; + if (deletes!=0 || inserts!=0 || thisob->trivial!=0) { - /* Print the lines that the first file has. */ - int trans_a0 = 0, trans_b0 = 0, trans_a1 = 0, trans_b1 = 0; - translate_range(&diffData->m_inf[0], first0, last0, &trans_a0, &trans_b0); - translate_range(&diffData->m_inf[1], first1, last1, &trans_a1, &trans_b1); - - //Determine quantity of lines in this block for both sides - int QtyLinesLeft = (trans_b0 - trans_a0) + 1; - int QtyLinesRight = (trans_b1 - trans_a1) + 1; - if (usefilters) + OP_TYPE op = (deletes == 0 && inserts == 0) ? OP_TRIVIAL : OP_DIFF; + + if (op != OP_TRIVIAL && usefilters) { - OP_TYPE op = OP_NONE; - if (deletes == 0 && inserts == 0) - op = OP_TRIVIAL; - else - op = OP_DIFF; - m_pDiffWrapper->PostFilter(ctxt, trans_a0 - 1, QtyLinesLeft, trans_a1 - 1, QtyLinesRight, op, diffData->m_inf); - if(op == OP_TRIVIAL) - { - thisob->trivial = 1; - } + m_pDiffWrapper->PostFilter(ctxt, thisob, diffData->m_inf); } } - /* Reconnect the script so it will all be freed properly. */ - end->link = next; } } } diff --git a/Src/DiffWrapper.cpp b/Src/DiffWrapper.cpp index aec9f19d3c5..726bf158619 100644 --- a/Src/DiffWrapper.cpp +++ b/Src/DiffWrapper.cpp @@ -61,6 +61,8 @@ extern "C" int is_blank_line(char const* pch, char const* limit); static void CopyTextStats(const file_data * inf, FileTextStats * myTextStats); static void CopyDiffutilTextStats(file_data *inf, DiffFileData * diffData); +constexpr char* FILTERED_LINE = "!" "c0d5089f" "-" "3d91" "-" "4d69" "-" "b406" "-" "dc5a5b51a4f8"; + /** * @brief Default constructor. * Initializes members. @@ -80,6 +82,7 @@ CDiffWrapper::CDiffWrapper() , m_bPluginsEnabled(false) , m_status() , m_codepage(ucr::CP_UTF_8) +, m_xdlFlags(0) { // character that ends a line. Currently this is always `\n' line_end_char = '\n'; @@ -156,6 +159,7 @@ void CDiffWrapper::SetOptions(const DIFFOPTIONS *options) { assert(options != nullptr); m_options.SetFromDiffOptions(*options); + m_xdlFlags = make_xdl_flags(m_options); } void CDiffWrapper::SetPrediffer(const PrediffingInfo * prediffer /*= nullptr*/) @@ -343,133 +347,332 @@ static void ReplaceChars(std::string & str, const char* chars, const char *rep) } /** - * @brief Remove blank lines + * @brief The main entry for post filtering. Performs post-filtering, by setting comment blocks to trivial + * @param [in, out] thisob Current change + * @return Number of trivial diffs inserted */ -void RemoveBlankLines(std::string &str) +int CDiffWrapper::PostFilter(PostFilterContext& ctxt, change* thisob, const file_data *file_data_ary) const { - size_t pos = 0; - while (pos < str.length()) - { - size_t posend = str.find_first_of("\r\n", pos); - if (posend != std::string::npos) - posend = str.find_first_not_of("\r\n", posend); - if (posend == std::string::npos) - posend = str.length(); - if (is_blank_line(str.data() + pos, str.data() + posend)) - str.erase(pos, posend - pos); - else - pos = posend; - } -} - -/** -@brief The main entry for post filtering. Performs post-filtering, by setting comment blocks to trivial -@param [in] LineNumberLeft - First line number to read from left file -@param [in] QtyLinesLeft - Number of lines in the block for left file -@param [in] LineNumberRight - First line number to read from right file -@param [in] QtyLinesRight - Number of lines in the block for right file -@param [in,out] Op - This variable is set to trivial if block should be ignored. -*/ -void CDiffWrapper::PostFilter(PostFilterContext& ctxt, int LineNumberLeft, int QtyLinesLeft, int LineNumberRight, - int QtyLinesRight, OP_TYPE &Op, const file_data *file_data_ary) const -{ - if (Op == OP_TRIVIAL) - return; - - if (m_pFilterList != nullptr && m_pFilterList->HasRegExps()) - { - // Match lines against regular expression filters - // Our strategy is that every line in both sides must - // match regexp before we mark difference as ignored. - bool match2 = false; - bool match1 = RegExpFilter(LineNumberLeft + file_data_ary[0].linbuf_base, LineNumberLeft + file_data_ary[0].linbuf_base + QtyLinesLeft - 1, &file_data_ary[0]); - if (match1) - match2 = RegExpFilter(LineNumberRight + file_data_ary[1].linbuf_base, LineNumberRight + file_data_ary[1].linbuf_base + QtyLinesRight - 1, &file_data_ary[1]); - if (match1 && match2) - { - Op = OP_TRIVIAL; - return; - } - } - - std::string LineDataLeft, LineDataRight; + const int first0 = thisob->line0; + const int first1 = thisob->line1; + const int last0 = first0 + thisob->deleted - 1; + const int last1 = first1 + thisob->inserted - 1; + int trans_a0 = 0, trans_b0 = 0, trans_a1 = 0, trans_b1 = 0; + translate_range(&file_data_ary[0], first0, last0, &trans_a0, &trans_b0); + translate_range(&file_data_ary[1], first1, last1, &trans_a1, &trans_b1); + const int qtyLinesLeft = (trans_b0 - trans_a0) + 1; //Determine quantity of lines in this block for left side + const int qtyLinesRight = (trans_b1 - trans_a1) + 1;//Determine quantity of lines in this block for right side + const int lineNumberLeft = trans_a0 - 1; + const int lineNumberRight = trans_a1 - 1; + + std::string lineDataLeft, lineDataRight; if (m_options.m_filterCommentsLines) { ctxt.dwCookieLeft = GetLastLineCookie(ctxt.dwCookieLeft, - ctxt.nParsedLineEndLeft + 1, LineNumberLeft - 1, file_data_ary[0].linbuf + file_data_ary[0].linbuf_base, m_pFilterCommentsDef); + ctxt.nParsedLineEndLeft + 1, lineNumberLeft - 1, file_data_ary[0].linbuf + file_data_ary[0].linbuf_base, m_pFilterCommentsDef); ctxt.dwCookieRight = GetLastLineCookie(ctxt.dwCookieRight, - ctxt.nParsedLineEndRight + 1, LineNumberRight - 1, file_data_ary[1].linbuf + file_data_ary[1].linbuf_base, m_pFilterCommentsDef); + ctxt.nParsedLineEndRight + 1, lineNumberRight - 1, file_data_ary[1].linbuf + file_data_ary[1].linbuf_base, m_pFilterCommentsDef); - ctxt.nParsedLineEndLeft = LineNumberLeft + QtyLinesLeft - 1; - ctxt.nParsedLineEndRight = LineNumberRight + QtyLinesRight - 1;; + ctxt.nParsedLineEndLeft = lineNumberLeft + qtyLinesLeft - 1; + ctxt.nParsedLineEndRight = lineNumberRight + qtyLinesRight - 1;; ctxt.dwCookieLeft = GetCommentsFilteredText(ctxt.dwCookieLeft, - LineNumberLeft, ctxt.nParsedLineEndLeft, file_data_ary[0].linbuf + file_data_ary[0].linbuf_base, LineDataLeft, m_pFilterCommentsDef); + lineNumberLeft, ctxt.nParsedLineEndLeft, file_data_ary[0].linbuf + file_data_ary[0].linbuf_base, lineDataLeft, m_pFilterCommentsDef); ctxt.dwCookieRight = GetCommentsFilteredText(ctxt.dwCookieRight, - LineNumberRight, ctxt.nParsedLineEndRight, file_data_ary[1].linbuf + file_data_ary[1].linbuf_base, LineDataRight, m_pFilterCommentsDef); + lineNumberRight, ctxt.nParsedLineEndRight, file_data_ary[1].linbuf + file_data_ary[1].linbuf_base, lineDataRight, m_pFilterCommentsDef); } else { - LineDataLeft.assign(file_data_ary[0].linbuf[LineNumberLeft + file_data_ary[0].linbuf_base], - file_data_ary[0].linbuf[LineNumberLeft + QtyLinesLeft + file_data_ary[0].linbuf_base] - - file_data_ary[0].linbuf[LineNumberLeft + file_data_ary[0].linbuf_base]); - LineDataRight.assign(file_data_ary[1].linbuf[LineNumberRight + file_data_ary[1].linbuf_base], - file_data_ary[1].linbuf[LineNumberRight + QtyLinesRight + file_data_ary[1].linbuf_base] - - file_data_ary[1].linbuf[LineNumberRight + file_data_ary[1].linbuf_base]); + lineDataLeft.assign(file_data_ary[0].linbuf[lineNumberLeft + file_data_ary[0].linbuf_base], + file_data_ary[0].linbuf[lineNumberLeft + qtyLinesLeft + file_data_ary[0].linbuf_base] + - file_data_ary[0].linbuf[lineNumberLeft + file_data_ary[0].linbuf_base]); + lineDataRight.assign(file_data_ary[1].linbuf[lineNumberRight + file_data_ary[1].linbuf_base], + file_data_ary[1].linbuf[lineNumberRight + qtyLinesRight + file_data_ary[1].linbuf_base] + - file_data_ary[1].linbuf[lineNumberRight + file_data_ary[1].linbuf_base]); + } + + if (m_pFilterList != nullptr && m_pFilterList->HasRegExps()) + { + // Match lines against regular expression filters + // Our strategy is that every line in both sides must + // match regexp before we mark difference as ignored. + bool match1 = RegExpFilter(lineDataLeft); + bool match2 = RegExpFilter(lineDataRight); + if (match1 && match2) + { + thisob->trivial = 1; + return 0; + } } if (m_pSubstitutionList) { - LineDataLeft = m_pSubstitutionList->Subst(LineDataLeft); - LineDataRight = m_pSubstitutionList->Subst(LineDataRight); + lineDataLeft = m_pSubstitutionList->Subst(lineDataLeft, m_codepage); + lineDataRight = m_pSubstitutionList->Subst(lineDataRight, m_codepage); } if (m_options.m_ignoreWhitespace == WHITESPACE_IGNORE_ALL) { //Ignore character case - ReplaceChars(LineDataLeft, " \t", ""); - ReplaceChars(LineDataRight, " \t", ""); + ReplaceChars(lineDataLeft, " \t", ""); + ReplaceChars(lineDataRight, " \t", ""); } else if (m_options.m_ignoreWhitespace == WHITESPACE_IGNORE_CHANGE) { //Ignore change in whitespace char count - ReplaceChars(LineDataLeft, " \t", " "); - ReplaceChars(LineDataRight, " \t", " "); + ReplaceChars(lineDataLeft, " \t", " "); + ReplaceChars(lineDataRight, " \t", " "); } - if (m_options.m_bIgnoreNumbers ) + if (m_options.m_bIgnoreNumbers) { //Ignore number character case - ReplaceChars(LineDataLeft, "0123456789", ""); - ReplaceChars(LineDataRight, "0123456789", ""); + ReplaceChars(lineDataLeft, "0123456789", ""); + ReplaceChars(lineDataRight, "0123456789", ""); } if (m_options.m_bIgnoreCase) { //ignore case - // std::transform(LineDataLeft.begin(), LineDataLeft.end(), LineDataLeft.begin(), ::toupper); - for (std::string::iterator pb = LineDataLeft.begin(), pe = LineDataLeft.end(); pb != pe; ++pb) + for (std::string::iterator pb = lineDataLeft.begin(), pe = lineDataLeft.end(); pb != pe; ++pb) *pb = static_cast(::toupper(*pb)); - // std::transform(LineDataRight.begin(), LineDataRight.end(), LineDataRight.begin(), ::toupper); - for (std::string::iterator pb = LineDataRight.begin(), pe = LineDataRight.end(); pb != pe; ++pb) + for (std::string::iterator pb = lineDataRight.begin(), pe = lineDataRight.end(); pb != pe; ++pb) *pb = static_cast(::toupper(*pb)); } if (m_options.m_bIgnoreEOLDifference) { - Replace(LineDataLeft, "\r\n", "\n"); - Replace(LineDataLeft, "\r", "\n"); - Replace(LineDataRight, "\r\n", "\n"); - Replace(LineDataRight, "\r", "\n"); + Replace(lineDataLeft, "\r\n", "\n"); + Replace(lineDataLeft, "\r", "\n"); + Replace(lineDataRight, "\r\n", "\n"); + Replace(lineDataRight, "\r", "\n"); } - if (m_options.m_bIgnoreBlankLines) + + // If both match after filtering, mark this diff hunk as trivial and return. + if (lineDataLeft == lineDataRight) { - RemoveBlankLines(LineDataLeft); - RemoveBlankLines(LineDataRight); + //only difference is trival + thisob->trivial = 1; + return 0; } - if (LineDataLeft != LineDataRight) - return; - //only difference is trival - Op = OP_TRIVIAL; + + auto SplitLines = [](const std::string& lines) -> std::vector + { + std::vector result; + const char* line = lines.c_str(); + for (size_t i = 0; i < lines.length(); ++i) + { + char c = lines[i]; + if (c == '\r') + { + if (i + 1 < lines.length() && lines[i + 1] == '\n') + i++; + result.emplace_back(line, lines.c_str() + i + 1 - line); + line = lines.c_str() + i + 1; + } + else if (c == '\n') + { + result.emplace_back(line, lines.c_str() + i + 1 - line); + line = lines.c_str() + i + 1; + } + } + if (!lines.empty() && (lines.back() != '\r' && lines.back() != '\n')) + result.emplace_back(line, lines.c_str() + lines.length() - line); + return result; + }; + + std::vector leftLines = SplitLines(lineDataLeft); + std::vector rightLines = SplitLines(lineDataRight); + + if (qtyLinesLeft != leftLines.size() || qtyLinesRight != rightLines.size()) + return 0; + + // If both do not match as a result of filtering, some lines may match, + // so diff calculation is performed again using the filtered lines. + change* script = diff_2_buffers_xdiff( + lineDataLeft.c_str(), lineDataLeft.length(), + lineDataRight.c_str(), lineDataRight.length(), m_xdlFlags); + + auto TranslateLineNumbers = [](change* thisob, change* script) + { + assert(thisob && script); + for (change* cur = script; cur; cur = cur->link) + { + cur->line0 += thisob->line0; + cur->line1 += thisob->line1; + } + }; + + // Insert lines with no differences as trivial diffs after filtering + auto InsertTrivialChanges = [](change* thisob, change* script) -> int + { + assert(thisob && script); + int l0 = thisob->line0; + int l1 = thisob->line1; + change* first = script; + change* prev = nullptr; + int nTrivialInserts = 0; + for (change* cur = script; cur; cur = cur->link) + { + if (l0 < cur->line0 || l1 < cur->line1) + { + nTrivialInserts++; + change *newob = (change *)xmalloc(sizeof (change)); + newob->line0 = l0; + newob->line1 = l1; + newob->deleted = cur->line0 - l0; + newob->inserted = cur->line1 - l1; + newob->trivial = 1; + newob->match0 = -1; + newob->match1 = -1; + if (cur == first) + { + std::swap(newob->line0, cur->line0); + std::swap(newob->line1, cur->line1); + std::swap(newob->deleted, cur->deleted); + std::swap(newob->inserted, cur->inserted); + std::swap(newob->trivial, cur->trivial); + std::swap(newob->match0, cur->match0); + std::swap(newob->match1, cur->match1); + newob->link = cur->link; + cur->link = newob; + } + else + { + prev->link = newob; + newob->link = cur; + } + } + l0 = cur->line0 + cur->deleted; + l1 = cur->line1 + cur->inserted; + prev = cur; + } + if (l0 < thisob->line0 + thisob->deleted || l1 < thisob->line1 + thisob->inserted) + { + nTrivialInserts++; + change *newob = (change *)xmalloc(sizeof (change)); + prev->link = newob; + newob->line0 = l0; + newob->line1 = l1; + newob->deleted = thisob->line0 + thisob->deleted - l0; + newob->inserted = thisob->line1 + thisob->inserted - l1; + newob->trivial = 1; + newob->match0 = -1; + newob->match1 = -1; + newob->link = nullptr; + } + return nTrivialInserts; + }; + + // Insert blank lines or filtered lines that are only on one side as trivial diffs. + auto InsertTrivialChanges2 = + [](change* thisob, change* script, bool ignoreBlankLines, + const std::vector& leftLines, + const std::vector& rightLines) -> int + { + assert(thisob && script); + auto IsBlankLine = [](const std::string_view& line) + { + for (char c : line) + { + if (!std::isspace(static_cast(c))) + return false; + } + return true; + }; + int nTrivialInserts = 0; + for (change* cur = script; cur; cur = cur->link) + { + if (!cur->trivial && cur->deleted != cur->inserted) + { + bool ignorable = true; + if (cur->deleted > cur->inserted) + { + for (int i = cur->line0 + cur->inserted - thisob->line0; i < cur->line0 + cur->deleted - thisob->line0; ++i) + { + if (!(ignoreBlankLines && IsBlankLine(leftLines[i])) && leftLines[i] != FILTERED_LINE) + ignorable = false; + } + if (ignorable) + { + if (cur->inserted == 0) + { + cur->trivial = 1; + } + else + { + nTrivialInserts++; + change* newob = (change*)xmalloc(sizeof(change)); + newob->line0 = cur->line0 + cur->inserted; + newob->line1 = cur->line1 + cur->inserted; + newob->deleted = cur->deleted - cur->inserted; + newob->inserted = 0; + newob->trivial = 1; + newob->match0 = -1; + newob->match1 = -1; + newob->link = cur->link; + cur->link = newob; + cur->deleted = cur->inserted; + } + } + } + else + { + for (int i = cur->line1 + cur->deleted - thisob->line1; i < cur->line1 + cur->inserted - thisob->line1; ++i) + { + if (!(ignoreBlankLines && IsBlankLine(rightLines[i])) && rightLines[i] != FILTERED_LINE) + ignorable = false; + } + if (ignorable) + { + if (cur->deleted == 0) + { + cur->trivial = 1; + } + else + { + nTrivialInserts++; + change* newob = (change*)xmalloc(sizeof(change)); + newob->line0 = cur->line0 + cur->deleted; + newob->line1 = cur->line1 + cur->deleted; + newob->deleted = 0; + newob->inserted = cur->inserted - cur->deleted; + newob->trivial = 1; + newob->match0 = -1; + newob->match1 = -1; + newob->link = cur->link; + cur->link = newob; + cur->inserted = cur->deleted; + } + } + } + } + } + return nTrivialInserts; + }; + + auto ReplaceChanges = [](change* thisob, change* script) + { + assert(thisob && script); + change* last = nullptr; + for (change* cur = script; cur; cur = cur->link) + last = cur; + last->link = thisob->link; + thisob->link = script->link; + thisob->line0 = script->line0; + thisob->line1 = script->line1; + thisob->deleted = script->deleted; + thisob->inserted = script->inserted; + thisob->trivial = script->trivial; + thisob->match0 = script->match0; + thisob->match1 = script->match1; + free(script); + }; + + TranslateLineNumbers(thisob, script); + int nTrivialInserts = InsertTrivialChanges(thisob, script); + nTrivialInserts += InsertTrivialChanges2(thisob, script, m_options.m_bIgnoreBlankLines, leftLines, rightLines); + ReplaceChanges(thisob, script); + return nTrivialInserts; } /** @@ -940,7 +1143,7 @@ CDiffWrapper::FreeDiffUtilsScript(struct change * & script) * @param [in] FileNo File to match. * return true if any of the expressions matches. */ -bool CDiffWrapper::RegExpFilter(int StartPos, int EndPos, const file_data *pinf) const +bool CDiffWrapper::RegExpFilter(std::string& lines) const { if (m_pFilterList == nullptr) { @@ -949,19 +1152,32 @@ bool CDiffWrapper::RegExpFilter(int StartPos, int EndPos, const file_data *pinf) } bool linesMatch = true; // set to false when non-matching line is found. - int line = StartPos; - while (line <= EndPos && linesMatch) - { - size_t len = pinf->linbuf[line + 1] - pinf->linbuf[line]; - const char *string = pinf->linbuf[line]; - size_t stringlen = linelen(string, len); - if (!m_pFilterList->Match(std::string(string, stringlen), m_codepage)) + std::string replaced; + replaced.reserve(lines.length()); + size_t pos = 0; + while (pos < lines.length()) + { + const char* string = lines.c_str() + pos; + while (pos < lines.length() && (lines[pos] != '\r' && lines[pos] != '\n')) + pos++; + size_t stringlen = lines.c_str() + pos - string; + std::string line = std::string(string, stringlen); + if (!m_pFilterList->Match(line, m_codepage)) { linesMatch = false; + replaced += line; + } + else + { + replaced += FILTERED_LINE; } - ++line; + std::string eol; + while (pos < lines.length() && (lines[pos] == '\r' || lines[pos] == '\n')) + eol += lines[pos++]; + replaced += eol; } + lines = replaced; return linesMatch; } @@ -1000,6 +1216,10 @@ CDiffWrapper::LoadWinMergeDiffsFromDiffUtilsScript(struct change * script, const /* Determine range of line numbers involved in each file. */ int first0=0, last0=0, first1=0, last1=0, deletes=0, inserts=0; analyze_hunk (thisob, &first0, &last0, &first1, &last1, &deletes, &inserts, file_data_ary); + + /* Reconnect the script so it will all be freed properly. */ + end->link = next; + if (deletes || inserts || thisob->trivial) { OP_TYPE op = OP_NONE; @@ -1039,35 +1259,64 @@ CDiffWrapper::LoadWinMergeDiffsFromDiffUtilsScript(struct change * script, const } } } - const int QtyLinesLeft = (trans_b0 - trans_a0) + 1; //Determine quantity of lines in this block for left side - const int QtyLinesRight = (trans_b1 - trans_a1) + 1;//Determine quantity of lines in this block for right side - if (usefilters) - PostFilter(ctxt, trans_a0 - 1, QtyLinesLeft, trans_a1 - 1, QtyLinesRight, op, file_data_ary); - - if (op == OP_TRIVIAL && m_options.m_bCompletelyBlankOutIgnoredDiffereneces) + int nTrivialInserts = 0; + if (op != OP_TRIVIAL && usefilters) + nTrivialInserts = PostFilter(ctxt, thisob, file_data_ary); + if (nTrivialInserts > 0) { - if (QtyLinesLeft == QtyLinesRight) - { - op = OP_NONE; - } - else if (QtyLinesLeft < QtyLinesRight) + while (thisob != next) { - trans_a0 += QtyLinesLeft; - trans_a1 += QtyLinesLeft; + op = (thisob->trivial) ? OP_TRIVIAL : OP_DIFF; + first0 = thisob->line0; + first1 = thisob->line1; + last0 = first0 + thisob->deleted - 1; + last1 = first1 + thisob->inserted - 1; + translate_range (&file_data_ary[0], first0, last0, &trans_a0, &trans_b0); + translate_range (&file_data_ary[1], first1, last1, &trans_a1, &trans_b1); + const int qtyLinesLeft = (trans_b0 - trans_a0) + 1; //Determine quantity of lines in this block for left side + const int qtyLinesRight = (trans_b1 - trans_a1) + 1;//Determine quantity of lines in this block for right side + + if (op == OP_TRIVIAL && m_options.m_bCompletelyBlankOutIgnoredDiffereneces) + { + if (qtyLinesLeft == qtyLinesRight) + { + op = OP_NONE; + } + else + { + trans_a0 += qtyLinesLeft < qtyLinesRight ? qtyLinesLeft : qtyLinesRight; + trans_a1 += qtyLinesLeft < qtyLinesRight ? qtyLinesLeft : qtyLinesRight; + } + } + if (op != OP_NONE) + AddDiffRange(m_pDiffList, trans_a0-1, trans_b0-1, trans_a1-1, trans_b1-1, op); + + thisob = thisob->link; } - else + } + else + { + if (thisob->trivial) + op = OP_TRIVIAL; + const int qtyLinesLeft = (trans_b0 - trans_a0) + 1; //Determine quantity of lines in this block for left side + const int qtyLinesRight = (trans_b1 - trans_a1) + 1;//Determine quantity of lines in this block for right side + if (op == OP_TRIVIAL && m_options.m_bCompletelyBlankOutIgnoredDiffereneces) { - trans_a0 += QtyLinesRight; - trans_a1 += QtyLinesRight; + if (qtyLinesLeft == qtyLinesRight) + { + op = OP_NONE; + } + else + { + trans_a0 += qtyLinesLeft < qtyLinesRight ? qtyLinesLeft : qtyLinesRight; + trans_a1 += qtyLinesLeft < qtyLinesRight ? qtyLinesLeft : qtyLinesRight; + } } + if (op != OP_NONE) + AddDiffRange(m_pDiffList, trans_a0-1, trans_b0-1, trans_a1-1, trans_b1-1, op); } - if (op != OP_NONE) - AddDiffRange(m_pDiffList, trans_a0-1, trans_b0-1, trans_a1-1, trans_b1-1, op); } } - - /* Reconnect the script so it will all be freed properly. */ - end->link = next; } } @@ -1153,6 +1402,10 @@ CDiffWrapper::LoadWinMergeDiffsFromDiffUtilsScript3( { /* Determine range of line numbers involved in each file. */ analyze_hunk (thisob, &first0, &last0, &first1, &last1, &deletes, &inserts, pinf); + + /* Reconnect the script so it will all be freed properly. */ + end->link = next; + if (deletes || inserts || thisob->trivial) { if (deletes && inserts) @@ -1205,17 +1458,33 @@ CDiffWrapper::LoadWinMergeDiffsFromDiffUtilsScript3( } } - const int QtyLinesLeft = (trans_b0 - trans_a0) + 1; //Determine quantity of lines in this block for left side - const int QtyLinesRight = (trans_b1 - trans_a1) + 1;//Determine quantity of lines in this block for right side - if (usefilters) - PostFilter(ctxt, trans_a0 - 1, QtyLinesLeft, trans_a1 - 1, QtyLinesRight, op, pinf); - - AddDiffRange(pdiff, trans_a0-1, trans_b0-1, trans_a1-1, trans_b1-1, op); + int nTrivialInserts = 0; + if (op != OP_TRIVIAL && usefilters) + nTrivialInserts = PostFilter(ctxt, thisob, pinf); + if (nTrivialInserts) + { + while (thisob != next) + { + op = (thisob->trivial) ? OP_TRIVIAL : OP_DIFF; + first0 = thisob->line0; + first1 = thisob->line1; + last0 = first0 + thisob->deleted - 1; + last1 = first1 + thisob->inserted - 1; + translate_range (&pinf[0], first0, last0, &trans_a0, &trans_b0); + translate_range (&pinf[1], first1, last1, &trans_a1, &trans_b1); + + AddDiffRange(pdiff, trans_a0-1, trans_b0-1, trans_a1-1, trans_b1-1, op); + thisob = thisob->link; + } + } + else + { + if (thisob->trivial) + op = OP_TRIVIAL; + AddDiffRange(pdiff, trans_a0-1, trans_b0-1, trans_a1-1, trans_b1-1, op); + } } } - - /* Reconnect the script so it will all be freed properly. */ - end->link = next; } } diff --git a/Src/DiffWrapper.h b/Src/DiffWrapper.h index d00329718b0..308ece073f9 100644 --- a/Src/DiffWrapper.h +++ b/Src/DiffWrapper.h @@ -192,8 +192,7 @@ class CDiffWrapper void SetFilterCommentsSourceDef(const String& ext); void SetCodepage(int codepage) { m_codepage = codepage; } void EnablePlugins(bool enable); - void PostFilter(PostFilterContext& ctxt, int LineNumberLeft, int QtyLinesLeft, int LineNumberRight, - int QtyLinesRight, OP_TYPE &Op, const file_data *file_data_ary) const; + int PostFilter(PostFilterContext& ctxt, change* thisob, const file_data* file_data_ary) const; bool Diff2Files(struct change ** diffs, DiffFileData *diffData, int * bin_status, int * bin_file) const; @@ -206,10 +205,11 @@ class CDiffWrapper struct change * script10, struct change * script12, const file_data * inf10, const file_data * inf12); static void FreeDiffUtilsScript(struct change * & script); - bool RegExpFilter(int StartPos, int EndPos, const file_data * pinf) const; + bool RegExpFilter(std::string& lines) const; private: DiffutilsOptions m_options; + int m_xdlFlags; DIFFSTATUS m_status; /**< Status of last compare */ std::shared_ptr m_pFilterList; /**< List of linefilters. */ std::shared_ptr m_pSubstitutionList;