blob: 3e0d71a5b6d09cdcc52d3ad26c9559217cf4384c [file] [log] [blame]
Ted Kremenek6a340832008-03-18 21:19:49 +00001//== HTMLRewrite.cpp - Translate source code into prettified HTML --*- C++ -*-//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file defines the HTMLRewriter clas, which is used to translate the
11// text of a source file into prettified HTML.
12//
13//===----------------------------------------------------------------------===//
14
15#include "clang/Rewrite/Rewriter.h"
16#include "clang/Rewrite/HTMLRewrite.h"
17#include "clang/Basic/SourceManager.h"
18#include "llvm/Support/MemoryBuffer.h"
19#include <sstream>
20
21using namespace clang;
22
Ted Kremenekfa5be362008-04-08 22:37:58 +000023void html::EscapeText(Rewriter& R, unsigned FileID,
24 bool EscapeSpaces, bool ReplaceTabs) {
Ted Kremenek6a340832008-03-18 21:19:49 +000025
26 const llvm::MemoryBuffer *Buf = R.getSourceMgr().getBuffer(FileID);
27 const char* C = Buf->getBufferStart();
28 const char* FileEnd = Buf->getBufferEnd();
29
30 assert (C <= FileEnd);
31
32 for (unsigned FilePos = 0; C != FileEnd ; ++C, ++FilePos) {
Ted Kremenek49cd6352008-04-03 07:12:29 +000033
Ted Kremenek6a340832008-03-18 21:19:49 +000034 switch (*C) {
35 default: break;
36
37 case ' ':
Ted Kremenek49cd6352008-04-03 07:12:29 +000038 if (EscapeSpaces) {
39 SourceLocation Loc = SourceLocation::getFileLoc(FileID, FilePos);
40 R.ReplaceText(Loc, 1, "&nbsp;", 6);
41 }
Ted Kremenek6a340832008-03-18 21:19:49 +000042 break;
43
Ted Kremenek49cd6352008-04-03 07:12:29 +000044 case '\t': {
Ted Kremenekfa5be362008-04-08 22:37:58 +000045 if (!ReplaceTabs)
46 break;
47
Ted Kremenek49cd6352008-04-03 07:12:29 +000048 SourceLocation Loc = SourceLocation::getFileLoc(FileID, FilePos);
Ted Kremenek4ce32cb2008-04-08 22:28:15 +000049
50 if (EscapeSpaces)
51 R.ReplaceText(Loc, 1, "&nbsp;&nbsp;&nbsp;&nbsp;", 6*4);
52 else
53 R.ReplaceText(Loc, 1, " ", 4);
54
Ted Kremenek49cd6352008-04-03 07:12:29 +000055 break;
56 }
57
58 case '<': {
59 SourceLocation Loc = SourceLocation::getFileLoc(FileID, FilePos);
60 R.ReplaceText(Loc, 1, "&lt;", 4);
61 break;
62 }
63
64 case '>': {
65 SourceLocation Loc = SourceLocation::getFileLoc(FileID, FilePos);
66 R.ReplaceText(Loc, 1, "&gt;", 4);
67 break;
68 }
69
70 case '&': {
71 SourceLocation Loc = SourceLocation::getFileLoc(FileID, FilePos);
72 R.ReplaceText(Loc, 1, "&amp;", 5);
73 break;
74 }
Ted Kremenek6a340832008-03-18 21:19:49 +000075 }
76 }
77}
78
Ted Kremenekfa5be362008-04-08 22:37:58 +000079std::string html::EscapeText(const std::string& s, bool EscapeSpaces,
80 bool ReplaceTabs) {
Ted Kremenek053ef592008-03-27 17:15:29 +000081
82 unsigned len = s.size();
83 std::ostringstream os;
84
85 for (unsigned i = 0 ; i < len; ++i) {
86
87 char c = s[i];
88
89 switch (c) {
90 default:
91 os << c; break;
92
93 case ' ':
Ted Kremenek8fb00162008-03-31 23:14:05 +000094 if (EscapeSpaces) os << "&nbsp;";
Ted Kremenek487f8272008-03-27 17:28:58 +000095 else os << ' ';
Ted Kremenek053ef592008-03-27 17:15:29 +000096 break;
97
Ted Kremenekfa5be362008-04-08 22:37:58 +000098 case '\t':
99 if (ReplaceTabs)
100 for (unsigned i = 0; i < 4; ++i) os << "&nbsp;";
101 else os << c;
102
103 break;
104
Ted Kremenek053ef592008-03-27 17:15:29 +0000105 case '<': os << "&lt;"; break;
106 case '>': os << "&gt;"; break;
107 case '&': os << "&amp;"; break;
108 }
109 }
110
111 return os.str();
112}
113
Ted Kremenekb485cd12008-03-18 23:08:51 +0000114static void AddLineNumber(Rewriter& R, unsigned LineNo,
115 SourceLocation B, SourceLocation E) {
Ted Kremenekf8309972008-03-19 01:30:02 +0000116
Ted Kremenekb485cd12008-03-18 23:08:51 +0000117 std::ostringstream os;
Ted Kremenek356708c2008-04-07 23:53:30 +0000118 os << "<tr><td class=\"num\" id=\"LN" << LineNo << "\">"
119 << LineNo << "</td><td class=\"line\">";
Ted Kremenek13e479b2008-03-19 07:53:42 +0000120
Ted Kremenek49cd6352008-04-03 07:12:29 +0000121 if (B == E) { // Handle empty lines.
122 os << " </td></tr>";
123 R.InsertStrBefore(B, os.str());
124 }
125 else {
126 R.InsertStrBefore(B, os.str());
127 R.InsertCStrBefore(E, "</td></tr>");
128 }
Ted Kremenekb485cd12008-03-18 23:08:51 +0000129}
130
131void html::AddLineNumbers(Rewriter& R, unsigned FileID) {
132
133 const llvm::MemoryBuffer *Buf = R.getSourceMgr().getBuffer(FileID);
134 const char* FileBeg = Buf->getBufferStart();
135 const char* FileEnd = Buf->getBufferEnd();
136 const char* C = FileBeg;
137
138 assert (C <= FileEnd);
139
140 unsigned LineNo = 0;
141 unsigned FilePos = 0;
142
143 while (C != FileEnd) {
144
145 ++LineNo;
146 unsigned LineStartPos = FilePos;
147 unsigned LineEndPos = FileEnd - FileBeg;
148
149 assert (FilePos <= LineEndPos);
150 assert (C < FileEnd);
151
152 // Scan until the newline (or end-of-file).
153
Ted Kremenek49cd6352008-04-03 07:12:29 +0000154 while (C != FileEnd) {
155 char c = *C;
156 ++C;
157
158 if (c == '\n') {
159 LineEndPos = FilePos++;
Ted Kremenekb485cd12008-03-18 23:08:51 +0000160 break;
161 }
Ted Kremenek49cd6352008-04-03 07:12:29 +0000162
163 ++FilePos;
164 }
Ted Kremenekb485cd12008-03-18 23:08:51 +0000165
166 AddLineNumber(R, LineNo,
167 SourceLocation::getFileLoc(FileID, LineStartPos),
Ted Kremenek49cd6352008-04-03 07:12:29 +0000168 SourceLocation::getFileLoc(FileID, LineEndPos));
Ted Kremenekd6c13602008-03-19 05:07:26 +0000169 }
170
171 // Add one big div tag that surrounds all of the code.
172
173 R.InsertCStrBefore(SourceLocation::getFileLoc(FileID, 0),
Ted Kremeneke8e019e2008-03-19 21:59:05 +0000174 "<table class=\"code\">\n");
Ted Kremenekd6c13602008-03-19 05:07:26 +0000175
176 R.InsertCStrAfter(SourceLocation::getFileLoc(FileID, FileEnd - FileBeg),
Ted Kremeneke8e019e2008-03-19 21:59:05 +0000177 "</table>");
Ted Kremenekb485cd12008-03-18 23:08:51 +0000178}
Ted Kremenekad0a2032008-03-19 06:14:37 +0000179
180void html::AddHeaderFooterInternalBuiltinCSS(Rewriter& R, unsigned FileID) {
181
182 const llvm::MemoryBuffer *Buf = R.getSourceMgr().getBuffer(FileID);
183 const char* FileStart = Buf->getBufferStart();
184 const char* FileEnd = Buf->getBufferEnd();
185
186 SourceLocation StartLoc = SourceLocation::getFileLoc(FileID, 0);
187 SourceLocation EndLoc = SourceLocation::getFileLoc(FileID, FileEnd-FileStart);
188
189 // Generate header
190
191 {
192 std::ostringstream os;
193
194 os << "<html>\n<head>\n"
Ted Kremenekeeacc522008-03-19 22:44:21 +0000195 << "<style type=\"text/css\">\n"
196 << " body { color:#000000; background-color:#ffffff }\n"
Ted Kremenek487f8272008-03-27 17:28:58 +0000197 << " body { font-family:Helvetica, sans-serif; font-size:10pt }\n"
198 << " h1 { font-size:12pt }\n"
Ted Kremeneke8e019e2008-03-19 21:59:05 +0000199 << " .code { border-spacing:0px; width:100%; }\n"
Chris Lattner6ccb91a2008-04-06 04:37:21 +0000200 << " .code { font-family: \"Andale Mono\", monospace; font-size:10pt }\n"
Ted Kremeneke8e019e2008-03-19 21:59:05 +0000201 << " .code { line-height: 1.2em }\n"
202 << " .num { width:2.5em; padding-right:2ex; background-color:#eeeeee }\n"
203 << " .num { text-align:right; font-size: smaller }\n"
Ted Kremenek0f1b67b2008-03-19 23:55:53 +0000204 << " .num { color:#444444 }\n"
Ted Kremeneke8e019e2008-03-19 21:59:05 +0000205 << " .line { padding-left: 1ex; border-left: 3px solid #ccc }\n"
206 << " .line { white-space: pre }\n"
Ted Kremenek7e54eed2008-04-07 23:43:44 +0000207 << " .msg { background-color:#fff8b4; color:#000000 }\n"
Ted Kremenek9d4e6592008-03-24 23:38:32 +0000208 << " .msg { -webkit-box-shadow:1px 1px 7px #000 }\n"
209 << " .msg { -webkit-border-radius:5px }\n"
Ted Kremeneke8e019e2008-03-19 21:59:05 +0000210 << " .msg { font-family:Helvetica, sans-serif; font-size: smaller }\n"
Ted Kremenekdb87ca02008-03-19 22:06:25 +0000211 << " .msg { font-weight: bold }\n"
Ted Kremeneke8e019e2008-03-19 21:59:05 +0000212 << " .msg { float:left }\n"
Ted Kremenekeeacc522008-03-19 22:44:21 +0000213 << " .msg { padding:0.5em 1ex 0.5em 1ex }\n"
214 << " .msg { margin-top:10px; margin-bottom:10px }\n"
Ted Kremenekf23621f2008-04-02 21:14:04 +0000215 << " .mrange { background-color:#dfddf3 }\n"
Ted Kremenek9e628a02008-04-02 22:50:50 +0000216 << " .mrange { border-bottom:1px solid #6F9DBE }\n"
Ted Kremenek718ceb12008-04-02 21:04:20 +0000217 << " .PathIndex { font-weight: bold }\n"
Ted Kremeneke8e019e2008-03-19 21:59:05 +0000218 << "</style>\n</head>\n<body>";
Ted Kremenekad0a2032008-03-19 06:14:37 +0000219
220 R.InsertStrBefore(StartLoc, os.str());
221 }
222
223 // Generate footer
224
225 {
226 std::ostringstream os;
227
228 os << "</body></html>\n";
229 R.InsertStrAfter(EndLoc, os.str());
230 }
231}
232
233