Click here to Skip to main content
Click here to Skip to main content

Tagged as

Crystal Edit - syntax coloring text editor

, 30 Jan 2000
Rate this:
Please Sign up or sign in to vote.
A set of classes that provide an expandable framework for the syntax coloring text editor.
  • Download demo project - 116 Kb
  • Download source files - 55 Kb
  • Sample Image - crysedit.gif

    <!-- Article Starts --> The package consists of three main classes:
    • CCrystalTextBuffer class is responsible for storing lines, loading and saving text to a file. To simplify Undo/Redo command implementations, every editing operation is split into a sequence of 'insert text' and 'delete text' actions. Accordingly, CView-derived classes are only intended to react only on this primitive operations.

    • CCrystalTextView class is the framework for text viewing window. It derives from CView, and it provides text painting code, overridable functions for syntax highlighting, different kinds of text selections, cursor movements, Find common dialog etc. However, it's not allowed to perform any changes to the text.

      CCrystalTextView-derived views are usually used with CCrystalTextBuffer object. Once such a view is connected to the CCrystalTextBuffer object, it is capable to track changes made to the text. (Obviously, any number of views can be connected to a single CCrystalTextBuffer object at the same time. This is useful, when we need to use the editor in the dynamic splitter as shown on the figure above).

    • CCrystalEditView class is derived from CCrystalTextView class. Unlike its ansector, which is only able to display a text and update the view when it is needed, it has functions to perform all sorts of editing, including drag-and-drop and Replace dialog. Note, that the view does not make the changes in the text directly, instead, it transforms the command into a sequence of primitive operations described above, and delegates them to the CCrystalTextBuffer object. Once the changes are made, the CCrystalTextBuffer object updates all views connected to it.

    Usually, CCrystalTextBuffer exists within the CDocument object. You must provide a way to connect views to the object (the best place for it is CView::OnInitialUpdate handler). In most cases, you will also need to override SetModified method to keep 'dirty' flag of the document up-to-date. Consider the following sample code:
    class CSampleDoc : public CDocument
    {
    // code omitted
    
    // Attributes
    public:
        class CSampleTextBuffer : public CCrystalTextBuffer
        {
        private:
            CSampleDoc *m_pOwnerDoc;
        public:
            CSampleTextBuffer(CSampleDoc *pDoc) { m_pOwnerDoc = pDoc; };
    
            virtual void SetModified(BOOL bModified = TRUE)
                { m_pOwnerDoc->SetModifiedFlag(bModified); };
        };
    
        CSampleTextBuffer m_xTextBuffer;
    };

    CCrystalTextView objects can exist without a buffer class, in that case it must provide its own storage for lines (binded to another storage object, for example) and mechanisms for updating the view when text content changes. Whether are you using CCrystalTextBuffer object or not, you will always need to derive your class from CCrystalTextView.

    CCrystalTextView cannot exist without CCrystalTextBuffer object.

    Using CCrystalTextView or CCrystalEditView with buffer class

    To use CCrystalEditView (or CCrystalTextView) with the CCrystalTextBuffer object, you must go through the following steps:
    1. Derive your class from CCrystalEditView (or CCrystalTextView).
    2. Override LocateTextBuffer member function. After that, your view class declaration will look like this:
      class CSampleView : public CCrystalEditView
      {
          // code omitted
      
      protected:
          virtual CCrystalTextBuffer *LocateTextBuffer();
      }
      

      and the implementation will look like this:

      CCrystalTextBuffer *CSampleView::LocateTextBuffer()
      {
          CSampleDoc *pDoc = (CSampleDoc *) GetDocument();
          return &pDoc->m_xTextBuffer;
      }
      
    That's all! From this point, view and buffer objects will work together. To load text from the file, simply call LoadFromFile method of CCrystalTextBuffer class. To save the text to file, call SaveToFile. Remember, you must call InitNew or LoadFromFile member function before using the object; and FreeAll function before deleting it.

    Parsing and syntax coloring

    All parsing is concentrated in a single method of CCrystalTextView class, declared as follows:

    virtual DWORD ParseLine(DWORD dwCookie, int nLineIndex,
                            TEXTBLOCK *pBuf, int &nActualItems);
    
    struct TEXTBLOCK
    {
        int  m_nCharPos;      // Offset from beginning of the line
        int  m_nColorIndex;   // Type of the block being defined: COLORINDEX_NORMALTEXT,
                              //  COLORINDEX_KEYWORD, COLORINDEX_COMMENT, etc.
    };
    
    This method should parse the line specified by its zero-based number (nLineIndex) and split it into the blocks of text. Each block is provided with the character position and its color.
    For the sake of an efficiency, the internal view implementation preserves the result of parsing each line. dwCookie parameter means the result of parsing the previous line. Really, this is the minimum of the information, needed to restart the parser from the indicated line. For example, when parsing C++ code, you'll have to pass the following set of flags as dwCookie parameter:
    • Extended comment (/* */) flag. This is absolutely needed because C++ has multiple-line comments.
    • Continuous double-slash comment;
    • Continuous preprocessor directive;
    • Continuous string constant;
    • Continuous character constant.

    To understand why we need last four cases, consider the following C++ code snippet:

    // This is the continuous double-slash comment.\
        you see, it is really continuous !
    #define MESSAGE "And this is continuous preprocessor directive.\n"\
        "And this is its second line."

    This approach can minimize amount of information, that we need to keep within the view object. Actually, we must preserve only the information that must be passed from one line to another. Moreover, to increase parsing speed, sometimes ParseLine member is called with NULL as pBuf parameter. In that case, the function is called only to calculate the cookie, and that can be made much faster.

    For more information, look in the demo project, which includes parser for the C++ language.

    Using CCrystalTextView without buffer class

    In that case, we are using it just as text viewer, and we need to provide the storage for lines. Suppose, we have an array of strings in the CDocument object. The view must take the text from this array. The view class declaration will look like this:
    protected:
        virtual int GetLineCount();
        virtual int GetLineLength(int nLineIndex);
        virtual LPCTSTR GetLineChars(int nLineIndex);
    

    And implementation will look like this:

    int CSampleView::GetLineCount()
    {
        // Please note that we must always return at least 1 line.
        // Even empty text has a single *empty* line!
        CSampleDoc *pDoc = (CSampleDoc *) GetDocument();
        return pDoc->m_strarrLines.GetSize();
    }
    
    int CSampleView::GetLineLength(int nLineIndex)
    {
        CSampleDoc *pDoc = (CSampleDoc *) GetDocument();
        return pDoc->m_strarrLines[nLineIndex].GetLength();
    }
    
    LPCTSTR CSampleView::GetLineChars(int nLineIndex)
    {
        CSampleDoc *pDoc = (CSampleDoc *) GetDocument();
        return pDoc->m_strarrLines[nLineIndex];
    }

    Known drawbacks and limitations

    • Only fixed fonts are supported.
    • No support for bold/italic on syntax elements (Delphi style)
    • No 'word wrap'. (Since the editor was primarily designed as a code editor, is this feature really needed?)
    • No support for column selection.

    If you decide to use this code

    You are free to use or modify this code to the following restrictions:
    • You must acknowledge me somewhere in your about box, simple "Parts of code by.." will be enough. If you cannot (or don't want to) mention my name, contact me personally. At least, I'm flexible.
    • Do not remove copyright notices from the source and header files.
    • Do not publish any part of this code or article on other websites.
    • I reserve to myself exclusive right to update this page, as well as provided source code and usage sample. Please publish your modification and additions on adjacent pages. In other words, do not blame me for other's bugs.

    The demo project includes parsing methods and the keyword set for C/C++ language. It was originally built using MS Developer Studio 5.0 SP3.

    Posted at CodeProject.com with permission of Andrei Stcherbatchenko.

    License

    This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

    A list of licenses authors might use can be found here

    Share

    About the Author

    No Biography provided

    Comments and Discussions

     
    QuestionUnicode PinmemberSZ123dsjdjd9-Mar-13 13:38 
    GeneralRuntime error in VS 2010 PinmemberMember 17562330-Jun-10 12:23 
    GeneralI've fixed a little bug Pinmembere-katerina1-Nov-08 11:59 
    GeneralA bug-- Display chinese PinmemberTony Chan9-Nov-07 3:36 
    GeneralRe: A bug-- Display chinese Pinmembersdhexu4-Oct-08 4:50 
    GeneralEdit Control to hold images Pinmemberminad_78612-Mar-07 2:07 
    GeneralSome question about GetLineChars() Pinmemberxyz999514-Aug-06 17:39 
    GeneralRe: Some question about GetLineChars() Pinmemberszblove14-Jan-09 20:22 
    QuestionCan I use the Crystal Edit for Commercial Purpose ? PinmemberTsoTakChiu26-Feb-06 15:54 
    GeneralCompiling in VC7 Pinmembercpmce20-Jan-06 3:56 
    GeneralRe: Compiling in VC7 PinmemberShahbaz Ali1-Feb-06 4:43 
    You need to use "Sample.dsw" in Demo Project
    QuestionHow to use Crystal Edit in Docking window without document? Pinmemberchihyu19-Dec-05 23:46 
    QuestionHow to implement wrapline feature? PinmemberSongLaiYun29-Oct-05 19:48 
    Questionhow to support column selection Pinmemberjackejiang9-Dec-04 4:22 
    QuestionOCX version? Pinmemberavins_7524-Oct-04 1:23 
    Questionthe limit of the length? PinsussAnonymous6-Sep-04 21:10 
    GeneralHere's Code to use as a Control PinmemberCurtis Faith13-Aug-04 13:35 
    GeneralLiscence policy PinmemberKoundinya6-Jul-04 2:37 
    GeneralNon-editable text Pinmemberrichiebabes1-Jun-04 7:26 
    GeneralRe: Non-editable text Pinmemberrichiebabes2-Jun-04 7:02 
    GeneralRe: Non-editable text Pinmembersabrown1008-Dec-07 3:52 
    GeneralProblem in the Israel HP Laptop Pinmemberrshetty27-May-04 19:36 
    GeneralCannot Compile PinmemberLachlan McCutcheon8-May-04 3:19 
    GeneralA Bug---- When Insert into Tab View(MDI View like .Net IDE) PinmemberGE - NBGYF25-Apr-04 6:24 
    GeneralTAB bug Pinmemberktalex20-Apr-04 21:09 
    GeneralRe: TAB bug PinmemberGE - NBGYF16-May-04 19:03 
    GeneralProgrammatically inserting text PinmemberDoug Matulis12-Feb-04 9:10 
    GeneralRe: Programmatically inserting text Pinsussfrancisco _lozano_ovejero24-Jul-04 1:39 
    GeneralDisplaying bugs when change font Pinmemberligs20014-Feb-04 21:30 
    GeneralRe: Displaying bugs when change font PinmemberJean-Michel LE FOL10-Mar-04 5:46 
    Generalscrollbar problem in splitter window Pinmemberwombatas27-Nov-03 14:15 
    Generalsytax parse problem PinmemberAltair_Liu23-Nov-03 14:22 
    GeneralRe: sytax parse problem Pinmemberucgui15-Jun-06 22:10 
    Generalya, what about unicode charsets Pinsusscadinfo21-Nov-03 18:54 
    GeneralRe: ya, what about unicode charsets Pinmembersammyc9-Jun-04 22:44 
    GeneralRe: ya, what about unicode charsets [modified] Pinmemberdonghyuk80kim23-Aug-12 20:14 
    QuestionMDI views? PinmemberHockey2-Nov-03 18:18 
    QuestionHow get I the hole text from CrystalView? PinsussAnonymous2-Nov-03 3:27 
    Generalresource problem PinmemberHockey24-Oct-03 15:21 
    GeneralRe: resource problem PinmemberHockey24-Oct-03 15:37 
    GeneralRe: resource problem Pinmemberwingwind9-Aug-06 2:53 
    GeneralRe: resource problem Pinmemberwingwind12-Aug-06 16:37 
    GeneralContinuous double-slash comment -- incomplete Pinmember.:fl0yd:.31-May-03 2:10 
    GeneralBug in comments: PinmemberAdam Clauss25-May-03 15:00 
    GeneralDoes any one know how to use other languages. PinmemberAtewa15-May-03 6:55 
    GeneralRe: Does any one know how to use other languages. Pinmembersammyc9-Jun-04 22:46 
    GeneralFind Replace Problem PinmemberCarey Hart15-Apr-03 4:40 
    GeneralPrint preview PinmemberThe Lady of Shallots21-Mar-03 9:11 
    GeneralCrash when saving file in Unicode build (and fix) PinmemberPierre MEINDRE6-Mar-03 2:11 
    GeneralToolbar colours Pinmembernottelling1-Mar-03 7:33 

    General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

    Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

    | Advertise | Privacy | Mobile
    Web02 | 2.8.140827.1 | Last Updated 31 Jan 2000
    Article Copyright 2000 by Andrei Stcherbatchenko
    Everything else Copyright © CodeProject, 1999-2014
    Terms of Service
    Layout: fixed | fluid