Today my thoughts about making syntax highlighting for my blog came back to me. As my blog is based on bash scripts, I needed an application that would do the actual highlighting. I know there exists a plugin for nanoblogger that enables syntax highlighting, but it’s fair from being mature. So I sat down and implemented
my own generic syntax highlighter. It’s not complete yet, but it already does some highlighting and it only took about an hour to implement. Qt was very helpful, as usual
Testing the highlighter should include trying to parse the code of the highlighter itself and so I did. You can see the result below.
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- class�QHighlighter{
- public:
- ��QHighlighter(QIODevice�*indevice);
- ��void�readConfig(QIODevice�*configdevice);
- ��QString�parse();
- protected:
- ��QString�isKeyword(const�QString�&);
- ��QString�parseNumber();
- ��QString�parseIdentifier();
- ��QString�parseString();
- ��QString�parseComment();
- ��QString�parsePreproc();
- ��QString�parseSLComment();
- ��void�makeLines(bool�count=false);
- ��QIODevice�*_indevice;
- ��bool�_perror;
- ��QString�output;
- ��QMap<QString,�QStringList>�keywords;
- ��
- };
- void�QHighlighter::readConfig(QIODevice�*configdevice){
- ����QDomDocument�doc;
- ����if(!doc.setContent(configdevice)){
- ��������qDebug(“CONFIG ERROR”);
- ��������return;
- ����}
- ����QDomElement�root�=�doc.documentElement();
- ����for(QDomElement�keywselem�=�root.firstChildElement(“keywords”);�
- ��������!keywselem.isNull();�
- ��������keywselem�=�keywselem.nextSiblingElement(“keywords”))
- ����{
- ��������QStringList�kw;
- ��������for(QDomElement�key�=�keywselem.firstChildElement(“keyword”);�
- ������������!key.isNull();
- ������������key�=�key.nextSiblingElement(“keyword”))
- ��������{
- ������������kw�<<�key.text().trimmed();
- ��������}
- ��������QDomElement�keystyle�=�keywselem.firstChildElement(“style”);
- ��������QString�kstyle�=�keystyle.text().replace(“$”,�“%”).replace(“[“,�“<").replace(“]–>,�“>”);
- ��������keywords[kstyle]�=�kw;
- ����}
- }
- QString�QHighlighter::isKeyword(const�QString�&s){
- ��foreach(QString�k,�keywords.keys()){
- ����const�QStringList�&slist�=�keywords[k];
- ����foreach(QString�el,�slist){
- ������if(QRegExp(el).exactMatch(s))�return�k.arg(s);
- ����}
- �}
- �return�s;
- }
- QHighlighter::QHighlighter(QIODevice�*indevice){
- ��_indevice�=�indevice;
- ��_perror�=�false;
- }
- void�QHighlighter::makeLines(bool�countLines){
- ��if(!countLines)�output�=�output.replace(“\n”,�“
“);- ��else�{
- ����QString�n�=�”
- “;
- ����foreach(QString�line,�output.split(“\n”)){
- ������n+=QString(”
- %1
- ����}
- ����n+=“
\n”).arg(line);
“
;- ����output�=�n;
- ��}
- }
- QString�QHighlighter::parse(){
- ��QString�current;
- ��while(!_indevice->atEnd()){
- ����char�c�=�_indevice->peek(1).at(0);
- ����QChar�ch(c);
- ����if(ch.isNumber())�{
- ������current�=�parseNumber();
- ������output�+=QString(“%1“).arg(current);
- ����}�else�if(ch.isLetter()�||�ch==‘_’)�{
- ������current�=�parseIdentifier();
- ������output�+=�isKeyword(current);
- ����}�else�if(c==‘”‘||�c==‘\”�)�{
- ������current�=�parseString().replace(“<“,�“<“);
- ������output�+=QString(“%1“).arg(current);
- ����}�else�if(c==‘/’�&&�_indevice->peek(2)==“/*”)�{
- ������current�=�parseComment().replace(“<“,�“<“);
- ������output�+=QString(“%1“).arg(current);
- ����}�else�if(c==‘/’�&&�_indevice->peek(2)==“//”){
- ������current�=�parseSLComment().replace(“<“,�“<“);
- ������output�+=�QString(“%1“).arg(current);
- ����}�else�if(c==‘#’){
- ������current�=�parsePreproc().replace(“<“,�“<“);
- ������output�+=�QString(“%1“).arg(current);
- ����}�else�if(c==‘<‘){
- ����_indevice->getChar(&c);
- ������output�+=�“<“;
- ����}�else�{
- ������_indevice->getChar(&c);
- ������if(c!=‘ ‘)
- ������output�+=�c;
- ������else�output�+=“�”;
- ����}
- ��}
- ��makeLines(true);
- ��return�output;
- }
- QString�QHighlighter::parsePreproc(){
- ��return�_indevice->readLine();
- }
- QString�QHighlighter::parseSLComment(){
- ��return�_indevice->readLine();
- }
- QString�QHighlighter::parseNumber(){
- ��QString�result;
- ��char�c;
- ��while(!_indevice->atEnd()){
- ����if(!_indevice->getChar(&c)){
- ������_perror�=�true;
- ������return�result;
- ����}
- ����QChar�ch(c);
- ����if(ch.isNumber()�||�c==‘.’){
- ������result+=c;
- ����}�else�{
- ������_indevice->ungetChar(c);
- ������return�result;
- ����}
- ��}
- ��return�result;
- }
- QString�QHighlighter::parseComment(){
- ��QString�result;
- ��char�c=‘\0′;
- ��char�prev=‘\0′;
- ��while(!_indevice->atEnd()){
- ����if(!_indevice->getChar(&c)){
- ������_perror�=�true;
- ������return�result;
- ����}
- ����// match */
- ����if(c==‘/’�&&�prev==‘*’){
- ��������result�+=c;
- ��������return�result;
- ����}
- ����prev�=�c;
- ����result+=c;
- ��}
- ���_perror�=�true;
- ��return�result;
- }
- QString�QHighlighter::parseIdentifier(){
- ��QString�result;
- ��char�c;
- ��while(!_indevice->atEnd()){
- ����if(!_indevice->getChar(&c)){
- ������_perror�=�true;
- ������return�result;
- ����}
- ����QChar�ch(c);
- ����if(ch.isLetter()�||�ch.isDigit()�||�c==‘_’�||�c==‘:’){
- ������result+=c;
- ����}�else�{
- ������_indevice->ungetChar(c);
- ������return�result;
- ����}
- ��}
- ��return�result;
- }
- QString�QHighlighter::parseString(){
- ��QString�result;
- ��char�c;
- ��char�sep;
- ��_indevice->getChar(&sep);
- ��result+=sep;
- ��while(!_indevice->atEnd()){
- ����if(!_indevice->getChar(&c)){
- ������_perror�=�true;
- ������return�result;
- ����}
- ����if(c==‘\\’){
- ������if(!_indevice->getChar(&c)){
- ��������_perror�=�true;
- ��������return�result;
- ������}
- ������result+=‘\\’;
- ������result+=c;
- ����}�else�if(c!=sep)�
- ������result+=c;
- �����else�{
- ������// _indevice->ungetChar(c);
- ��������result+=c;
- �������return�result;
- �����}
- ��}
- ��_perror�=�true;
- ��return�result;
- }
- int�main(int�argc,�char�**argv){
- ��QFile�infile(argv[1]);
- ��if(!infile.open(QFile::ReadOnly))�return�2;
- ��QHighlighter�h(&infile);
- ��QFile�config(“h.config”);
- ��if(!config.open(QFile::ReadOnly))�return�2;
- ��h.readConfig(&config);
- ��QString�result�=�h.parse();
- ��QFile�outfile(“hh.html”);
- ��outfile.open(QFile::WriteOnly);
- // outfile.write(”
");
- ��outfile.write(result.toLocal8Bit());
- // outfile.write(“”);
- ��return�0;
- }
]]>