blob: dcbf181980882f8a2541dbc7d1d87bb486750de0 [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
23void html::EscapeText(Rewriter& R, unsigned FileID, bool EscapeSpaces) {
24
25 const llvm::MemoryBuffer *Buf = R.getSourceMgr().getBuffer(FileID);
26 const char* C = Buf->getBufferStart();
27 const char* FileEnd = Buf->getBufferEnd();
28
29 assert (C <= FileEnd);
30
31 for (unsigned FilePos = 0; C != FileEnd ; ++C, ++FilePos) {
32
33 SourceLocation Loc = SourceLocation::getFileLoc(FileID, FilePos);
34
35 switch (*C) {
36 default: break;
37
38 case ' ':
39 if (EscapeSpaces) R.ReplaceText(Loc, 1, "&#32;", 5);
40 break;
41
42 case '<': R.ReplaceText(Loc, 1, "&lt;", 4); break;
43 case '>': R.ReplaceText(Loc, 1, "&gt;", 4); break;
44 case '&': R.ReplaceText(Loc, 1, "&amp;", 5); break;
45 }
46 }
47}
48
Ted Kremenekb485cd12008-03-18 23:08:51 +000049static void AddLineNumber(Rewriter& R, unsigned LineNo,
50 SourceLocation B, SourceLocation E) {
Ted Kremenekf8309972008-03-19 01:30:02 +000051
Ted Kremenekd6c13602008-03-19 05:07:26 +000052 // Surround the line text with a div tag.
Ted Kremenek13e479b2008-03-19 07:53:42 +000053
54 R.InsertCStrBefore(E, "</div>");
Ted Kremenekb485cd12008-03-18 23:08:51 +000055
Ted Kremenekd6c13602008-03-19 05:07:26 +000056 if (B == E) // Handle empty lines.
57 R.InsertCStrBefore(B, "<div class=\"lines\"> </div>");
58 else {
59 R.InsertCStrBefore(E, "</div>");
60 R.InsertCStrBefore(B, "<div class=\"lines\">");
61 }
Ted Kremenekf8309972008-03-19 01:30:02 +000062
Ted Kremenekd6c13602008-03-19 05:07:26 +000063 // Insert a div tag for the line number.
64
Ted Kremenekb485cd12008-03-18 23:08:51 +000065 std::ostringstream os;
Ted Kremenekd6c13602008-03-19 05:07:26 +000066 os << "<div class=\"nums\">" << LineNo << "</div>";
67
68 R.InsertStrBefore(B, os.str());
69
70 // Now surround the whole line with another div tag.
71
72 R.InsertCStrBefore(B, "<div class=\"codeline\">");
Ted Kremenek13e479b2008-03-19 07:53:42 +000073
Ted Kremenekb485cd12008-03-18 23:08:51 +000074}
75
76void html::AddLineNumbers(Rewriter& R, unsigned FileID) {
77
78 const llvm::MemoryBuffer *Buf = R.getSourceMgr().getBuffer(FileID);
79 const char* FileBeg = Buf->getBufferStart();
80 const char* FileEnd = Buf->getBufferEnd();
81 const char* C = FileBeg;
82
83 assert (C <= FileEnd);
84
85 unsigned LineNo = 0;
86 unsigned FilePos = 0;
87
88 while (C != FileEnd) {
89
90 ++LineNo;
91 unsigned LineStartPos = FilePos;
92 unsigned LineEndPos = FileEnd - FileBeg;
93
94 assert (FilePos <= LineEndPos);
95 assert (C < FileEnd);
96
97 // Scan until the newline (or end-of-file).
98
99 for ( ; C != FileEnd ; ++C, ++FilePos)
100 if (*C == '\n') {
101 LineEndPos = FilePos;
102 break;
103 }
104
105 AddLineNumber(R, LineNo,
106 SourceLocation::getFileLoc(FileID, LineStartPos),
107 SourceLocation::getFileLoc(FileID, LineEndPos));
108
109 if (C != FileEnd) {
110 ++C;
111 ++FilePos;
112 }
Ted Kremenekd6c13602008-03-19 05:07:26 +0000113 }
114
115 // Add one big div tag that surrounds all of the code.
116
117 R.InsertCStrBefore(SourceLocation::getFileLoc(FileID, 0),
118 "<div id=\"codeblock\">");
119
120 R.InsertCStrAfter(SourceLocation::getFileLoc(FileID, FileEnd - FileBeg),
121 "</div>");
Ted Kremenekb485cd12008-03-18 23:08:51 +0000122}
Ted Kremenekad0a2032008-03-19 06:14:37 +0000123
124void html::AddHeaderFooterInternalBuiltinCSS(Rewriter& R, unsigned FileID) {
125
126 const llvm::MemoryBuffer *Buf = R.getSourceMgr().getBuffer(FileID);
127 const char* FileStart = Buf->getBufferStart();
128 const char* FileEnd = Buf->getBufferEnd();
129
130 SourceLocation StartLoc = SourceLocation::getFileLoc(FileID, 0);
131 SourceLocation EndLoc = SourceLocation::getFileLoc(FileID, FileEnd-FileStart);
132
133 // Generate header
134
135 {
136 std::ostringstream os;
137
138 os << "<html>\n<head>\n"
139 << " <style type=\"text/css\">\n"
140 << " .codeblock { width:100% }\n"
141 << " .codeline { font-family: \"Andale Mono\", fixed; font-size:10pt }\n"
142 << " .codeline { height:1.5em; line-height:1.5em }\n"
143 << " .nums, .lines { float:left; height:100% }\n"
144 << " .nums { background-color: #eeeeee }\n"
145 << " .nums { font-size:smaller }\n"
Ted Kremenek13e479b2008-03-19 07:53:42 +0000146 << " .nums { width:2.5em; padding-right:2ex; text-align:right }\n"
Ted Kremenekad0a2032008-03-19 06:14:37 +0000147 << " .lines { padding-left: 1ex; border-left: 3px solid #ccc }\n"
148 << " .lines { white-space: pre }\n"
Ted Kremenek13e479b2008-03-19 07:53:42 +0000149 << " .msg { background-color:#fcff4c; float:left }\n"
150 << " .msg { font-family:Helvetica, sans-serif; font-size: smaller }\n"
151 << " .msg { padding:5px; margin-top:10px; margin-bottom:10px }\n"
Ted Kremenekad0a2032008-03-19 06:14:37 +0000152 << " </style>\n"
153 << "</head>\n"
154 << "<body>";
155
156 R.InsertStrBefore(StartLoc, os.str());
157 }
158
159 // Generate footer
160
161 {
162 std::ostringstream os;
163
164 os << "</body></html>\n";
165 R.InsertStrAfter(EndLoc, os.str());
166 }
167}
168
169