@@ -18,6 +18,8 @@ import std.algorithm, std.array, std.ascii, std.conv, std.file, std.format, std.
1818 std.meta , std.path , std.range , std.string , std.typecons ;
1919import std.stdio ;
2020
21+ import dmd.cli;
22+
2123struct Config
2224{
2325 string dmdBinPath = " dmd" ;
@@ -53,6 +55,7 @@ All unknown options are passed to the compiler.
5355 text = genGrammar(text);
5456 text = genHeader(text);
5557 text = genChangelogVersion(inputFile, text);
58+ text = genSwitches(text);
5659
5760 // inject custom, "dynamic" macros
5861 text ~= " \n SRC_FILENAME=%s\n " .format(inputFile.buildNormalizedPath);
@@ -277,3 +280,93 @@ auto genChangelogVersion(string fileName, string fileText)
277280 }
278281 return fileText;
279282}
283+
284+ // generate CLI documentation
285+ auto genSwitches (string fileText)
286+ {
287+ enum ddocKey = " $(CLI_SWITCHES" ;
288+ string content;
289+ foreach (option; Usage.options)
290+ {
291+ string flag = option.flag;
292+ string helpText = option.helpText;
293+
294+ // capitalize the first letter
295+ helpText = helpText.capitalize.to! string ;
296+
297+ highlightSpecialWords(flag, helpText);
298+ auto flagEndPos = flag.representation.countUntil(" =" , " $(" , " <" );
299+ string switchName;
300+ if (flagEndPos < 0 )
301+ switchName = " $(SWNAME -%s)" .format(flag);
302+ else
303+ switchName = " $(SWNAME -%s)%s" .format(flag[0 .. flagEndPos], flag[flagEndPos.. $]);
304+
305+ auto currentFlag = " $(SWITCH %s,\n
306+ %s
307+ )" .format(switchName, helpText);
308+
309+ with (TargetOS)
310+ switch (option.os)
311+ {
312+ case windows:
313+ currentFlag = text(" $(WINDOWS " , currentFlag, " )" );
314+ break ;
315+ case linux:
316+ case macOS:
317+ case freeBSD:
318+ case solaris:
319+ case dragonFlyBSD:
320+ currentFlag = text(" $(UNIX " , currentFlag, " )" );
321+ break ;
322+ case all:
323+ default :
324+ break ;
325+ }
326+ content ~= currentFlag;
327+ }
328+ return updateDdocTag (fileText, ddocKey, content);
329+ }
330+
331+ auto italic (string w)
332+ {
333+ return " $(I %s )" .format(w);
334+ }
335+
336+
337+ // capitalize the first letter
338+ auto capitalize (string w)
339+ {
340+ import std.range , std.uni ;
341+ return w.take(1 ).asUpperCase.chain(w.dropOne);
342+ }
343+
344+ private void highlightSpecialWords (ref string flag, ref string helpText)
345+ {
346+ if (flag.canFind(" <" , " [" ) && flag.canFind(" >" , " ]" ))
347+ {
348+ string specialWord;
349+
350+ // detect special words in <...> and highlight them
351+ static foreach (t; [[" <" , " >" ], [" [" , " ]" ]])
352+ {
353+ if (flag.canFind(t[0 ]))
354+ {
355+ specialWord = flag.findSplit(t[0 ])[2 ].until(t[1 ]).to! string ;
356+ // keep []
357+ auto replaceWord = t[0 ] == " <" ? t[0 ] ~ specialWord ~ t[1 ] : specialWord;
358+ flag = flag.replace(replaceWord, specialWord.italic);
359+ }
360+ }
361+
362+ // highlight individual words in the description
363+ helpText = helpText
364+ .splitter(" " )
365+ .map! ((w){
366+ auto wPlain = w.filter! (c => ! c.among(' <' , ' >' , ' `' , ' \' ' )).to! string ;
367+ return wPlain == specialWord ? wPlain.italic: w;
368+ })
369+ .joiner(" " )
370+ .to! string ;
371+ }
372+ }
0 commit comments