@@ -50,10 +50,20 @@ static void writeHeader(const Twine &Text, unsigned int Num, raw_ostream &OS) {
50
50
OS << std::string (Num, ' #' ) + " " + Text << " \n\n " ;
51
51
}
52
52
53
- static void writeFileDefinition (const Location &L, raw_ostream &OS) {
54
- OS << genItalic (" Defined at line " + std::to_string (L.LineNumber ) + " of " +
55
- L.Filename )
56
- << " \n\n " ;
53
+ static void writeFileDefinition (const ClangDocContext &CDCtx, const Location &L,
54
+ raw_ostream &OS) {
55
+
56
+ if (!CDCtx.RepositoryUrl ) {
57
+ OS << " *Defined at " << L.Filename << " #" << std::to_string (L.LineNumber )
58
+ << " *" ;
59
+ } else {
60
+ OS << " *Defined at [" << L.Filename << " #" << std::to_string (L.LineNumber )
61
+ << " ](" << StringRef{CDCtx.RepositoryUrl .getValue ()}
62
+ << llvm::sys::path::relative_path (L.Filename ) << " #"
63
+ << std::to_string (L.LineNumber ) << " )"
64
+ << " *" ;
65
+ }
66
+ OS << " \n\n " ;
57
67
}
58
68
59
69
static void writeDescription (const CommentInfo &I, raw_ostream &OS) {
@@ -104,7 +114,18 @@ static void writeDescription(const CommentInfo &I, raw_ostream &OS) {
104
114
}
105
115
}
106
116
107
- static void genMarkdown (const EnumInfo &I, llvm::raw_ostream &OS) {
117
+ static void writeNameLink (const StringRef &CurrentPath, const Reference &R,
118
+ llvm::raw_ostream &OS) {
119
+ llvm::SmallString<64 > Path = R.getRelativeFilePath (CurrentPath);
120
+ // Paths in Markdown use POSIX separators.
121
+ llvm::sys::path::native (Path, llvm::sys::path::Style ::posix);
122
+ llvm::sys::path::append (Path, llvm::sys::path::Style ::posix,
123
+ R.getFileBaseName () + " .md" );
124
+ OS << " [" << R.Name << " ](" << Path << " )" ;
125
+ }
126
+
127
+ static void genMarkdown (const ClangDocContext &CDCtx, const EnumInfo &I,
128
+ llvm::raw_ostream &OS) {
108
129
if (I.Scoped )
109
130
writeLine (" | enum class " + I.Name + " |" , OS);
110
131
else
@@ -118,13 +139,14 @@ static void genMarkdown(const EnumInfo &I, llvm::raw_ostream &OS) {
118
139
Members << " | " << N << " |\n " ;
119
140
writeLine (Members.str (), OS);
120
141
if (I.DefLoc )
121
- writeFileDefinition (I.DefLoc .getValue (), OS);
142
+ writeFileDefinition (CDCtx, I.DefLoc .getValue (), OS);
122
143
123
144
for (const auto &C : I.Description )
124
145
writeDescription (C, OS);
125
146
}
126
147
127
- static void genMarkdown (const FunctionInfo &I, llvm::raw_ostream &OS) {
148
+ static void genMarkdown (const ClangDocContext &CDCtx, const FunctionInfo &I,
149
+ llvm::raw_ostream &OS) {
128
150
std::string Buffer;
129
151
llvm::raw_string_ostream Stream (Buffer);
130
152
bool First = true ;
@@ -145,13 +167,14 @@ static void genMarkdown(const FunctionInfo &I, llvm::raw_ostream &OS) {
145
167
Stream.str () + " )" ),
146
168
OS);
147
169
if (I.DefLoc )
148
- writeFileDefinition (I.DefLoc .getValue (), OS);
170
+ writeFileDefinition (CDCtx, I.DefLoc .getValue (), OS);
149
171
150
172
for (const auto &C : I.Description )
151
173
writeDescription (C, OS);
152
174
}
153
175
154
- static void genMarkdown (const NamespaceInfo &I, llvm::raw_ostream &OS) {
176
+ static void genMarkdown (const ClangDocContext &CDCtx, const NamespaceInfo &I,
177
+ llvm::raw_ostream &OS) {
155
178
if (I.Name == " " )
156
179
writeHeader (" Global Namespace" , 1 , OS);
157
180
else
@@ -164,36 +187,47 @@ static void genMarkdown(const NamespaceInfo &I, llvm::raw_ostream &OS) {
164
187
writeNewLine (OS);
165
188
}
166
189
190
+ llvm::SmallString<64 > BasePath = I.getRelativeFilePath (" " );
191
+
167
192
if (!I.ChildNamespaces .empty ()) {
168
193
writeHeader (" Namespaces" , 2 , OS);
169
- for (const auto &R : I.ChildNamespaces )
170
- writeLine (R.Name , OS);
194
+ for (const auto &R : I.ChildNamespaces ) {
195
+ OS << " * " ;
196
+ writeNameLink (BasePath, R, OS);
197
+ OS << " \n " ;
198
+ }
171
199
writeNewLine (OS);
172
200
}
201
+
173
202
if (!I.ChildRecords .empty ()) {
174
203
writeHeader (" Records" , 2 , OS);
175
- for (const auto &R : I.ChildRecords )
176
- writeLine (R.Name , OS);
204
+ for (const auto &R : I.ChildRecords ) {
205
+ OS << " * " ;
206
+ writeNameLink (BasePath, R, OS);
207
+ OS << " \n " ;
208
+ }
177
209
writeNewLine (OS);
178
210
}
211
+
179
212
if (!I.ChildFunctions .empty ()) {
180
213
writeHeader (" Functions" , 2 , OS);
181
214
for (const auto &F : I.ChildFunctions )
182
- genMarkdown (F, OS);
215
+ genMarkdown (CDCtx, F, OS);
183
216
writeNewLine (OS);
184
217
}
185
218
if (!I.ChildEnums .empty ()) {
186
219
writeHeader (" Enums" , 2 , OS);
187
220
for (const auto &E : I.ChildEnums )
188
- genMarkdown (E, OS);
221
+ genMarkdown (CDCtx, E, OS);
189
222
writeNewLine (OS);
190
223
}
191
224
}
192
225
193
- static void genMarkdown (const RecordInfo &I, llvm::raw_ostream &OS) {
226
+ static void genMarkdown (const ClangDocContext &CDCtx, const RecordInfo &I,
227
+ llvm::raw_ostream &OS) {
194
228
writeHeader (getTagType (I.TagType ) + " " + I.Name , 1 , OS);
195
229
if (I.DefLoc )
196
- writeFileDefinition (I.DefLoc .getValue (), OS);
230
+ writeFileDefinition (CDCtx, I.DefLoc .getValue (), OS);
197
231
198
232
if (!I.Description .empty ()) {
199
233
for (const auto &C : I.Description )
@@ -234,24 +268,94 @@ static void genMarkdown(const RecordInfo &I, llvm::raw_ostream &OS) {
234
268
if (!I.ChildFunctions .empty ()) {
235
269
writeHeader (" Functions" , 2 , OS);
236
270
for (const auto &F : I.ChildFunctions )
237
- genMarkdown (F, OS);
271
+ genMarkdown (CDCtx, F, OS);
238
272
writeNewLine (OS);
239
273
}
240
274
if (!I.ChildEnums .empty ()) {
241
275
writeHeader (" Enums" , 2 , OS);
242
276
for (const auto &E : I.ChildEnums )
243
- genMarkdown (E, OS);
277
+ genMarkdown (CDCtx, E, OS);
244
278
writeNewLine (OS);
245
279
}
246
280
}
247
281
282
+ static void serializeReference (llvm::raw_fd_ostream &OS, Index &I, int Level) {
283
+ // Write out the heading level starting at ##
284
+ OS << " ##" << std::string (Level, ' #' ) << " " ;
285
+ writeNameLink (" " , I, OS);
286
+ OS << " \n " ;
287
+ }
288
+
289
+ static llvm::Error serializeIndex (ClangDocContext &CDCtx) {
290
+ std::error_code FileErr;
291
+ llvm::SmallString<128 > FilePath;
292
+ llvm::sys::path::native (CDCtx.OutDirectory , FilePath);
293
+ llvm::sys::path::append (FilePath, " all_files.md" );
294
+ llvm::raw_fd_ostream OS (FilePath, FileErr, llvm::sys::fs::OF_None);
295
+ if (FileErr)
296
+ return llvm::createStringError (llvm::inconvertibleErrorCode (),
297
+ " error creating index file: " +
298
+ FileErr.message ());
299
+
300
+ CDCtx.Idx .sort ();
301
+ OS << " # All Files" ;
302
+ if (!CDCtx.ProjectName .empty ())
303
+ OS << " for " << CDCtx.ProjectName ;
304
+ OS << " \n\n " ;
305
+
306
+ for (auto C : CDCtx.Idx .Children )
307
+ serializeReference (OS, C, 0 );
308
+
309
+ return llvm::Error::success ();
310
+ }
311
+
312
+ static llvm::Error genIndex (ClangDocContext &CDCtx) {
313
+ std::error_code FileErr;
314
+ llvm::SmallString<128 > FilePath;
315
+ llvm::sys::path::native (CDCtx.OutDirectory , FilePath);
316
+ llvm::sys::path::append (FilePath, " index.md" );
317
+ llvm::raw_fd_ostream OS (FilePath, FileErr, llvm::sys::fs::OF_None);
318
+ if (FileErr)
319
+ return llvm::createStringError (llvm::inconvertibleErrorCode (),
320
+ " error creating index file: " +
321
+ FileErr.message ());
322
+ CDCtx.Idx .sort ();
323
+ OS << " # " << CDCtx.ProjectName << " C/C++ Reference\n\n " ;
324
+ for (auto C : CDCtx.Idx .Children ) {
325
+ if (!C.Children .empty ()) {
326
+ const char *Type;
327
+ switch (C.RefType ) {
328
+ case InfoType::IT_namespace:
329
+ Type = " Namespace" ;
330
+ break ;
331
+ case InfoType::IT_record:
332
+ Type = " Type" ;
333
+ break ;
334
+ case InfoType::IT_enum:
335
+ Type = " Enum" ;
336
+ break ;
337
+ case InfoType::IT_function:
338
+ Type = " Function" ;
339
+ break ;
340
+ case InfoType::IT_default:
341
+ Type = " Other" ;
342
+ }
343
+ OS << " * " << Type << " : [" << C.Name << " ](" ;
344
+ if (!C.Path .empty ())
345
+ OS << C.Path << " /" ;
346
+ OS << C.Name << " )\n " ;
347
+ }
348
+ }
349
+ return llvm::Error::success ();
350
+ }
248
351
// / Generator for Markdown documentation.
249
352
class MDGenerator : public Generator {
250
353
public:
251
354
static const char *Format;
252
355
253
356
llvm::Error generateDocForInfo (Info *I, llvm::raw_ostream &OS,
254
357
const ClangDocContext &CDCtx) override ;
358
+ llvm::Error createResources (ClangDocContext &CDCtx) override ;
255
359
};
256
360
257
361
const char *MDGenerator::Format = " md" ;
@@ -260,16 +364,16 @@ llvm::Error MDGenerator::generateDocForInfo(Info *I, llvm::raw_ostream &OS,
260
364
const ClangDocContext &CDCtx) {
261
365
switch (I->IT ) {
262
366
case InfoType::IT_namespace:
263
- genMarkdown (*static_cast <clang::doc::NamespaceInfo *>(I), OS);
367
+ genMarkdown (CDCtx, *static_cast <clang::doc::NamespaceInfo *>(I), OS);
264
368
break ;
265
369
case InfoType::IT_record:
266
- genMarkdown (*static_cast <clang::doc::RecordInfo *>(I), OS);
370
+ genMarkdown (CDCtx, *static_cast <clang::doc::RecordInfo *>(I), OS);
267
371
break ;
268
372
case InfoType::IT_enum:
269
- genMarkdown (*static_cast <clang::doc::EnumInfo *>(I), OS);
373
+ genMarkdown (CDCtx, *static_cast <clang::doc::EnumInfo *>(I), OS);
270
374
break ;
271
375
case InfoType::IT_function:
272
- genMarkdown (*static_cast <clang::doc::FunctionInfo *>(I), OS);
376
+ genMarkdown (CDCtx, *static_cast <clang::doc::FunctionInfo *>(I), OS);
273
377
break ;
274
378
case InfoType::IT_default:
275
379
return createStringError (llvm::inconvertibleErrorCode (),
@@ -278,11 +382,25 @@ llvm::Error MDGenerator::generateDocForInfo(Info *I, llvm::raw_ostream &OS,
278
382
return llvm::Error::success ();
279
383
}
280
384
385
+ llvm::Error MDGenerator::createResources (ClangDocContext &CDCtx) {
386
+ // Write an all_files.md
387
+ auto Err = serializeIndex (CDCtx);
388
+ if (Err)
389
+ return Err;
390
+
391
+ // Generate the index page.
392
+ Err = genIndex (CDCtx);
393
+ if (Err)
394
+ return Err;
395
+
396
+ return llvm::Error::success ();
397
+ }
398
+
281
399
static GeneratorRegistry::Add<MDGenerator> MD (MDGenerator::Format,
282
400
" Generator for MD output." );
283
401
284
- // This anchor is used to force the linker to link in the generated object file
285
- // and thus register the generator.
402
+ // This anchor is used to force the linker to link in the generated object
403
+ // file and thus register the generator.
286
404
volatile int MDGeneratorAnchorSource = 0 ;
287
405
288
406
} // namespace doc
0 commit comments