Files
FC1/Editor/Controls/SyntaxColorizer.cpp
romkazvo 34d6c5d489 123
2023-08-07 19:29:24 +08:00

572 lines
14 KiB
C++

// SyntaxColorizer.cpp: implementation of the CSyntaxColorizer class.
//
// Version: 1.0.0
// Author: Jeff Schering jeffschering@hotmail.com
// Date: Jan 2001
// Copyright 2001 by Jeff Schering
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "SyntaxColorizer.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CSyntaxColorizer::CSyntaxColorizer()
{
createDefaultCharFormat();
SetCommentColor(CLR_COMMENT);
SetStringColor(CLR_STRING);
createTables();
m_pskKeyword = NULL;
createDefaultKeywordList();
}
CSyntaxColorizer::~CSyntaxColorizer()
{
ClearKeywordList();
deleteTables();
}
//////////////////////////////////////////////////////////////////////
// Member Functions
//////////////////////////////////////////////////////////////////////
void CSyntaxColorizer::createDefaultCharFormat()
{
ZeroStruct( m_cfDefault );
m_cfDefault.dwMask = CFM_CHARSET | CFM_FACE | CFM_SIZE | CFM_OFFSET | CFM_COLOR;
m_cfDefault.dwMask ^= CFM_ITALIC ^ CFM_BOLD ^ CFM_STRIKEOUT ^ CFM_UNDERLINE;
m_cfDefault.dwEffects = 0;
//m_cfDefault.yHeight = 200; //10pts * 20 twips/point = 200 twips
m_cfDefault.yHeight = 180; //10pts * 20 twips/point = 200 twips
m_cfDefault.bCharSet = ANSI_CHARSET;
m_cfDefault.bPitchAndFamily = FIXED_PITCH | FF_MODERN;
m_cfDefault.yOffset = 0;
m_cfDefault.crTextColor = CLR_PLAIN;
strcpy(m_cfDefault.szFaceName,"Courier New");
m_cfDefault.cbSize = sizeof(m_cfDefault);
m_cfComment = m_cfDefault;
m_cfString = m_cfDefault;
}
void CSyntaxColorizer::createDefaultKeywordList()
{
LPTSTR sKeywords = "__asm,else,main,struct,__assume,enum,"
"__multiple_inheritance,switch,auto,__except,__single_inheritance,"
"template,__based,explicit,__virtual_inheritance,this,bool,extern,"
"mutable,thread,break,false,naked,throw,case,__fastcall,namespace,"
"true,catch,__finally,new,try,__cdecl,float,noreturn,__try,char,for,"
"operator,typedef,class,friend,private,typeid,const,goto,protected,"
"typename,const_cast,if,public,union,continue,inline,register,"
"unsigned,__declspec,__inline,reinterpret_cast,using,declaration,"
"directive,default,int,return,uuid,delete,__int8,short,"
"__uuidof,dllexport,__int16,signed,virtual,dllimport,__int32,sizeof,"
"void,do,__int64,static,volatile,double,__leave,static_cast,wmain,"
"dynamic_cast,long,__stdcall,while";
LPTSTR sDirectives = "#define,#elif,#else,#endif,#error,#ifdef,"
"#ifndef,#import,#include,#line,#pragma,#undef";
LPTSTR sPragmas = "alloc_text,comment,init_seg1,optimize,auto_inline,"
"component,inline_depth,pack,bss_seg,data_seg,"
"inline_recursion,pointers_to_members1,check_stack,"
"function,intrinsic,setlocale,code_seg,hdrstop,message,"
"vtordisp1,const_seg,include_alias,once,warning";
AddKeyword(sKeywords,CLR_KEYWORD,GRP_KEYWORD);
AddKeyword(sDirectives,CLR_KEYWORD,GRP_KEYWORD);
AddKeyword(sPragmas,CLR_KEYWORD,GRP_KEYWORD);
}
void CSyntaxColorizer::createTables()
{
m_pTableZero = new unsigned char[256]; m_pTableOne = new unsigned char[256];
m_pTableTwo = new unsigned char[256]; m_pTableThree = new unsigned char[256];
m_pTableFour = new unsigned char[256]; m_pAllowable = new unsigned char[256];
memset(m_pTableZero,SKIP,256); memset(m_pTableOne,SKIP,256);
memset(m_pTableTwo,SKIP,256); memset(m_pTableThree,SKIP,256);
memset(m_pTableFour,SKIP,256); memset(m_pAllowable,false,256);
*(m_pTableZero + '"') = DQSTART; *(m_pTableZero + '\'') = SQSTART;
*(m_pTableZero + '/') = CMSTART; *(m_pTableOne + '"') = DQEND;
*(m_pTableTwo + '\'') = SQEND; *(m_pTableThree + '\n') = SLEND; *(m_pTableThree + '\r') = SLEND;
*(m_pTableFour + '*') = MLEND;
*(m_pAllowable + '\n') = true; *(m_pAllowable + '\r') = true;
*(m_pAllowable + '\t') = true; *(m_pAllowable + '\0') = true;
*(m_pAllowable + ' ') = true; *(m_pAllowable + ';') = true;
*(m_pAllowable + '(') = true; *(m_pAllowable + ')') = true;
*(m_pAllowable + '{') = true; *(m_pAllowable + '}') = true;
*(m_pAllowable + '[') = true; *(m_pAllowable + ']') = true;
*(m_pAllowable + '*') = true;
}
void CSyntaxColorizer::deleteTables()
{
delete m_pTableZero; delete m_pTableOne; delete m_pTableTwo;
delete m_pTableThree; delete m_pTableFour; delete m_pAllowable;
}
void CSyntaxColorizer::AddKeyword(LPCTSTR Keyword, COLORREF cr, int grp)
{
LPTSTR token;
//make a copy of Keyword so that strtok will operate correctly
LPTSTR keyword = new TCHAR[strlen(Keyword) + 1];
strcpy(keyword,Keyword);
CHARFORMAT cf = m_cfDefault;
cf.crTextColor = cr;
token = strtok(keyword,",");
while(token != NULL)
{
if(_stricmp(token,"rem") == 0)
*(m_pTableTwo + '\n') = SLEND; //set single quote as comment start
addKey(token,cf,grp);
token = strtok(NULL,",");
}
delete keyword;
}
void CSyntaxColorizer::AddKeyword(LPCTSTR Keyword, CHARFORMAT cf, int grp)
{
LPTSTR token;
//make a copy of Keyword so that strtok will operate correctly
LPTSTR keyword = new TCHAR[strlen(Keyword) + 1];
strcpy(keyword,Keyword);
token = strtok(keyword,",");
while(token != NULL)
{
if(_stricmp(token,"rem") == 0)
*(m_pTableTwo + '\n') = SLEND; //set single quote as comment start
addKey(token,cf,grp);
token = strtok(NULL,",");
}
delete keyword;
}
void CSyntaxColorizer::addKey(LPCTSTR Keyword, CHARFORMAT cf, int grp) //add in ascending order
{
SKeyword* pskNewKey = new SKeyword;
SKeyword* prev,*curr;
//the string pointed to by Keyword is only temporary, so make a copy
// of it for our list
pskNewKey->keyword = new TCHAR[strlen(Keyword)+1];
strcpy(pskNewKey->keyword,Keyword);
m_keywords[pskNewKey->keyword] = pskNewKey;
pskNewKey->keylen = strlen(Keyword);
pskNewKey->cf = cf;
pskNewKey->group = grp;
pskNewKey->pNext = NULL;
*(m_pTableZero + pskNewKey->keyword[0]) = KEYWORD;
//if list is empty, add first node
if(m_pskKeyword == NULL)
m_pskKeyword = pskNewKey;
else
{
//check to see if new node goes before first node
if(strcmp(Keyword,m_pskKeyword->keyword) < 0)
{
pskNewKey->pNext = m_pskKeyword;
m_pskKeyword = pskNewKey;
}
//check to see if new keyword already exists at the first node
else if(strcmp(Keyword,m_pskKeyword->keyword) == 0)
{
//the keyword exists, so replace the existing with the new
pskNewKey->pNext = m_pskKeyword->pNext;
delete []m_pskKeyword->keyword; delete m_pskKeyword;
m_pskKeyword = pskNewKey;
}
else
{
prev = m_pskKeyword;
curr = m_pskKeyword->pNext;
while(curr != NULL && strcmp(curr->keyword,Keyword) < 0)
{
prev = curr;
curr = curr->pNext;
}
if(curr != NULL && strcmp(curr->keyword,Keyword) == 0)
{
//the keyword exists, so replace the existing with the new
prev->pNext = pskNewKey;
pskNewKey->pNext = curr->pNext;
delete []curr->keyword; delete curr;
}
else
{
pskNewKey->pNext = curr;
prev->pNext = pskNewKey;
}
}
}
}
void CSyntaxColorizer::ClearKeywordList()
{
SKeyword* pTemp = m_pskKeyword;
m_keywords.clear();
while(m_pskKeyword != NULL)
{
*(m_pTableZero + m_pskKeyword->keyword[0]) = SKIP;
if(_stricmp(m_pskKeyword->keyword,"rem") == 0)
*(m_pTableTwo + '\n') = SKIP;
pTemp = m_pskKeyword->pNext;
delete []m_pskKeyword->keyword;
delete m_pskKeyword;
m_pskKeyword = pTemp;
}
}
CString CSyntaxColorizer::GetKeywordList()
{
CString sList;
SKeyword* pTemp = m_pskKeyword;
while(pTemp != NULL)
{
sList += pTemp->keyword;
sList += ",";
pTemp = pTemp->pNext;
}
sList.TrimRight(',');
return sList;
}
CString CSyntaxColorizer::GetKeywordList(int grp)
{
CString sList;
SKeyword* pTemp = m_pskKeyword;
while(pTemp != NULL)
{
if(pTemp->group == grp)
{
sList += pTemp->keyword;
sList += ",";
}
pTemp = pTemp->pNext;
}
sList.TrimRight(',');
return sList;
}
void CSyntaxColorizer::SetCommentColor(COLORREF cr)
{
CHARFORMAT cf = m_cfComment;
cf.dwMask = CFM_COLOR;
cf.crTextColor = cr;
SetCommentStyle(cf);
}
void CSyntaxColorizer::SetStringColor(COLORREF cr)
{
CHARFORMAT cf = m_cfString;
cf.dwMask = CFM_COLOR;
cf.crTextColor = cr;
SetStringStyle(cf);
}
void CSyntaxColorizer::SetGroupStyle(int grp, CHARFORMAT cf)
{
SKeyword* pTemp = m_pskKeyword;
while(pTemp != NULL)
{
if(pTemp->group == grp)
{
pTemp->cf = cf;
}
pTemp = pTemp->pNext;
}
}
void CSyntaxColorizer::GetGroupStyle(int grp, CHARFORMAT &cf)
{
SKeyword* pTemp = m_pskKeyword;
while(pTemp != NULL)
{
if(pTemp->group == grp)
{
cf = pTemp->cf;
pTemp = NULL;
}
else
{
pTemp = pTemp->pNext;
//if grp is not found, return default style
if(pTemp == NULL) cf = m_cfDefault;
}
}
}
void CSyntaxColorizer::SetGroupColor(int grp, COLORREF cr)
{
CHARFORMAT cf;
GetGroupStyle(grp,cf);
cf.dwMask = CFM_COLOR;
cf.crTextColor = cr;
SetGroupStyle(grp,cf);
}
void CSyntaxColorizer::Colorize(CHARRANGE cr, CRichEditCtrl *pCtrl)
{
pCtrl->LockWindowUpdate();
long nTextLength = 0;
if(cr.cpMin == 0 && cr.cpMax == -1) //send entire text of rich edit box
{
//set up the buffer to hold the text from the rich edit box
nTextLength = pCtrl->GetTextLength();
//if there is alot of text in the Rich Edit (>64K) then GetWindowText doesn't
//work. We have to select all of the text, and then use GetSelText
pCtrl->SetSel(0,-1);
}
else
{
//set up the buffer to hold the text
nTextLength = cr.cpMax - cr.cpMin + 1;//add 1 because zero-based array
//get the text
pCtrl->SetSel(cr.cpMin,cr.cpMax);
}
LPTSTR lpszBuf = new TCHAR[nTextLength+1];
pCtrl->GetSelText(lpszBuf);
pCtrl->SetSelectionCharFormat(m_cfDefault);
colorize(lpszBuf,pCtrl,cr.cpMin);
delete lpszBuf;
pCtrl->UnlockWindowUpdate();
}
void CSyntaxColorizer::Colorize(long nStartChar, long nEndChar, CRichEditCtrl *pCtrl)
{
long nTextLength = 0;
if(nStartChar == 0 && nEndChar == -1) //send entire text of rich edit box
{
nTextLength = pCtrl->GetTextLength();
//if there is alot of text in the Rich Edit (>64K) then GetWindowText doesn't
//work. We have to select all of the text, and then use GetSelText
pCtrl->SetSel(0,-1);
}
else
{
//set up the text buffer; add 1 because zero-based array
nTextLength = nEndChar - nStartChar + 1;
pCtrl->SetSel(nStartChar,nEndChar);
}
LPTSTR lpszBuf = new TCHAR[nTextLength+1];
pCtrl->GetSelText(lpszBuf);
pCtrl->SetSelectionCharFormat(m_cfDefault);
colorize(lpszBuf,pCtrl,nStartChar);
delete lpszBuf;
}
void CSyntaxColorizer::colorize(LPTSTR lpszBuf, CRichEditCtrl *pCtrl, long iOffset /*=0*/)
{
//setup some vars
char sWord[4096];
CHARFORMAT cf;
LPTSTR lpszTemp;
long iStart;
long x = 0;
SKeyword* pskTemp = m_pskKeyword;
unsigned char* pTable = m_pTableZero;
//do the work
while(lpszBuf[x])
{
switch(pTable[lpszBuf[x]])
{
case DQSTART:
pTable = m_pTableOne;
iStart = iOffset + x;
break;
case SQSTART:
pTable = m_pTableTwo;
iStart = iOffset + x;
break;
case CMSTART:
if(lpszBuf[x+1] == '/')
{
pTable = m_pTableThree;
iStart = iOffset + x;
x++;
}
else if(lpszBuf[x+1] == '*')
{
pTable = m_pTableFour;
iStart = iOffset + x;
x++;
}
else if(lpszBuf[x] == '\'')
{
pTable = m_pTableThree;
iStart = iOffset + x;
x++;
}
break;
case MLEND:
if(lpszBuf[x+1] == '/')
{
x++;
pTable = m_pTableZero;
pCtrl->SetSel(iStart,iOffset + x+1);
pCtrl->SetSelectionCharFormat(m_cfComment);
}
break;
case SLEND:
if(lpszBuf[x-2] != '\\') // line continuation character
{
pTable = m_pTableZero;
pCtrl->SetSel(iStart,iOffset + x+1);
pCtrl->SetSelectionCharFormat(m_cfComment);
}
break;
case DQEND:
pTable = m_pTableZero;
pCtrl->SetSel(iStart,iOffset + x+1);
pCtrl->SetSelectionCharFormat(m_cfString);
break;
case SQEND:
if(lpszBuf[x-1] == '\\' && lpszBuf[x+1] == '\'')
break;
pTable = m_pTableZero;
pCtrl->SetSel(iStart,iOffset + x+1);
pCtrl->SetSelectionCharFormat(m_cfString);
break;
case KEYWORD:
// Extract whole word.
lpszTemp = lpszBuf+x;
{
if (x > 0 && !m_pAllowable[lpszBuf[x-1]])
break;
int i = 0;
while (!m_pAllowable[lpszTemp[i]])
{
sWord[i] = lpszTemp[i];
i++;
}
if (i > 0)
{
sWord[i] = 0;
// Word extracted.
// Find keyword.
Keywords::iterator it = m_keywords.find( sWord );
if (it != m_keywords.end())
{
int iStart = iOffset + x;
pskTemp = it->second;
x += pskTemp->keylen;
pCtrl->SetSel(iStart,iOffset + x);
pCtrl->SetSelectionCharFormat(pskTemp->cf);
}
}
}
/*
lpszTemp = lpszBuf+x;
while(pskTemp != NULL)
{
if(pskTemp->keyword[0] == lpszTemp[0])
{
int x1=0,y1=0;iStart = iOffset + x;
while(pskTemp->keyword[x1])
{
y1 += lpszTemp[x1] ^ pskTemp->keyword[x1];
x1++;
}
if(y1 == 0 && (*(m_pAllowable + (lpszBuf[x-1])) &&
*(m_pAllowable + (lpszBuf[x+pskTemp->keylen]))))
{
if(_stricmp(pskTemp->keyword,"rem") == 0)
{
pTable = m_pTableThree;
}
else
{
x += pskTemp->keylen;
pCtrl->SetSel(iStart,iOffset + x);
pCtrl->SetSelectionCharFormat(pskTemp->cf);
}
}
}
pskTemp = pskTemp->pNext;
}
*/
pskTemp = m_pskKeyword;
break;
case SKIP:;
}
x++;
}
//sometimes we get to the end of the file before the end of the string
//or comment, so we deal with that situation here
if(pTable == m_pTableOne)
{
cf = m_cfString;
pCtrl->SetSel(iStart,iOffset + x+1);
pCtrl->SetSelectionCharFormat(cf);
}
else if(pTable == m_pTableTwo)
{
cf = m_cfString;
pCtrl->SetSel(iStart,iOffset + x+1);
pCtrl->SetSelectionCharFormat(cf);
}
else if(pTable == m_pTableThree)
{
cf = m_cfComment;
pCtrl->SetSel(iStart,iOffset + x+1);
pCtrl->SetSelectionCharFormat(cf);
}
else if(pTable == m_pTableFour)
{
cf = m_cfComment;
pCtrl->SetSel(iStart,iOffset + x+1);
pCtrl->SetSelectionCharFormat(cf);
}
}