Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Using Scintilla for syntax coloring in MFC

0.00/5 (No votes)
29 Jun 2003 2  
The article describes how to use the scintilla control in a MFC application to display syntax coloring information

Introduction

Using syntax coloring when editing source code makes navigating the code much easier. If you want to put syntax coloring to work in your application this seemed to be a complicated tasks. Neil Hodgson from www.scintilla.org has written an excellent multiplatform editing control for that task. It is for use on Windows and Linux and does not use MFC. If you want to integrate this control into your application you have to build a MFC wrapper to use it in a CView derived class or in a dialog box. This article describes how to do that by implementing a sample application which handles most of the common tasks.

Background

Syntax coloring uses different colors for portions of a text. Scintilla uses styles for that task. Each style has a foreground color, a background color and font attributes to draw the text. If text is loaded into the control a lexer module scans the text and assigns numbered styles to known keywords, strings, numbers or comments. There are a lot of lexer modules for common languages (HTML, XML, C++, Java etc.) integrated into scintilla. Another concept of scintilla is source folding. Folding hides or redisplays a portion of source code to make code easier to navigate. Think of folding as a treeview of your source - if you click on a folding symbol at an "else" statement, the body of the statement is hidden and you you get a visual indicator (a +-sign) to expand it again.

Using the scintilla control

You may derive your CView class from CScintillamfcView or use the CScintillaWnd class provided.

Loading Scintilla

Scintilla comes as a DLL in two flavors - simple scintilla without advanced lexers as scintilla.dll or as SciLexer.dll with all built-in lexers for HTML, XML, C++ etc. Load the DLL in your CWinApp::InitInstace() function:

HMODULE m_hDll = NULL;
m_hDll = ::LoadLibrary(_T("SciLexer.dll"));

In your CWinApp:.ExitInstance() function unload the Library by calling:

AfxFreeLibrary(m_hDll);

Creating the Window and setting a lexer

Scintilla is NOT derived from CEdit or CRichEdit! You have to use a member variable in you CView derived class and create the Scintilla window yourself by calling:

int CScintillamfcView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
   if (CView::OnCreate(lpCreateStruct) == -1)
        return -1;
   if (!m_wndScintilla.Create(_T("Title"), WS_CHILD | WS_VISIBLE, 
        CRect(0,0,0,0), this, 10000))
   {   
      return -1;
   }
    return 0;
}

You have to size the scintilla window to fit the size of the client area of your view:

void CScintillamfcView::OnSize(UINT nType, int cx, int cy)
{
   CView::OnSize(nType, cx, cy);
    if (m_wndScintilla.GetSafeHwnd())
   {
      m_wndScintilla.MoveWindow(0, 0, cx, cy);
   }
}

The scintilla window is now ready to use. If you want some reasonable defaults call the CScintillaWnd::Init() to set some styles and to allow brace highlighting. The most important part now is to find a lexer which fits your source code. If you load a file, the view tries to find a matching lexer from the file extension of the document by calling CScintillaWnd::LoadFile():

void CScintillamfcView::OnInitialUpdate() 
{
   CView::OnInitialUpdate();
   CDocument *pDoc = GetDocument();
   CString strTitle = pDoc->GetPathName();
    m_wndScintilla.Init();
    m_wndScintilla.LoadFile(strTitle);

}

Exploring Scintilla styles

If you load a C++ source file into the scintilla mfc application and move the cursor around you will notice a status bar display indicating "Style:xxx". If you move the cursor into a quoted string this display may change to "Style:6". This means the lexer for the C++ language has detected a quoted string. If you pull down the options menu and select a new foreground color "red" for this style, all quoted strings within the control turn red. Scintilla uses up to 128 styles depending on the language used. Most of languages use only up to 32 styles, but HTML with embedded scripting needs all 128 styles. If you want to let the user customize the styles for a language you have to take a look at the supplied lexer source code to find out which style is used for what language construct. Nearly all lexers use up to 8 wordlists of keywords to find language specific keywords like while, if, else etc. The scintilla mfc application has a menu command to try that for C++ keywords. After setting the default wordlist from the dialog to wordlist (0). All C++ keywords should turn blue. You can set style attributes by calling the following CScintillaWnd functions:

// @cmember set the fontname for a style number

   virtual void SetFontname(int nStyle, LPCSTR szFontname);
// @cmember set the fontname height in points for a style number

   virtual void SetFontheight(int nStyle, int nHeight);
// @cmember set the foregroundcolor for a style number

   virtual void SetForeground(int nStyle, COLORREF crForeground);
// @cmember set the backgroundcolor for a style number

   virtual void SetBackground(int nStyle, COLORREF crBackground);
// @cmember set given style to bold

   virtual void SetBold(int nStyle, BOOL bFlag);
// @cmember set given style to bold

   virtual void SetItalic(int nStyle, BOOL bFlag);
// @cmember set given style to bold

   virtual void SetUnderline(int nStyle, BOOL bFlag);

Exploring Scintilla source folding

The status bar of the scintilla mfc applications displays "Folding levels". If you look at the left margin of the display of a C++ file you see some minus signs in the margin. If you click on that sign it turns into a plus sign and some portions of the source code disappear. This is called "source folding". To activate folding you have to process notification messages in your CView derived class. Scintilla sends a notification if the user clicks in one of the margins supplied by the control. You have to capture this notification and process them. The CScintillaWnd class has some standard function to process standard folding and brace highlighting for you. You must capture the notification in a OnNotify handler:

BOOL CScintillamfcView::OnNotify(WPARAM wParam, 
      LPARAM lParam, LRESULT* pResult)
{
   NMHDR *phDR;
   phDR = (NMHDR*)lParam;
// does notification come from my scintilla window?

   if (phDR !=  NULL &&phDR->hwndFrom == m_wndScintilla.m_hWnd)
   {
      SCNotification *pMsg = 
       (SCNotification*)lParam;
      switch
(phDR->code)       { // called when the document is changed - mark

         document modified
         case
            SCN_SAVEPOINTLEFT: {  CDocument
            *pDoc=
         GetDocument();
         pDoc->SetModifiedFlag(TRUE);
}       break; // called when something changes and 

               // we want to show new indicator state or

         brace matching
         case
            SCN_UPDATEUI:
         {
         m_wndScintilla.UpdateUI();
}       break; // user clicked margin - try

         folding action
         case
            SCN_MARGINCLICK:{ m_wndScintilla.DoDefaultFolding(
                      pMsg->margin,pMsg->position);
         }
         break;
      }
      return TRUE; // we processed the message

   }
   return CWnd::OnNotify(wParam, lParam, pResult);
}

More Scintilla features

Scintilla is a solid piece of work and has more features than discussed here. If you want to find out more about call tips, bookmarks, search and replace with regular expressions, auto-complete and macro recording you have to take a look at the www.scintilla.org website and the HTML docs about the messages used by scintilla.

History

  • 06/07/2003 initial release 1.1 for scintilla 1.53.

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