📄 bcgpoutlineparser.cpp
字号:
m_strOut.Empty ();
CList <Lexeme, Lexeme&> lstStack;
Lexeme lexemStackTop (0, LT_Eps, 0, 0);
lstStack.AddTail (lexemStackTop);
int nOffset = nStartOffset;
while (nOffset <= nEndOffset)
{
// Get next lexem:
Lexeme lexemNext = GetNext (strBuffer, nOffset, nEndOffset);
Lexeme lexemTop = lstStack.GetTail ();
if (lexemNext.m_nType == LT_EndOfText)
{
break;
}
// Parser logic:
switch (lexemNext.m_nType)
{
case LT_BlockStart:
lstStack.AddTail (lexemNext);
break;
case LT_BlockEnd:
if (lexemTop.m_nType == LT_BlockStart &&
lexemTop.m_nBlockType == lexemNext.m_nBlockType)
{
// Push Block:
lstStack.RemoveTail ();
Lexeme lexemRes (lexemTop.m_nBlockType, LT_CompleteBlock, lexemTop.m_nStart, lexemNext.m_nEnd);
PushResult (lexemRes, lstResults);
}
else
{
lstStack.AddTail (lexemNext);
}
break;
case LT_CompleteBlock:
{
// Push Comment:
PushResult (lexemNext, lstResults);
}
break;
}
}
// Finish parsing:
while (!lstStack.IsEmpty ())
{
Lexeme lexem = lstStack.RemoveTail ();
PushResult (lexem, lstResults);
}
}
//************************************************************************************
static void CalcMinMaxBounds (const CObList& lst, int& nMin, int& nMax)
{
for (POSITION pos = lst.GetHeadPosition (); pos != NULL; )
{
CBCGPOutlineBaseNode* pNode = (CBCGPOutlineBaseNode*) lst.GetNext (pos);
ASSERT_VALID (pNode);
if (pNode->m_nStart < nMin)
{
nMin = pNode->m_nStart;
}
if (pNode->m_nEnd > nMax)
{
nMax = pNode->m_nEnd;
}
}
}
//************************************************************************************
void CBCGPOutlineParser::UpdateOutlining (CString& strBuffer, int nOffsetFrom, int nCharsCount,
CBCGPOutlineNode* pOutlineNode, BCGP_EDIT_OUTLINE_CHANGES& changes)
{
ASSERT_VALID (this);
ASSERT (nOffsetFrom >= 0);
ASSERT (nCharsCount >= 0);
ASSERT (nOffsetFrom + nCharsCount <= strBuffer.GetLength ());
ASSERT_VALID (pOutlineNode);
int nStartOffset = nOffsetFrom;
int nEndOffset = nOffsetFrom + nCharsCount - 1;
CBCGPOutlineNode* pChangedNode = GetRangeToReparse (pOutlineNode, nStartOffset, nEndOffset);
nStartOffset = max (0, nStartOffset);
nEndOffset = min (strBuffer.GetLength () - 1, nEndOffset);
if (nStartOffset > nEndOffset)
{
return; // no reparse needed
}
changes.m_nStartOffset = min (nStartOffset, changes.m_nStartOffset);
changes.m_nEndOffset = max (nEndOffset, changes.m_nEndOffset);
// --------------------------------------------------------------
// 1) Parse text and find new blocks and part of blocks (markers)
// --------------------------------------------------------------
CObList lstBlocks;
DoParse (strBuffer, nStartOffset, nEndOffset, lstBlocks);
// ----------------------------------------------------------
// Reparse text once more
// if parser found blocks that are greater then parsing range
// ----------------------------------------------------------
int nMin = nStartOffset, nMax = nEndOffset;
CalcMinMaxBounds (lstBlocks, nMin, nMax);
if (nMin < nStartOffset || nMax > nEndOffset)
{
nStartOffset = min (nMin, nStartOffset);
nEndOffset = max (nMax, nEndOffset);
pChangedNode = GetRangeToReparse (pOutlineNode, nStartOffset, nEndOffset);
nStartOffset = max (0, nStartOffset);
nEndOffset = min (strBuffer.GetLength () - 1, nEndOffset);
changes.m_nStartOffset = min (nStartOffset, changes.m_nStartOffset);
changes.m_nEndOffset = max (nEndOffset, changes.m_nEndOffset);
while (!lstBlocks.IsEmpty ())
{
delete lstBlocks.RemoveTail ();
}
DoParse (strBuffer, nStartOffset, nEndOffset, lstBlocks);
}
// Update name offsets, start offsets and end offsets:
DoUpdateOffsets (strBuffer, nStartOffset, nEndOffset, lstBlocks);
// ------------------------
// Reconstruct outline tree
// ------------------------
// 2) Del old blocks
pOutlineNode->DeleteBlocksInRange (nStartOffset, nEndOffset, changes); // do not remove user blocks
for (POSITION pos = lstBlocks.GetHeadPosition (); pos != NULL; )
{
POSITION posSave = pos;
CBCGPOutlineNode* pNode = (CBCGPOutlineNode*) lstBlocks.GetNext (pos);
ASSERT_VALID (pNode);
BlockType* pBlockType = m_arrBlockTypes [pNode->m_nBlockType];
if (pBlockType != NULL && !pBlockType->m_bIgnore)
{
if ((pNode->m_dwFlags & g_dwOBFComplete) != 0)
{
// 3) Add new blocks
AddNode (pNode, pOutlineNode, changes);
}
else if ((pNode->m_dwFlags & g_dwOBFLeft) != 0 ||
(pNode->m_dwFlags & g_dwOBFRight) != 0)
{
// it's possible that pChangedNode was removed from outline tree
POSITION posChangedNode = changes.m_lstRemoved.Find (pChangedNode);
if (posChangedNode != NULL)
{
if ((pNode->m_dwFlags & g_dwOBFLeft) != 0)
{
pChangedNode = pOutlineNode->FindCollapsedBlock (pNode->m_nStart);
}
else if ((pNode->m_dwFlags & g_dwOBFRight) != 0)
{
pChangedNode = pOutlineNode->FindCollapsedBlock (pNode->m_nEnd);
}
if (pChangedNode == NULL)
{
pChangedNode = pOutlineNode;
}
}
ASSERT_VALID (pChangedNode);
// 4) Reconstruct outline tree (add new markers)
if (!AddMarker (pNode, pChangedNode, changes))
{
lstBlocks.RemoveAt (posSave);
delete pNode; // to prevent memory leak
}
}
}
else
{
// delete temporary blocks:
lstBlocks.RemoveAt (posSave);
delete pNode;
}
}
}
//************************************************************************************
CBCGPOutlineNode* CBCGPOutlineParser::GetRangeToReparse (CBCGPOutlineNode* pOutlineNode,
int& nStartOffset, int& nEndOffset) const
{
ASSERT_VALID (pOutlineNode);
// --------------------------------------
// Enlarge to start close string lengths:
// --------------------------------------
int nMaxBlockOpenStrLen = 1;
int nMaxBlockCloseStrLen = 1;
for (int i = 0; i <= m_arrBlockTypes.GetUpperBound (); i++)
{
BlockType* pBlockType = m_arrBlockTypes [i];
ASSERT (pBlockType != NULL);
if (pBlockType->m_strOpen.GetLength () > nMaxBlockOpenStrLen)
{
nMaxBlockOpenStrLen = pBlockType->m_strOpen.GetLength ();
}
if (pBlockType->m_strClose.GetLength () > nMaxBlockCloseStrLen)
{
nMaxBlockCloseStrLen = pBlockType->m_strClose.GetLength ();
}
}
nStartOffset -= nMaxBlockOpenStrLen - 1;
nEndOffset += nMaxBlockCloseStrLen - 1;
// ----------------------
// Enlarge to block size:
// ----------------------
CBCGPOutlineNode* pParentNode = pOutlineNode;
CBCGPOutlineNode* pNode = NULL;
POSITION pos = pParentNode->GetNodes ()->GetHeadPosition ();
// By offset:
if (nStartOffset > nEndOffset) // no range - use nStartOffset:
{
pParentNode = pOutlineNode->GetInnermostBlock (nStartOffset);
// Ensure the block it's not user block:
while (pParentNode != NULL && pParentNode != pOutlineNode &&
pParentNode->m_nBlockType < 0)
{
pParentNode = pParentNode->GetParentNode ();
}
if (pParentNode != NULL && pParentNode != pOutlineNode)
{
nStartOffset = pParentNode->m_nStart - pParentNode->m_nNameOffset;
nEndOffset = pParentNode->m_nEnd;
return pParentNode;
}
else
{
return pOutlineNode;
}
}
// By range:
while (pos != NULL)
{
pNode = (CBCGPOutlineNode*) pParentNode->GetNodes ()->GetNext (pos);
ASSERT_VALID (pNode);
CBCGPOutlineBaseNode::CBCGPEditOutlineRange range =
pNode->IsInRangeByOffset (nStartOffset, nEndOffset);
if (range == FULL_IN_RANGE ||
(pNode->m_nStart - pNode->m_nNameOffset >= nStartOffset &&
pNode->m_nStart - pNode->m_nNameOffset <= nEndOffset))
{
// full in range
// or left side in range - enlarge nEndOffset:
nStartOffset = min (nStartOffset, pNode->m_nStart - pNode->m_nNameOffset);
nEndOffset = max (nEndOffset, pNode->m_nEnd);
}
else if (range == PARTIAL_IN_RANGE)
{
if (pNode->m_nEnd >= nStartOffset &&
pNode->m_nEnd <= nEndOffset)
{
// right side in range - enlarge nStartOffset:
nStartOffset = min (nStartOffset, pNode->m_nStart - pNode->m_nNameOffset);
nEndOffset = max (nEndOffset, pNode->m_nEnd);
}
else
{
// middle in range - level down:
pParentNode = pNode;
pNode = NULL;
pos = pParentNode->GetNodes ()->GetHeadPosition ();
const BlockType* pBlockType = GetBlockType (pParentNode->m_nBlockType);
if (pBlockType == NULL || !pBlockType->m_bAllowNestedBlocks)
{
nStartOffset = min (nStartOffset, pParentNode->m_nStart - pParentNode->m_nNameOffset);
nEndOffset = max (nEndOffset, pParentNode->m_nEnd);
}
}
}
}
if (pParentNode != NULL)
{
nStartOffset = min (nStartOffset, pParentNode->m_nStart - pParentNode->m_nNameOffset);
nEndOffset = max (nEndOffset, pParentNode->m_nEnd);
}
return pParentNode;
}
//************************************************************************************
void CBCGPOutlineParser::DoUpdateOffsets (const CString& strBuffer,
const int nStartOffset, const int nEndOffset,
CObList& lstBlocks)
{
// Update name offsets, start offsets and end offsets:
CBCGPOutlineNode* pPreviousNode = NULL;
CObList lstIgnoreBlocks;
for (POSITION pos = lstBlocks.GetHeadPosition (); pos != NULL; )
{
CBCGPOutlineNode* pNode = (CBCGPOutlineNode*) lstBlocks.GetNext (pos);
ASSERT_VALID (pNode);
const BlockType* pBlockType = GetBlockType (pNode->m_nBlockType);
if (pBlockType != NULL && !pBlockType->m_bIgnore)
{
// --------------------------------------
// Update name offsets and start offsets:
// --------------------------------------
CString strName;
int nSearchTo = nStartOffset;
if (pPreviousNode != NULL &&
pPreviousNode->m_nEnd < pNode->m_nStart &&
pPreviousNode->m_nEnd > nStartOffset)
{
nSearchTo = pPreviousNode->m_nEnd;
}
pNode->m_nNameOffset = GetNameOffset (strBuffer, pNode->m_nStart, nSearchTo,
pBlockType, lstIgnoreBlocks, strName);
int nNewStart = GetStartOffset (strBuffer, pNode->m_nStart, pNode->m_nStart - pNode->m_nNameOffset, lstIgnoreBlocks);
ASSERT (nNewStart >= nSearchTo);
int nDelta = nNewStart - pNode->m_nStart;
pNode->m_nNameOffset += nDelta;
pNode->m_nStart = nNewStart;
// strName = strName.Left (strName.GetLength () + nDelta);
// pNode->m_strName = strName;
// -------------------
// Update end offsets:
// -------------------
nSearchTo = nEndOffset;
if (pos != NULL)
{
CBCGPOutlineNode* pNextNode = (CBCGPOutlineNode*) lstBlocks.GetAt (pos);
ASSERT_VALID (pNextNode);
if (pNextNode->m_nStart > pNode->m_nEnd &&
pNextNode->m_nStart < nEndOffset)
{
nSearchTo = pNextNode->m_nStart;
}
}
int nNewEnd = GetEndOffset (strBuffer, pNode->m_nEnd, nSearchTo);
ASSERT (nNewEnd <= nSearchTo);
pNode->m_nEnd = nNewEnd;
pPreviousNode = pNode;
lstIgnoreBlocks.AddTail (pNode);
}
else
{
lstIgnoreBlocks.AddTail (pNode);
}
}
}
//************************************************************************************
static BOOL IsInRange(CObList& lstIgnore, int nStart, int nEnd)
{
for (POSITION pos = lstIgnore.GetTailPosition (); pos != NULL; )
{
CBCGPOutlineNode* pPrevNode = (CBCGPOutlineNode*) lstIgnore.GetPrev (pos);
ASSERT_VALID (pPrevNode);
if (pPrevNode->IsInRangeByOffset (nStart, nEnd) != NOT_IN_RANGE)
{
return TRUE;
}
}
return FALSE;
}
//************************************************************************************
int CBCGPOutlineParser::GetNameOffset (const CString& strIn, int nStartFrom, int nSearchTo,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -