Programming 版 (精华区)

发信人: SwordLea (飞刀李), 信区: Programming
标  题: Re: 怎样实现类似 UltraEdit的语法高亮
发信站: 哈工大紫丁香 (2004年03月26日13:52:06 星期五), 站内信件

没太看懂你的问题,是不是想自己实现CRichEdit的语法高亮显示啊?
我曾经找过一个SyntaxColorizer类,但在个别系统不太好用。     

// SyntaxColorizer.h: interface for the CSyntaxColorizer class.
//
// Version: 1.0.1
// Author:  Jeff Schering jeffschering@hotmail.com
// Date:    Feb 22, 2001
// Copyright 2001 by Jeff Schering
//
// Changes in 1.0.1: 
//      1. added UNICODE support
//////////////////////////////////////////////////////////////////////

#if 
!defined(AFX_SYNTAXCOLORIZER_H__5C50E421_E4AC_11D4_A61E_60A459C10100__INCLUDED_
)
#define AFX_SYNTAXCOLORIZER_H__5C50E421_E4AC_11D4_A61E_60A459C10100__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#define _UNICODE

#define CLR_STRING  RGB(55,0,200)
#define CLR_PLAIN   RGB(0,0,0)
#define CLR_COMMENT RGB(0,170,0)
#define CLR_KEYWORD RGB(0,0,255)
#define GRP_KEYWORD     0
#define TBLSIZE     65536
class CSyntaxColorizer  
{
public:
    CSyntaxColorizer();
    virtual ~CSyntaxColorizer();

//protected vars
protected:
    unsigned short *m_pTableZero, *m_pTableOne;
    unsigned short *m_pTableTwo,  *m_pTableThree;
    unsigned short *m_pTableFour, *m_pAllowable;

    enum Types
    {
        SKIP,
        DQSTART,    //Double Quotes start
        DQEND,      //Double Quotes end
        SQSTART,    //Single Quotes start
        SQEND,      //Single Quotes end
        CMSTART,    //Comment start (both single and multi line)
        SLEND,      //Single line comment end
        MLEND,      //Multi line comment end
        KEYWORD     //Keyword start
    } m_type;

    struct SKeyword 
    {
        TCHAR* keyword;
        int  keylen;
        CHARFORMAT cf;
        int group;
        SKeyword* pNext;
        SKeyword() { pNext = NULL; }
    };

    SKeyword*   m_pskKeyword;
    CHARFORMAT  m_cfComment;
    CHARFORMAT  m_cfString;
    CHARFORMAT  m_cfDefault;

//protected member functions
protected:
    void addKey(LPCTSTR Keyword, CHARFORMAT cf, int grp);
    void createTables();
    void deleteTables();
    void createDefaultKeywordList();
    void createDefaultCharFormat();
    void colorize(LPTSTR lpszBuf, CRichEditCtrl *pCtrl, long iOffset = 0);

//public member functions
public:
    void Colorize(long StartChar, long nEndChar, CRichEditCtrl *pCtrl);
    void Colorize(CHARRANGE cr, CRichEditCtrl *pCtrl);

    void GetCommentStyle(CHARFORMAT &cf) { cf = m_cfComment; };
    void GetStringStyle(CHARFORMAT &cf) { cf = m_cfString; };
    void GetGroupStyle(int grp, CHARFORMAT &cf);
    void GetDefaultStyle(CHARFORMAT &cf) { cf = m_cfDefault; };

    void SetCommentStyle(CHARFORMAT cf) { m_cfComment = cf; };
    void SetCommentColor(COLORREF cr);
    void SetStringStyle(CHARFORMAT cf) { m_cfString = cf; };
    void SetStringColor(COLORREF cr);
    void SetGroupStyle(int grp, CHARFORMAT cf);
    void SetGroupColor(int grp, COLORREF cr);
    void SetDefaultStyle(CHARFORMAT cf) { m_cfDefault = cf; };

    void AddKeyword(LPCTSTR Keyword, CHARFORMAT cf, int grp = 0); 
    void AddKeyword(LPCTSTR Keyword, COLORREF cr, int grp = 0);
    void ClearKeywordList();
    CString GetKeywordList();
    CString GetKeywordList(int grp);
};

#endif // 
!defined(AFX_SYNTAXCOLORIZER_H__5C50E421_E4AC_11D4_A61E_60A459C10100__INCLUDED_
)

// SyntaxColorizer.cpp: implementation of the CSyntaxColorizer class.
//
// Version: 1.0.1
// Author:  Jeff Schering jeffschering@hotmail.com
// Date:    Feb 22, 2001
// Copyright 2001 by Jeff Schering
//
// Changes in 1.0.1: 
//      1. added UNICODE support
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "SyntaxColorizer.h"

#define _UNICODE
#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;
}

CSyntaxColorizer::~CSyntaxColorizer()
{
    ClearKeywordList();
    deleteTables();
}

//////////////////////////////////////////////////////////////////////
// Member Functions
//////////////////////////////////////////////////////////////////////
void CSyntaxColorizer::createDefaultCharFormat()
{
    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.bCharSet = ANSI_CHARSET;
    m_cfDefault.bPitchAndFamily = FIXED_PITCH | FF_MODERN;
    m_cfDefault.yOffset = 0;
    m_cfDefault.crTextColor = CLR_PLAIN;
    _tcscpy(m_cfDefault.szFaceName,"Courier New");
    m_cfDefault.cbSize = sizeof(m_cfDefault);

    m_cfComment = m_cfDefault;
    m_cfString = m_cfDefault;
}

void CSyntaxColorizer::createDefaultKeywordList()
{
    LPTSTR sKeywords = _T("__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 = _T("#define,#elif,#else,#endif,#error,#ifdef,"
        "#ifndef,#import,#include,#line,#pragma,#undef");
    LPTSTR sPragmas = _T("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 short[TBLSIZE]; m_pTableOne   = new unsigned 
short[TBLSIZE];
    m_pTableTwo  = new unsigned short[TBLSIZE]; m_pTableThree = new unsigned 
short[TBLSIZE];
    m_pTableFour = new unsigned short[TBLSIZE]; m_pAllowable  = new unsigned 
short[TBLSIZE];

    memset(m_pTableZero,SKIP,TBLSIZE); memset(m_pTableOne,SKIP,TBLSIZE);
    memset(m_pTableTwo,SKIP,TBLSIZE);  memset(m_pTableThree,SKIP,TBLSIZE);
    memset(m_pTableFour,SKIP,TBLSIZE); memset(m_pAllowable,false,TBLSIZE);

    *(m_pTableZero + _T('"')) = DQSTART; *(m_pTableZero + _T('\''))  = 
SQSTART;
    *(m_pTableZero + _T('/')) = CMSTART; *(m_pTableOne + _T('"'))    = DQEND;
    *(m_pTableTwo + _T('\'')) = SQEND;   *(m_pTableThree + _T('\n')) = SLEND;
    *(m_pTableFour + _T('*')) = MLEND;

    *(m_pAllowable + _T('\n')) = true; *(m_pAllowable + _T('\r')) = true;
    *(m_pAllowable + _T('\t')) = true; *(m_pAllowable + _T('\0')) = true;
    *(m_pAllowable + _T(' '))  = true; *(m_pAllowable + _T(';'))  = true;
    *(m_pAllowable + _T('('))  = true; *(m_pAllowable + _T(')'))  = true;
    *(m_pAllowable + _T('{'))  = true; *(m_pAllowable + _T('}'))  = true;
    *(m_pAllowable + _T('['))  = true; *(m_pAllowable + _T(']'))  = true;
    *(m_pAllowable + _T('*'))  = 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 _tcstok will operate correctly
    LPTSTR keyword = new TCHAR[_tcslen(Keyword) + 1];
    _tcscpy(keyword,Keyword);

    CHARFORMAT cf = m_cfDefault;
    cf.crTextColor = cr;

    token = _tcstok(keyword,_T(","));
    while(token != NULL)
    {
        if(_tcsicmp(token,_T("rem")) == 0)
            *(m_pTableTwo + _T('\n')) = SLEND; //set single quote as comment 
start
        addKey(token,cf,grp);
        token = _tcstok(NULL,_T(","));
    }
    delete keyword;
}

void CSyntaxColorizer::AddKeyword(LPCTSTR Keyword, CHARFORMAT cf, int grp)
{
    LPTSTR token;

    //make a copy of Keyword so that _tcstok will operate correctly
    LPTSTR keyword = new TCHAR[_tcslen(Keyword) + 1];
    _tcscpy(keyword,Keyword);

    token = _tcstok(keyword,_T(","));
    while(token != NULL)
    {
        if(_tcsicmp(token,_T("rem")) == 0)
            *(m_pTableTwo + _T('\n')) = SLEND; //set single quote as comment 
start
        addKey(token,cf,grp);
        token = _tcstok(NULL,_T(","));
    }
    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[_tcslen(Keyword)+1];
    _tcscpy(pskNewKey->keyword,Keyword);

    pskNewKey->keylen = _tcslen(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(_tcscmp(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(_tcscmp(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 && _tcscmp(curr->keyword,Keyword) < 0)
            {
                prev = curr;
                curr = curr->pNext;
            }
            if(curr != NULL && _tcscmp(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;

    while(m_pskKeyword != NULL)
    {
        *(m_pTableZero + m_pskKeyword->keyword[0]) = SKIP;
        if(_tcsicmp(m_pskKeyword->keyword,_T("rem")) == 0)
            *(m_pTableTwo + _T('\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 += _T(",");
        pTemp = pTemp->pNext;
    }
    sList.TrimRight(_T(','));
    return sList;
}

CString CSyntaxColorizer::GetKeywordList(int grp)
{
    CString sList;
    SKeyword* pTemp = m_pskKeyword;

    while(pTemp != NULL)
    {
        if(pTemp->group == grp)
        {
            sList += pTemp->keyword;
            sList += _T(",");
        }
        pTemp = pTemp->pNext;
    }
    sList.TrimRight(_T(','));
    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)
{
    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;
}

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
    CHARFORMAT cf;
    LPTSTR lpszTemp;
    long iStart;
    long x = 0;
    SKeyword* pskTemp = m_pskKeyword;
    unsigned short* 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] == _T('/'))
            {
                pTable = m_pTableThree;
                iStart = iOffset + x;
                x++;
            }
            else if(lpszBuf[x+1] == _T('*'))
            {
                pTable = m_pTableFour;
                iStart = iOffset + x;
                x++;
            }
            else if(lpszBuf[x] == _T('\''))
            {
                pTable = m_pTableThree;
                iStart = iOffset + x;
                x++;
            }

            break;
        case MLEND:
            if(lpszBuf[x+1] == _T('/'))
            {
                x++;
                pTable = m_pTableZero;
                pCtrl->SetSel(iStart,iOffset + x+1);
                pCtrl->SetSelectionCharFormat(m_cfComment);
            }
            break;
        case SLEND:
            if(lpszBuf[x-2] != _T('\\')) // 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] == _T('\\') && lpszBuf[x+1] == _T('\''))
                break;
            pTable = m_pTableZero;
            pCtrl->SetSel(iStart,iOffset + x+1);
            pCtrl->SetSelectionCharFormat(m_cfString);
            break;
        case KEYWORD:
            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(_tcsicmp(pskTemp->keyword,_T("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);
    }
}


 【
 在
 traceroute ( 懵懂书童∷苏格拉底最后的门徒) 的大作中提到: 】: 【 以下文字转载自 
C_and_CPP 讨论区 】 : 【 原文由 traceroute 所发表 】
: 请问怎样设置UltraEdit,使编辑时文本采用C语言形式?
: 另外如何设置不同类型变量的颜色?setcolour好像不行


--
    穿好一双鞋,以后用什么武器都不用再担心鞋子的问题

※ 来源:·哈工大紫丁香 bbs.hit.edu.cn·[FROM: 202.118.246.241]
※ 修改:·SwordLea 於 03月26日13:52:32 修改本文·[FROM: 202.118.246.241]
[百宝箱] [返回首页] [上级目录] [根目录] [返回顶部] [刷新] [返回]
Powered by KBS BBS 2.0 (http://dev.kcn.cn)
页面执行时间:211.354毫秒