// WinMerge: an interactive diff/merge utility
// Copyright (C) 1997-2000 Thingamahoochie Software
// Author: Dean Grimm
-//
-// This program is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation; either version 2 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-//
+// SPDX-License-Identifier: GPL-2.0-or-later
/////////////////////////////////////////////////////////////////////////////
/**
* @file GhostTextBuffer.cpp
context.m_ptEnd.y = nLine + 1;
CCrystalTextBuffer::InsertLine (_T(""), 0, nLine);
- if (pSource != NULL)
+ if (pSource != nullptr)
UpdateViews (pSource, &context, UPDATE_HORZRANGE | UPDATE_VERTRANGE, nLine);
return true;
for (int i = nLine ; i < nLine + nCount; i++)
{
- ASSERT (GetLineFlags(i) & LF_GHOST);
+ ASSERT ( (GetLineFlags(i) & LF_GHOST) != 0 );
m_aLines[i].Clear();
}
vector<LineInfo>::iterator iterEnd = iterBegin + nCount;
m_aLines.erase(iterBegin, iterEnd);
- if (pSource != NULL)
+ if (pSource != nullptr)
{
CDeleteContext context;
context.m_ptStart.y = nLine;
if (nLine == GetLineCount())
nLine--;
// The last parameter is optimization
- // - don't recompute lines preceeding the removed line.
+ // - don't recompute lines preceding the removed line.
UpdateViews (pSource, &context, UPDATE_HORZRANGE | UPDATE_VERTRANGE,
nLine);
}
* @brief Get text of specified lines (ghost lines will not contribute to text).
*
* @param nCrlfStyle determines the EOL type in the returned buffer.
- * If nCrlfStyle equals CRLF_STYLE_AUTOMATIC, we read the EOL from the line buffer
+ * If nCrlfStyle equals CRLFSTYLE::AUTOMATIC, we read the EOL from the line buffer
*
* @note This function has its base in CrystalTextBuffer
* CrystalTextBuffer::GetTextWithoutEmptys() is for a buffer with no ghost lines.
* CrystalTextBuffer::GetText() returns text including ghost lines.
* These two base functions never read the EOL from the line buffer, they
- * use CRLF_STYLE_DOS when nCrlfStyle equals CRLF_STYLE_AUTOMATIC.
+ * use CRLFSTYLE::DOS when nCrlfStyle equals CRLFSTYLE::AUTOMATIC.
*/
void CGhostTextBuffer:: /* virtual override */
GetTextWithoutEmptys(int nStartLine, int nStartChar,
int nEndLine, int nEndChar,
- CString &text, CRLFSTYLE nCrlfStyle /*= CRLF_STYLE_AUTOMATIC */,
+ CString &text, CRLFSTYLE nCrlfStyle /*= CRLFSTYLE::AUTOMATIC */,
bool bExcludeInvisibleLines /*= true*/) const
{
const size_t lines = m_aLines.size();
nBufSize += (GetFullLineLength(i) + 2); // in case we insert EOLs
LPTSTR pszBuf = text.GetBuffer(nBufSize);
- if (nCrlfStyle != CRLF_STYLE_AUTOMATIC)
+ if (nCrlfStyle != CRLFSTYLE::AUTOMATIC)
{
// we must copy this EOL type only
const CString sEol = GetStringEol (nCrlfStyle);
// (If this happens, editor probably has bug)
ASSERT(false);
CString sEol = GetStringEol (nCrlfStyle);
- CopyMemory(pszBuf, sEol, sEol.GetLength());
+ CopyMemory(pszBuf, sEol, sEol.GetLength() * sizeof(TCHAR));
pszBuf += sEol.GetLength();
}
}
if (i >= 0 && !m_aLines[i].HasEol())
CCrystalTextBuffer::InsertText(pSource, i, GetLineLength(i), text, text.GetLength(), nEndLine, nEndChar, 0, bHistory);
else if (!LineInfo::IsEol(pszText[cchText - 1]))
- CCrystalTextBuffer::InsertText(pSource, nLine, 0, text, text.GetLength(), nEndLine, nEndChar, 0, bHistory);
+ {
+ auto findRealLine = [&](int nLine) {
+ for (; nLine < GetLineCount(); ++nLine) { if ((GetLineFlags(nLine) & LF_GHOST) == 0) break; }
+ if (nLine == GetLineCount())
+ return -1;
+ return nLine;
+ };
+ if (findRealLine(nLine) != -1)
+ CCrystalTextBuffer::InsertText(pSource, nLine, 0, text, text.GetLength(), nEndLine, nEndChar, 0, bHistory);
+ }
}
if (!CCrystalTextBuffer::InsertText (pSource, nLine, nPos, pszText,
// file. Later (below), the Ghost status of both the first and last inserted
// lines will get straightened out, with the trailing Ghost line becomming
// a NULL line.
- if ((GetLineFlags(nLine) & LF_GHOST) == 0) // first line still marked GHOST
+ if ((GetLineFlags(nLine) & LF_GHOST) != 0) // first line still marked GHOST
bSpecialLastLineHandling = false;
else
bDiscrepancyInInsertedLines = false;
if (bSpecialLastLineHandling)
{
- // By setting the last line (in this special case, see above) to NULL,
+ // By setting the last line (in this special case, see above) to `nullptr`,
// the line will eventually be removed or become an actual LF_GHOST line.
int nLastLine = GetLineCount()-1;
ASSERT(m_aLines[nLastLine].FullLength() == 0);
DeleteText2 (CCrystalTextView * pSource, int nStartLine, int nStartChar,
int nEndLine, int nEndChar, int nAction /*= CE_ACTION_UNKNOWN*/, bool bHistory /*= true*/)
{
- if ((GetLineFlags(nEndLine) & LF_GHOST) == 0)
+ int const nLineCount = GetLineCount();
+ while (nEndLine < nLineCount - 1 && GetLineFlags(nEndLine) & LF_GHOST)
+ ++nEndLine;
+ if (!CCrystalTextBuffer::DeleteText2(pSource, nStartLine, nStartChar,
+ nEndLine, nEndChar, nAction, bHistory))
{
- if (!CCrystalTextBuffer::DeleteText2(pSource, nStartLine, nStartChar,
- nEndLine, nEndChar, nAction, bHistory))
- {
- return false;
- }
- }
- else
- {
- // if the last line in selection to be deleted is a ghost line,
- // the EOL of last real line in selection should not be deleted.
- // Otherwise, a line with no EOL will appear.
- int nEndLine2 = nEndLine;
- int nEndChar2 = nEndChar;
- for (; nEndLine2 >= nStartLine; --nEndLine2)
- {
- if ((GetLineFlags(nEndLine2) & LF_GHOST) == 0)
- break;
- }
- if (nStartLine <= nEndLine2)
- {
- if(nEndLine2 != nEndLine)
- nEndChar2 = GetLineLength(nEndLine2);
- if (!CCrystalTextBuffer::DeleteText2(pSource, nStartLine, nStartChar,
- nEndLine2, nEndChar2, nAction, bHistory))
- {
- return false;
- }
- InternalDeleteGhostLine(pSource, nStartLine + 1, nEndLine - (nEndLine2 + 1) + 1);
- }
- else
- {
- if (bHistory && m_nUndoPosition < static_cast<int>(m_aUndoBuf.size()))
- m_aUndoBuf.resize(m_nUndoPosition);
- InternalDeleteGhostLine(pSource, nEndLine2 + 1, nEndLine - (nEndLine2 + 1));
- }
+ return false;
}
if (nStartChar != 0 || nEndChar != 0)
return;
}
-static int CountEol(LPCTSTR pszText, size_t cchText)
+void CGhostTextBuffer::
+CountEolAndLastLineLength(const CPoint& ptStartPos, LPCTSTR pszText, size_t cchText, int &nLastLineLength, int &nEol)
{
- int nEol = 0;
- for (size_t nTextPos = 0; nTextPos < cchText; ++nTextPos)
+ nLastLineLength = 0;
+ nEol = 0;
+ if (m_bTableEditing && m_bAllowNewlinesInQuotes)
+ {
+ bool bInQuote = false;
+ const TCHAR* pszLine = m_aLines[ptStartPos.y].GetLine();
+ for (int j = 0; j < ptStartPos.x; ++j)
+ {
+ if (pszLine[j] == m_cFieldEnclosure)
+ bInQuote = !bInQuote;
+ }
+ for (size_t nTextPos = 0; nTextPos < cchText; ++nTextPos)
+ {
+ if (pszText[nTextPos] == m_cFieldEnclosure)
+ bInQuote = !bInQuote;
+ if (!bInQuote && LineInfo::IsEol(pszText[nTextPos]))
+ {
+ if (nTextPos + 1 < cchText && LineInfo::IsDosEol(&pszText[nTextPos]))
+ ++nTextPos;
+ ++nEol;
+ nLastLineLength = 0;
+ }
+ else
+ ++nLastLineLength;
+ }
+ }
+ else
{
- if (LineInfo::IsEol(pszText[nTextPos]))
+ for (size_t nTextPos = 0; nTextPos < cchText; ++nTextPos)
{
- if (nTextPos + 1 < cchText && LineInfo::IsDosEol(&pszText[nTextPos]))
- ++nTextPos;
- ++nEol;
+ if (LineInfo::IsEol(pszText[nTextPos]))
+ {
+ if (nTextPos + 1 < cchText && LineInfo::IsDosEol(&pszText[nTextPos]))
+ ++nTextPos;
+ ++nEol;
+ nLastLineLength = 0;
+ }
+ else
+ ++nLastLineLength;
}
}
- return nEol;
}
-
void CGhostTextBuffer:: /* virtual override */
AddUndoRecord(bool bInsert, const CPoint & ptStartPos,
const CPoint & ptEndPos, LPCTSTR pszText, size_t cchText,
int nActionType /*= CE_ACTION_UNKNOWN*/,
- CDWordArray *paSavedRevisionNumbers)
+ CDWordArray *paSavedRevisionNumbers /*= nullptr*/)
{
CPoint real_ptStartPos(ptStartPos.x, ComputeRealLine(ptStartPos.y));
- CPoint real_ptEndPos(ptEndPos.x, real_ptStartPos.y + CountEol(pszText, cchText));
+ int nLastLineLength, nEol;
+ CountEolAndLastLineLength(ptStartPos, pszText, cchText, nLastLineLength, nEol);
+ CPoint real_ptEndPos(ptEndPos.x, real_ptStartPos.y + nEol);
+ if (ptEndPos.x == 0 && cchText > 0 && !LineInfo::IsEol(pszText[cchText - 1]))
+ real_ptEndPos.x = nLastLineLength;
CCrystalTextBuffer::AddUndoRecord(bInsert, real_ptStartPos, real_ptEndPos, pszText,
cchText, nActionType, paSavedRevisionNumbers);
}
{
// Try to ensure that we are undoing correctly...
// Just compare the text as it was before Undo operation
- GetTextWithoutEmptys (apparent_ptStartPos.y, apparent_ptStartPos.x, apparent_ptEndPos.y, apparent_ptEndPos.x, text, CRLF_STYLE_AUTOMATIC, false);
+ GetTextWithoutEmptys (apparent_ptStartPos.y, apparent_ptStartPos.x, apparent_ptEndPos.y, apparent_ptEndPos.x, text, CRLFSTYLE::AUTOMATIC, false);
if (static_cast<size_t>(text.GetLength()) == ur.GetTextLength() && memcmp(text, ur.GetText(), text.GetLength() * sizeof(TCHAR)) == 0)
{
if (CCrystalTextBuffer::UndoInsert(pSource, ptCursorPos, apparent_ptStartPos, apparent_ptEndPos, ur))
CPoint apparentEnd2 = apparent_ptEndPos;
apparentEnd2.x = static_cast<LONG>(m_aLines[apparentEnd2.y].FullLength());
text.Empty();
- GetTextWithoutEmptys(apparent_ptStartPos.y, apparent_ptStartPos.x, apparent_ptEndPos.y, apparentEnd2.x, text, CRLF_STYLE_AUTOMATIC, false);
+ GetTextWithoutEmptys(apparent_ptStartPos.y, apparent_ptStartPos.x, apparent_ptEndPos.y, apparentEnd2.x, text, CRLFSTYLE::AUTOMATIC, false);
if (static_cast<size_t>(text.GetLength()) == ur.GetTextLength() && memcmp(text, ur.GetText(), text.GetLength() * sizeof(TCHAR)) == 0)
{
if (CCrystalTextBuffer::UndoInsert(pSource, ptCursorPos, apparent_ptStartPos, apparentEnd2, ur))