Scintilla icon Scintilla Usage Notes

Implementing Auto-Indent

The key idea is to use the SCN_CHARADDED notification to add indentation after a newline.

The lParam on the notification is a pointer to a SCNotification structure whose ch member specifies the character added. If a newline was added, the previous line can be retrieved and the same indentation can be added to the new line.

Here is the relevant portion of code from SciTE: (SciTE.cxx SciTEWindow::CharAdded)

if  (ch  ==  '\r'  ||  ch  ==  '\n')  {
    
char  linebuf[1000];
    
int  curLine  =  GetCurrentLineNumber();
    
int  lineLength  =  SendEditor(SCI_LINELENGTH,  curLine);
    
//Platform::DebugPrintf("[CR] %d len = %d\n", curLine, lineLength);
    
if  (curLine  >  0  &&  lineLength  <=  2)  {
    
int  prevLineLength  =  SendEditor(SCI_LINELENGTH,  curLine  -  1);
    
if  (prevLineLength  <  sizeof(linebuf))  {
        
WORD  buflen  =  sizeof(linebuf);
        
memcpy(linebuf,  &buflen,  sizeof(buflen));
        
SendEditor(EM_GETLINE,  curLine  -  1,
                   
reinterpret_cast<LPARAM>(static_cast<char  *>(linebuf)));
        
linebuf[prevLineLength]  =  '\0';
        
for  (int Scintilla Usage Notes
Scintilla icon Scintilla Usage Notes

Implementing Auto-Indent

The key idea is to use the SCN_CHARADDED notification to add indentation after a newline.

The lParam on the notification is a pointer to a SCNotification structure whose ch member specifies the character added. If a newline was added, the previous line can be retrieved and the same indentation can be added to the new line.

Here is the relevant portion of code from SciTE: (SciTE.cxx SciTEWindow::CharAdded)

if  (ch  ==  '\r'  ||  ch  ==  '\n')  {
    
char  linebuf[1000];
    
int  curLine  =  GetCurrentLineNumber();
    
int  lineLength  =  SendEditor(SCI_LINELENGTH,  curLine);
    
//Platform::DebugPrintf("[CR] %d len = %d\n", curLine, lineLength);
    
if  (curLine  >  0  &&  lineLength  <=  2)  {
    
int  prevLineLength  =  SendEditor(SCI_LINELENGTH,  curLine  -  1);
    
if  (prevLineLength  <  sizeof(linebuf))  {
        
WORD  buflen  =  sizeof(linebuf);
        
memcpy(linebuf,  &buflen,  sizeof(buflen));
        
SendEditor(EM_GETLINE,  curLine  -  1,
                   
reinterpret_cast<LPARAM>(static_cast<char  *>(linebuf)));
        
linebuf[prevLineLength]  =  '\0';
        
for  (int  pos  =  0;  linebuf[pos];  pos++)  {
            
if  (linebuf[pos]  !=  ' '  &&  linebuf[pos]  !=  '\t')
                
linebuf[pos]  =  '\0';
        
}
        
SendEditor(EM_REPLACESEL,  0,  reinterpret_cast<LPARAM>(static_cast<char  *>(linebuf)));
    
}
}

Of course, fancier handling could be implemented. For example, if the previous line was the start of a control construct, the next line could be automatically indented one tab further. (Assuming that is your indenting style.)

Implementing Syntax Styling

Syntax styling is handled by the SCN_STYLENEEDED notification. Scintilla keeps track of the end of the styled text - this is retrieved with SCI_GETENDSTYLED. In response to the SCN_STYLENEEDED notification, you should apply styles to the text from ENDSTYLED to the position specified by the notification.

Here is the relevant portion of code from SciTE: (SciTE.cxx)

void  SciTEWindow::Notify(SCNotification  *notification)  {
    
switch  (notification->nmhdr.code)  {
    
case  SCN_STYLENEEDED:  {
            
if  (notification->nmhdr.idFrom  ==  IDM_SRCWIN)  {
                
int  endStyled  =  SendEditor(SCI_GETENDSTYLED);
                
int  lineEndStyled  =  SendEditor(EM_LINEFROMCHAR,  endStyled);
                
endStyled