00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #ifndef qsourcecolorizer_h
00024 #define qsourcecolorizer_h
00025
00026 #include <private/qrichtext_p.h>
00027 #include <qintdict.h>
00028 #include <qptrlist.h>
00029 #include <qmap.h>
00030 #include <qregexp.h>
00031 #include <qpair.h>
00032 #include <kdebug.h>
00033
00034 #define DECLARE_FORMAT_ITEM(type, id, f, c)\
00035 {\
00036 QFont font = f; \
00037 QColor color = c; \
00038 font = config->readFontEntry( QString("Font ") + id, &font ); \
00039 color = config->readColorEntry( QString("Color ") + id, &color ); \
00040 m_formats.insert( type, qMakePair(QString(id), new QTextFormat(font, color)) ); \
00041 }
00042
00043 #define UPDATE_FORMAT_ITEM(type, f, c)\
00044 m_formats[ type ].second->setFont( f ); \
00045 m_formats[ type ].second->setColor( c );
00046
00047 #define STORE_FORMAT_ITEM(type)\
00048 {\
00049 QString id = m_formats[ type ].first; \
00050 QTextFormat* fmt = m_formats[ type ].second; \
00051 config->writeEntry( QString("Font ") + id, fmt->font() ); \
00052 config->writeEntry( QString("Color ") + id, fmt->color() ); \
00053 }
00054
00055 class QEditor;
00056
00057 class HLItem{
00058 public:
00059 HLItem( int state=0, int context=0 )
00060 : m_state( state ), m_context( context ) {}
00061 virtual ~HLItem() {}
00062
00063 virtual int attr() const { return m_state; }
00064 virtual int context() const { return m_context; }
00065
00066 virtual int checkHL( const QChar* buffer, int pos, int length, int*, int* ) = 0;
00067
00068 private:
00069 int m_state;
00070 int m_context;
00071 };
00072
00073 class NumberHLItem: public HLItem{
00074 public:
00075 NumberHLItem( int state, int context )
00076 : HLItem( state, context ) {}
00077
00078 int checkHL( const QChar* buffer, int pos, int length, int*, int* ){
00079
00080 while( pos<length && buffer[pos].isNumber() ){
00081 ++pos;
00082 }
00083 return pos;
00084 }
00085 };
00086
00087 class WhiteSpacesHLItem: public HLItem{
00088 public:
00089 WhiteSpacesHLItem( int state, int context )
00090 : HLItem( state, context ) {}
00091
00092 int checkHL( const QChar* buffer, int pos, int length, int*, int* ){
00093
00094 while( (pos<length) && buffer[pos].isSpace() ){
00095 ++pos;
00096 }
00097 return pos;
00098 }
00099 };
00100
00101 class KeywordsHLItem: public HLItem{
00102 public:
00103 KeywordsHLItem( const char** keywords, int state, int ide_state, int context, bool finalize = true, bool ignoreCase = false )
00104 : HLItem( state, context ), m_ok(false), m_state(state), m_ide_state(ide_state), m_finalize(finalize), m_ignoreCase(ignoreCase) {
00105 int i = 1;
00106 if ( ignoreCase ) {
00107 while( *keywords )
00108 m_keywords.insert( QString(*keywords++).lower(), i++ );
00109 } else {
00110 while( *keywords )
00111 m_keywords.insert( QString(*keywords++), i++ );
00112 }
00113 }
00114
00115 KeywordsHLItem( const QMap<QString, int> keywords, int state, int ide_state, int context, bool finalize = true, bool ignoreCase = false )
00116 : HLItem( state, context ), m_ok(false), m_state(state), m_ide_state(ide_state), m_finalize(finalize), m_ignoreCase(ignoreCase) {
00117 m_keywords = keywords;
00118 }
00119
00120 int attr() const { return m_ok ? m_state : m_ide_state; }
00121
00122 int checkHL( const QChar* buffer, int pos, int length, int*, int* ){
00123
00124
00125 int start_pos = pos;
00126
00127 while( (pos<length) && (buffer[pos].isLetterOrNumber() || buffer[pos] == '_') )
00128 ++pos;
00129
00130 if( start_pos != pos ) {
00131 if ( m_ignoreCase ) {
00132 m_ok = m_keywords.contains( QString(buffer+start_pos, pos-start_pos).lower() );
00133 } else {
00134 m_ok = m_keywords.contains( QString(buffer+start_pos, pos-start_pos) );
00135 }
00136 }
00137
00138 return ( m_ok || m_finalize ) ? pos : start_pos;
00139 }
00140
00141 private:
00142 QMap<QString, int> m_keywords;
00143 bool m_ok;
00144 int m_state;
00145 int m_ide_state;
00146 bool m_finalize;
00147 bool m_ignoreCase;
00148 };
00149
00150 class StartsWithHLItem: public HLItem{
00151 public:
00152 StartsWithHLItem( const QString& s, int state, int context )
00153 : HLItem( state, context ), m_text(s) {}
00154
00155 int checkHL( const QChar* buffer, int pos, int length, int*, int* ){
00156
00157 if( (length - pos) >= (int)m_text.length() && QString(buffer+pos, m_text.length()) == m_text )
00158 return length;
00159
00160 return pos;
00161 }
00162
00163 private:
00164 QString m_text;
00165 };
00166
00167 class StringHLItem: public HLItem{
00168 public:
00169 StringHLItem( const QString& text, int state, int context )
00170 : HLItem( state, context ), m_text(text) {}
00171
00172 int checkHL( const QChar* buffer, int pos, int length, int*, int* ){
00173
00174 if( (length - pos) >= (int)m_text.length() && QString(buffer+pos, m_text.length()) == m_text )
00175 return pos + m_text.length();
00176
00177 return pos;
00178 }
00179
00180 private:
00181 QString m_text;
00182 };
00183
00184 class RegExpHLItem: public HLItem{
00185 public:
00186 RegExpHLItem( QString pattern, int state, int context )
00187 : HLItem( state, context ), m_rx( pattern ) {}
00188
00189 int checkHL( const QChar* buffer, int pos, int length, int*, int* ){
00190
00191 QString s( buffer, length );
00192
00193 int idx = m_rx.search(s, pos);
00194 if( idx == pos )
00195 return pos + m_rx.matchedLength();
00196
00197 return pos;
00198 }
00199
00200 private:
00201 QRegExp m_rx;
00202 };
00203
00204 class HexHLItem: public HLItem{
00205 public:
00206 HexHLItem( int state, int context )
00207 : HLItem( state, context ) {}
00208
00209 int checkHL( const QChar* buffer, int pos, int length, int*, int* ){
00210 if( (length-pos) > 2 ){
00211 QString s( buffer+pos,2 );
00212 if( s == "0x" || s == "0X" ){
00213 pos += 2;
00214 while( pos < length ){
00215 const QChar& ch = buffer[ pos ];
00216 if( ch.isNumber() || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F') )
00217 ++pos;
00218 else
00219 break;
00220 }
00221
00222 }
00223 }
00224 return pos;
00225 }
00226 };
00227
00228 class HLItemCollection: public HLItem{
00229 public:
00230 HLItemCollection( int state=0, int context=0 ): HLItem( state, context )
00231 { m_items.setAutoDelete( TRUE ); }
00232
00233 void appendChild( HLItem* item ) { m_items.append( item ); }
00234
00235 int checkHL( const QChar* buffer, int pos, int length, int* state, int* next ){
00236 QPtrListIterator<HLItem> it( m_items );
00237
00238 while( it.current() ){
00239 HLItem* item = it.current();
00240
00241 int npos = item->checkHL( buffer, pos, length, state, next );
00242
00243 if( npos > pos ){
00244 pos = npos;
00245 if( state )
00246 *state = item->attr();
00247 if( next )
00248 *next = item->context();
00249 break;
00250 }
00251 ++it;
00252 }
00253
00254 return pos;
00255 }
00256
00257 private:
00258 QPtrList<HLItem> m_items;
00259 };
00260
00261 class QSourceColorizer: public QTextPreProcessor{
00262 public:
00263 enum Type {
00264 Normal=0,
00265 PreProcessor,
00266 Keyword,
00267 BuiltInClass,
00268 Operator,
00269 Comment,
00270 Constant,
00271 String,
00272
00273 Custom = 1000
00274 };
00275
00276 public:
00277 QSourceColorizer( QEditor* );
00278 virtual ~QSourceColorizer();
00279
00280 QEditor* editor() const { return m_editor; }
00281
00282 void insertHLItem( int, HLItemCollection* );
00283
00284 void setSymbols( const QString&, const QString& );
00285 QString leftSymbols() const { return m_left; }
00286 QString rightSymbols() const { return m_right; }
00287
00288 virtual QTextFormat* format( int key ) { return m_formats[ key ].second; }
00289 virtual QTextFormat* formatFromId( const QString& id );
00290
00291 QStringList styleList() const;
00292 virtual void updateStyles( QMap<QString, QPair<QFont, QColor> >& values );
00293 virtual void process( QTextDocument*, QTextParagraph*, int, bool=FALSE );
00294 virtual int computeLevel( QTextParagraph*, int ) { return 0; }
00295
00296 protected:
00297 QEditor* m_editor;
00298 QMap<int, QPair<QString, QTextFormat*> > m_formats;
00299 QPtrList<HLItemCollection> m_items;
00300 QString m_left;
00301 QString m_right;
00302 };
00303
00304
00305 #endif