2 * @file MergeDocLineDiffs.cpp
4 * @brief Implementation file for word diff highlighting (F4) for merge edit & detail views
7 // RCS ID line follows -- this is updated by CVS
8 // $Id: MergeDocLineDiffs.cpp 7067 2009-12-29 14:22:46Z kimmov $
15 #include "MergeEditView.h"
16 #include "DiffTextBuffer.h"
17 #include "stringdiffs.h"
18 #include "UnicodeString.h"
23 static char THIS_FILE[] = __FILE__;
29 * @brief Display the line/word difference highlight in edit view
32 HighlightDiffRect(CMergeEditView * pView, const CRect & rc)
36 // Should we remove existing selection ?
41 // with anchor at left and caret at right
42 // this seems to be conventional behavior in Windows editors
43 pView->SelectArea(rc.TopLeft(), rc.BottomRight());
44 pView->SetCursorPos(rc.BottomRight());
45 pView->SetNewAnchor(rc.TopLeft());
46 // try to ensure that selected area is visible
47 pView->EnsureVisible(rc.TopLeft(), rc.BottomRight());
52 * @brief Highlight difference in current line (left & right panes)
54 void CMergeDoc::Showlinediff(CMergeEditView *pView, bool bReversed)
59 Computelinediff(pView, rc, bReversed);
61 IF_IS_TRUE_ALL ((rc[pane].top == -1), pane, m_nBuffers)
63 String caption = _("Line difference");
64 String msg = _("No difference");
65 MessageBox(pView->GetSafeHwnd(), msg.c_str(), caption.c_str(), MB_OK);
69 // Actually display selection areas on screen in both edit panels
70 for (pane = 0; pane < m_nBuffers; pane++)
71 HighlightDiffRect(m_pView[pane], rc[pane]);
76 * @brief Returns rectangles to highlight in both views (to show differences in line specified)
78 void CMergeDoc::Computelinediff(CMergeEditView *pView, CRect rc[], bool bReversed)
81 for (file = 0; file < m_nBuffers; file++)
84 CPoint ptStart, ptEnd;
85 pView->GetSelection(ptStart, ptEnd);
87 vector<WordDiff> worddiffs;
88 GetWordDiffArray(ptStart.y, &worddiffs);
90 if (worddiffs.empty())
93 int nActivePane = pView->m_nThisPane;
95 std::vector<WordDiff>::iterator it;
96 for (it = worddiffs.begin(); it != worddiffs.end(); ++it)
98 if ((*it).beginline[nActivePane] <= ptStart.y && ptStart.y <= (*it).endline[nActivePane])
100 int begin = ((*it).beginline[nActivePane] < ptStart.y) ? 0 : (*it).begin[nActivePane];
101 int end = ((*it).endline[nActivePane] > ptStart.y) ? m_ptBuf[nActivePane]->GetLineLength(ptStart.y) : (*it).end[nActivePane];
102 if (begin <= ptStart.x && ptStart.x <= end)
109 if (it != worddiffs.end())
112 if (it == worddiffs.end())
113 it = worddiffs.begin();
117 if (it == worddiffs.begin() || it == worddiffs.end())
118 it = worddiffs.end() - 1;
123 for (file = 0; file < m_nBuffers; file++)
125 rc[file].left = (*it).begin[file];
126 rc[file].top = (*it).beginline[file];
127 rc[file].right =(*it).end[file];
128 rc[file].bottom = (*it).endline[file];
132 void CMergeDoc::ClearWordDiffCache(int nDiff/* = -1 */)
136 m_cacheWordDiffs.clear();
140 std::map<int, std::vector<WordDiff> >::iterator it = m_cacheWordDiffs.find(nDiff);
141 if (it != m_cacheWordDiffs.end())
142 m_cacheWordDiffs.erase(it);
147 * @brief Return array of differences in specified line
148 * This is used by algorithm for line diff coloring
149 * (Line diff coloring is distinct from the selection highlight code)
151 void CMergeDoc::GetWordDiffArray(int nLineIndex, vector<WordDiff> *pWordDiffs)
155 int nDiff = m_diffList.LineToDiff(nLineIndex);
158 std::map<int, std::vector<WordDiff> >::iterator itmap = m_cacheWordDiffs.find(nDiff);
159 if (itmap != m_cacheWordDiffs.end())
161 pWordDiffs->resize((*itmap).second.size());
162 std::copy((*itmap).second.begin(), (*itmap).second.end(), pWordDiffs->begin());
166 m_diffList.GetDiff(nDiff, cd);
168 DIFFOPTIONS diffOptions = {0};
169 m_diffWrapper.GetOptions(&diffOptions);
171 std::unique_ptr<int[]> nOffsets[3];
172 const int LineLimit = 20;
173 bool diffPerLine = false;
175 for (file = 0; file < m_nBuffers; file++)
177 if (cd.dend[file] - cd.dbegin[file] > LineLimit)
184 int nLineBegins[3], nLineEnds[3];
185 for (file = 0; file < m_nBuffers; file++)
189 nLineBegins[file] = cd.dbegin[file];
190 nLineEnds[file] = cd.dend[file];
194 nLineBegins[file] = nLineEnds[file] = nLineIndex;
198 for (file = 0; file < m_nBuffers; file++)
200 int nLineBegin = nLineBegins[file], nLineEnd = nLineEnds[file];
201 nOffsets[file].reset(new int[nLineEnd - nLineBegin + 1]);
203 if (nLineBegin != nLineEnd || m_ptBuf[file]->GetLineLength(nLineEnd) > 0)
204 m_ptBuf[file]->GetTextWithoutEmptys(nLineBegin, 0, nLineEnd, m_ptBuf[file]->GetLineLength(nLineEnd), strText);
205 strText += m_ptBuf[file]->GetLineEol(nLineEnd);
208 nOffsets[file][0] = 0;
209 for (int nLine = nLineBegin; nLine < nLineEnd; nLine++)
210 nOffsets[file][nLine-nLineBegin+1] = nOffsets[file][nLine-nLineBegin] + m_ptBuf[file]->GetFullLineLength(nLine);
213 // Options that affect comparison
214 bool casitive = !diffOptions.bIgnoreCase;
215 int xwhite = diffOptions.nIgnoreWhitespace;
216 int breakType = GetBreakType(); // whitespace only or include punctuation
217 bool byteColoring = GetByteColoringOption();
219 std::vector<wdiff> worddiffs;
220 // Make the call to stringdiffs, which does all the hard & tedious computations
221 sd_ComputeWordDiffs(m_nBuffers, str, casitive, xwhite, breakType, byteColoring, &worddiffs);
224 std::vector<wdiff>::iterator it;
225 for (i = 0, it = worddiffs.begin(); it != worddiffs.end(); i++, it++)
228 for (file = 0; file < m_nBuffers; file++)
231 int nLineBegin = nLineBegins[file], nLineEnd = nLineEnds[file];
232 for (nLine = nLineBegin; nLine < nLineEnd; nLine++)
234 if (it->begin[file] == nOffsets[file][nLine-nLineBegin] || it->begin[file] < nOffsets[file][nLine-nLineBegin+1])
237 wd.beginline[file] = nLine;
238 wd.begin[file] = it->begin[file] - nOffsets[file][nLine-nLineBegin];
239 if (m_ptBuf[file]->GetLineLength(nLine) < wd.begin[file])
240 wd.begin[file] = m_ptBuf[file]->GetLineLength(nLine);
242 for (; nLine < nLineEnd; nLine++)
244 if (it->end[file] + 1 == nOffsets[file][nLine-nLineBegin] || it->end[file] + 1 < nOffsets[file][nLine-nLineBegin+1])
247 wd.endline[file] = nLine;
248 wd.end[file] = it->end[file] + 1 - nOffsets[file][nLine-nLineBegin];
249 if (m_ptBuf[file]->GetLineLength(nLine) < wd.end[file])
250 wd.end[file] = m_ptBuf[file]->GetLineLength(nLine);
254 pWordDiffs->push_back(wd);
259 m_cacheWordDiffs[nDiff].resize(pWordDiffs->size());
260 std::copy(pWordDiffs->begin(), pWordDiffs->end(), m_cacheWordDiffs[nDiff].begin());