HTMLRewrite.cpp revision a745e8c52839d9c8dd0fd8d5276b4eab182ec7f2
123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)//== HTMLRewrite.cpp - Translate source code into prettified HTML --*- C++ -*-// 2a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// 3a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// The LLVM Compiler Infrastructure 4a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// 5effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// This file is distributed under the University of Illinois Open Source 6a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// License. See LICENSE.TXT for details. 7effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// 8cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)//===----------------------------------------------------------------------===// 9effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// 10a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// This file defines the HTMLRewriter clas, which is used to translate the 115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// text of a source file into prettified HTML. 12a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// 135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)//===----------------------------------------------------------------------===// 14a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "clang/Rewrite/Rewriter.h" 16a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "clang/Rewrite/HTMLRewrite.h" 17a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "clang/Lex/Preprocessor.h" 18a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "clang/Basic/SourceManager.h" 19a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "llvm/ADT/SmallString.h" 20a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "llvm/Support/MemoryBuffer.h" 21a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include <sstream> 225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)using namespace clang; 235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void html::EscapeText(Rewriter& R, unsigned FileID, 255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) bool EscapeSpaces, bool ReplaceTabs) { 26a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 27a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) const llvm::MemoryBuffer *Buf = R.getSourceMgr().getBuffer(FileID); 28a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) const char* C = Buf->getBufferStart(); 29a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) const char* FileEnd = Buf->getBufferEnd(); 30a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 31a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) assert (C <= FileEnd); 32a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 33a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) RewriteBuffer &RB = R.getEditBuffer(FileID); 34a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 35a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) for (unsigned FilePos = 0; C != FileEnd ; ++C, ++FilePos) { 36a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 37a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) switch (*C) { 38a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) default: break; 39a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) case ' ': 415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (EscapeSpaces) 425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) RB.ReplaceText(FilePos, 1, " ", 6); 43a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) break; 44a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) case '\t': 46a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (!ReplaceTabs) 47a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) break; 485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (EscapeSpaces) 495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) RB.ReplaceText(FilePos, 1, " ", 6*4); 505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) else 515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) RB.ReplaceText(FilePos, 1, " ", 4); 525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) break; 535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 54a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) case '<': 555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) RB.ReplaceText(FilePos, 1, "<", 4); 565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) break; 575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) case '>': 595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) RB.ReplaceText(FilePos, 1, ">", 4); 60a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) break; 61a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 62a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) case '&': 63a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) RB.ReplaceText(FilePos, 1, "&", 5); 64a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) break; 65a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 66a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)std::string html::EscapeText(const std::string& s, bool EscapeSpaces, 70a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) bool ReplaceTabs) { 71a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 72a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) unsigned len = s.size(); 73a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) std::ostringstream os; 74a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 75a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) for (unsigned i = 0 ; i < len; ++i) { 76a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 77a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) char c = s[i]; 78a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) switch (c) { 79a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) default: 80a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) os << c; break; 815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) case ' ': 835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (EscapeSpaces) os << " "; 845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) else os << ' '; 855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) break; 865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) case '\t': 885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (ReplaceTabs) 895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) for (unsigned i = 0; i < 4; ++i) 905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) os << " "; 915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) else 925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) os << c; 93a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) break; 955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) case '<': os << "<"; break; 97a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) case '>': os << ">"; break; 985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) case '&': os << "&"; break; 995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 1005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 1015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return os.str(); 1035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 104a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 1055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)static void AddLineNumber(RewriteBuffer &RB, unsigned LineNo, 1065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) unsigned B, unsigned E) { 1075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) llvm::SmallString<100> Str; 1085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) Str += "<tr><td class=\"num\" id=\"LN"; 1095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) Str.append_uint(LineNo); 1105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) Str += "\">"; 1115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) Str.append_uint(LineNo); 1125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) Str += "</td><td class=\"line\">"; 113cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 114cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (B == E) { // Handle empty lines. 115cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) Str += " </td></tr>"; 116cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) RB.InsertTextBefore(B, &Str[0], Str.size()); 117cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } else { 118cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) RB.InsertTextBefore(B, &Str[0], Str.size()); 119cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) RB.InsertTextBefore(E, "</td></tr>", strlen("</td></tr>")); 1205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 1215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 1225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void html::AddLineNumbers(Rewriter& R, unsigned FileID) { 1245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 125a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) const llvm::MemoryBuffer *Buf = R.getSourceMgr().getBuffer(FileID); 126a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) const char* FileBeg = Buf->getBufferStart(); 127a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) const char* FileEnd = Buf->getBufferEnd(); 128a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) const char* C = FileBeg; 129a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) RewriteBuffer &RB = R.getEditBuffer(FileID); 130a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 131a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) assert (C <= FileEnd); 132a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 133a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) unsigned LineNo = 0; 134a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) unsigned FilePos = 0; 1355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) while (C != FileEnd) { 1375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ++LineNo; 139a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) unsigned LineStartPos = FilePos; 140a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) unsigned LineEndPos = FileEnd - FileBeg; 141a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 142a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) assert (FilePos <= LineEndPos); 143a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) assert (C < FileEnd); 144a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 145a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // Scan until the newline (or end-of-file). 146a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 1475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) while (C != FileEnd) { 148a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) char c = *C; 1495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ++C; 1505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (c == '\n') { 1525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) LineEndPos = FilePos++; 1535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) break; 1545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 155a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 156a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) ++FilePos; 157a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 158a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 159a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) AddLineNumber(RB, LineNo, LineStartPos, LineEndPos); 160a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 161a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 162a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // Add one big table tag that surrounds all of the code. 163a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) RB.InsertTextBefore(0, "<table class=\"code\">\n", 164a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) strlen("<table class=\"code\">\n")); 1655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) RB.InsertTextAfter(FileEnd - FileBeg, "</table>", strlen("</table>")); 167a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} 1685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void html::AddHeaderFooterInternalBuiltinCSS(Rewriter& R, unsigned FileID) { 1705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const llvm::MemoryBuffer *Buf = R.getSourceMgr().getBuffer(FileID); 1725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const char* FileStart = Buf->getBufferStart(); 1735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const char* FileEnd = Buf->getBufferEnd(); 174a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 175a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) SourceLocation StartLoc = SourceLocation::getFileLoc(FileID, 0); 176a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) SourceLocation EndLoc = SourceLocation::getFileLoc(FileID, FileEnd-FileStart); 177a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 1785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Generate header 179a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) R.InsertCStrBefore(StartLoc, 180a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "<html>\n<head>\n" 181a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "<style type=\"text/css\">\n" 182a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) " body { color:#000000; background-color:#ffffff }\n" 183a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) " body { font-family:Helvetica, sans-serif; font-size:10pt }\n" 184a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) " h1 { font-size:14pt }\n" 185a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) " .code { border-spacing:0px; width:100%; }\n" 186a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) " .code { font-family: \"Andale Mono\", monospace; font-size:10pt }\n" 187a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) " .code { line-height: 1.2em }\n" 188a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) " .comment { color: #A0A0A0 }\n" 189a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) " .keyword { color: #FF00FF }\n" 190a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) " .directive { color: #FFFF00 }\n" 191a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) " .macro { color: #FF0000; background-color:#FFC0C0 }\n" 192a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) " .num { width:2.5em; padding-right:2ex; background-color:#eeeeee }\n" 193a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) " .num { text-align:right; font-size: smaller }\n" 194a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) " .num { color:#444444 }\n" 195a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) " .line { padding-left: 1ex; border-left: 3px solid #ccc }\n" 196a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) " .line { white-space: pre }\n" 197a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) " .msg { background-color:#fff8b4; color:#000000 }\n" 1985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) " .msg { -webkit-box-shadow:1px 1px 7px #000 }\n" 1995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) " .msg { -webkit-border-radius:5px }\n" 2005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) " .msg { font-family:Helvetica, sans-serif; font-size: smaller }\n" 2015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) " .msg { font-weight: bold }\n" 2025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) " .msg { float:left }\n" 2035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) " .msg { padding:0.5em 1ex 0.5em 1ex }\n" 2045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) " .msg { margin-top:10px; margin-bottom:10px }\n" 205a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) " .mrange { background-color:#dfddf3 }\n" 206a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) " .mrange { border-bottom:1px solid #6F9DBE }\n" 2075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) " .PathIndex { font-weight: bold }\n" 2085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) " table.simpletable {\n" 2095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) " padding: 5px;\n" 2105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) " font-size:12pt;\n" 2115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) " margin:20px;\n" 2125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) " border-collapse: collapse; border-spacing: 0px;\n" 2135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) " }\n" 2145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) " td.rowname {\n" 2155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) " text-align:right; font-weight:bold; color:#444444;\n" 2165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) " padding-right:2ex; }\n" 217a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "</style>\n</head>\n<body>"); 2185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Generate footer 220a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 221a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) R.InsertCStrAfter(EndLoc, "</body></html>\n"); 222a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 223a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 224a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)/// SyntaxHighlight - Relex the specified FileID and annotate the HTML with 225a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)/// information about keywords, macro expansions etc. This uses the macro 226116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch/// table state from the end of the file, so it won't be perfectly perfect, 227116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch/// but it will be reasonably close. 228116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid html::SyntaxHighlight(Rewriter &R, unsigned FileID, Preprocessor &PP) { 229116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch RewriteBuffer &RB = R.getEditBuffer(FileID); 230116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 231116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch const SourceManager &SourceMgr = PP.getSourceManager(); 232116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch std::pair<const char*, const char*> File = SourceMgr.getBufferData(FileID); 233116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch const char *BufferStart = File.first; 234116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 235116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch Lexer L(SourceLocation::getFileLoc(FileID, 0), PP.getLangOptions(), 236116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch File.first, File.second); 237116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 238116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // Inform the preprocessor that we want to retain comments as tokens, so we 239116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // can highlight them. 240116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch //PP.SetCommentRetentionState(true, false); 241116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 242116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // Lex all the tokens in raw mode, to avoid entering #includes or expanding 243116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // macros. 244116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch Token Tok; 245116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch L.LexRawToken(Tok); 246116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 247116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch while (Tok.isNot(tok::eof)) { 248116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // Since we are lexing unexpanded tokens, all tokens are from the main 249116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // FileID. 250116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch unsigned TokOffs = SourceMgr.getFullFilePos(Tok.getLocation()); 251a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) unsigned TokLen = Tok.getLength(); 252a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) switch (Tok.getKind()) { 253116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch default: break; 254116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch case tok::identifier: { 255116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // Fill in Result.IdentifierInfo, looking up the identifier in the 256116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // identifier table. 257116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch IdentifierInfo *II = PP.LookUpIdentifierInfo(Tok, BufferStart+TokOffs); 258a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 259a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // If this is a pp-identifier, for a keyword, highlight it as such. 260a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (II->getTokenID() != tok::identifier) { 261a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) RB.InsertTextAfter(TokOffs, "<span class='keyword'>", 262a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) strlen("<span class='keyword'>")); 2635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) RB.InsertTextBefore(TokOffs+TokLen, "</span>", strlen("</span>")); 2645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 2655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) break; 2665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 2675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) case tok::comment: 2685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) RB.InsertTextAfter(TokOffs, "<span class='comment'>", 2695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) strlen("<span class='comment'>")); 2705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) RB.InsertTextBefore(TokOffs+TokLen, "</span>", strlen("</span>")); 2715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) break; 2725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) case tok::hash: 2735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // FIXME: This isn't working because we're not in raw mode in the lexer. 2745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Just cons up our own lexer here? 2755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // If this is a preprocessor directive, all tokens to end of line are too. 2775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (Tok.isAtStartOfLine()) { 2785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) RB.InsertTextAfter(TokOffs, "<span class='directive'>", 2795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) strlen("<span class='directive'>")); 2805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Find end of line. This is a hack. 2815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const char *LineEnd = SourceMgr.getCharacterData(Tok.getLocation()); 2825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) unsigned TokEnd = TokOffs+strcspn(LineEnd, "\n\r"); 2835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) RB.InsertTextBefore(TokEnd, "</span>", strlen("</span>")); 2845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 2855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) break; 2865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 2875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) L.LexRawToken(Tok); 2895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 2905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 2915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)/// HighlightMacros - This uses the macro table state from the end of the 2935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)/// file, to reexpand macros and insert (into the HTML) information about the 2945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)/// macro expansions. This won't be perfectly perfect, but it will be 295a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)/// reasonably close. 2965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void html::HighlightMacros(Rewriter &R, unsigned FileID, Preprocessor &PP) { 2975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) RewriteBuffer &RB = R.getEditBuffer(FileID); 2985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 299cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // Inform the preprocessor that we don't want comments. 300cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) PP.SetCommentRetentionState(false, false); 3015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 3025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Start parsing the specified input file. 3035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) PP.EnterMainSourceFile(); 304116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 305116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // Lex all the tokens. 3065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const SourceManager &SourceMgr = PP.getSourceManager(); 3075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) Token Tok; 3085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) PP.Lex(Tok); 309a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) while (Tok.isNot(tok::eof)) { 310a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // Ignore non-macro tokens. 311a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (!Tok.getLocation().isMacroID()) { 312a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) PP.Lex(Tok); 3135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) continue; 3145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 3155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 3165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Ignore tokens whose logical location was not the main file. 3175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) SourceLocation LLoc = SourceMgr.getLogicalLoc(Tok.getLocation()); 3185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) std::pair<unsigned, unsigned> LLocInfo = 3195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) SourceMgr.getDecomposedFileLoc(LLoc); 3205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 3215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (LLocInfo.first != FileID) { 3225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) PP.Lex(Tok); 3235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) continue; 3245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 3255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 3265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Okay, we have the first token of a macro expansion: highlight the 3275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // instantiation. 3285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 3295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Get the size of current macro call itself. 3305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // FIXME: This should highlight the args of a function-like 3315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // macro, using a heuristic. 332a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) unsigned TokLen = Lexer::MeasureTokenLength(LLoc, SourceMgr); 3335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 3345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) unsigned TokOffs = LLocInfo.second; 335116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch RB.InsertTextAfter(TokOffs, "<span class='macro'>", 3365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) strlen("<span class='macro'>")); 3375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) RB.InsertTextBefore(TokOffs+TokLen, "</span>", strlen("</span>")); 3385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 3395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Okay, eat this token, getting the next one. 3405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) PP.Lex(Tok); 3415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 3425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Skip all the rest of the tokens that are part of this macro 3435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // instantiation. It would be really nice to pop up a window with all the 3445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // spelling of the tokens or something. 3455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) while (!Tok.is(tok::eof) && 3465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) SourceMgr.getLogicalLoc(Tok.getLocation()) == LLoc) 3475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) PP.Lex(Tok); 348a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 3495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 3505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 3515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 3525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)