diff --git a/dub.json b/dub.json index 827fe657..58861d52 100644 --- a/dub.json +++ b/dub.json @@ -8,7 +8,7 @@ ], "dependencies": { "vibe-d": "~>0.7.22", - "libdparse": {"optional": true, "version": "~>0.2.0"}, + "libdparse": "~>0.4.0", "hyphenate": "~>1.1.0" }, "versions": ["JsonLineNumbers"], diff --git a/dub.selections.json b/dub.selections.json index 26aac340..0ccb75eb 100644 --- a/dub.selections.json +++ b/dub.selections.json @@ -4,8 +4,9 @@ "libevent": "2.0.1+2.0.16", "libev": "5.0.0+4.04", "openssl": "1.1.4+1.0.1g", - "libdparse": "0.2.1", - "memutils": "0.4.3", + "experimental_allocator": "2.70.0-b1", + "libdparse": "0.4.0", + "memutils": "0.4.4", "vibe-d": "0.7.26", "hyphenate": "1.1.0", "libasync": "0.7.5" diff --git a/public/prettify/prettify.css b/public/prettify/prettify.css index ef71722a..c0e08448 100644 --- a/public/prettify/prettify.css +++ b/public/prettify/prettify.css @@ -2,21 +2,22 @@ /* SPAN elements with the classes below are added by prettyprint. */ .pln { color: #222 } /* plain text */ -pre .pln, .prototype .pln { color: #ffffff } /* plain text */ +pre .pln, div.prototype .pln { color: #fff } /* plain text */ @media screen { pre .str { color: #ffe7b6 } /* string content */ pre .typ { color: #9ad452 } /* a type name */ pre .lit { color: #ffe7b6 } /* a literal value */ - pre .pun, .prototype .pun, .opn, .clo { color: #ddd } + pre .pun, div.prototype .pun { color: #fff } + .spc { color: #a0a } /* special token sequence */ .str { color: #842 } /* string content */ .kwd { color: #ffaa00 } /* a keyword */ .com { color: #888 } /* a comment */ .typ { color: #693 } /* a type name */ .lit { color: #875 } /* a literal value */ /* punctuation, lisp open bracket, lisp close bracket */ - .pun, .opn, .clo { color: #333 } + .pun, .opn, .clo { color: #222 } .tag { color: #ffaa00 } /* a markup tag name */ .atn { color: #9ad452 } /* a markup attribute name */ .atv { color: #ffe7b6 } /* a markup attribute value */ @@ -26,6 +27,7 @@ pre .pln, .prototype .pln { color: #ffffff } /* plain text */ /* Use higher contrast and text-weight for printable form. */ @media print, projection { + .spc { color: #606 } /* special token sequence */ .str { color: #060 } .kwd { color: #006; font-weight: bold } .com { color: #600; font-style: italic } @@ -38,7 +40,7 @@ pre .pln, .prototype .pln { color: #ffffff } /* plain text */ } /* Put a border around prettyprinted code snippets. */ -pre.prettyprint, pre.code, .prototype { +pre.prettyprint, pre.code, div.prototype { padding: 1em 0; background-color: #222; border: 1px solid black; diff --git a/public/prettify/prettify.js b/public/prettify/prettify.js deleted file mode 100644 index a6a62d72..00000000 --- a/public/prettify/prettify.js +++ /dev/null @@ -1 +0,0 @@ -var o=!0,r=null,A=!1;window.PR_SHOULD_USE_CONTINUATION=o; (function(){function O(a){function m(a){var f=a.charCodeAt(0);if(92!==f)return f;var b=a.charAt(1);return(f=s[b])?f:"0"<=b&&"7">=b?parseInt(a.substring(1),8):"u"===b||"x"===b?parseInt(a.substring(2),16):a.charCodeAt(1)}function e(a){if(32>a)return(16>a?"\\x0":"\\x")+a.toString(16);a=String.fromCharCode(a);if("\\"===a||"-"===a||"["===a||"]"===a)a="\\"+a;return a}function h(a){for(var f=a.substring(1,a.length-1).match(RegExp("\\\\u[0-9A-Fa-f]{4}|\\\\x[0-9A-Fa-f]{2}|\\\\[0-3][0-7]{0,2}|\\\\[0-7]{1,2}|\\\\[\\s\\S]|-|[^-\\\\]","g")), a=[],b=[],p="^"===f[0],c=p?1:0,i=f.length;cd||122d||90d||122i[0]&&(i[1]+1>i[0]&&b.push("-"),b.push(e(i[1])));b.push("]");return b.join("")}function z(a){for(var f=a.source.match(RegExp("(?:\\[(?:[^\\x5C\\x5D]|\\\\[\\s\\S])*\\]|\\\\u[A-Fa-f0-9]{4}|\\\\x[A-Fa-f0-9]{2}|\\\\[0-9]+|\\\\[^ux0-9]|\\(\\?[:!=]|[\\(\\)\\^]|[^\\x5B\\x5C\\(\\)\\^]+)","g")),b=f.length,d=[],c=0,i=0;c/,r])):m.push(["com",/^#[^\r\n]*/,r,"#"]));a.cStyleComments&&(e.push(["com",/^\/\/[^\r\n]*/,r]),e.push(["com",/^\/\*[\s\S]*?(?:\*\/|$)/,r]));a.regexLiterals&&e.push(["lang-regex",RegExp("^(?:^^\\.?|[+-]|\\!|\\!=|\\!==|\\#|\\%|\\%=|&|&&|&&=|&=|\\(|\\*|\\*=|\\+=|\\,|\\-=|\\->|\\/|\\/=|:|::|\\;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|\\?|\\@|\\[|\\^|\\^=|\\^\\^|\\^\\^=|\\{|\\||\\|=|\\|\\||\\|\\|=|\\~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\\s*(/(?=[^/*])(?:[^/\\x5B\\x5C]|\\x5C[\\s\\S]|\\x5B(?:[^\\x5C\\x5D]|\\x5C[\\s\\S])*(?:\\x5D|$))+/)")]); (h=a.types)&&e.push(["typ",h]);a=(""+a.keywords).replace(/^ | $/g,"");a.length&&e.push(["kwd",RegExp("^(?:"+a.replace(/[\s,]+/g,"|")+")\\b"),r]);m.push(["pln",/^\s+/,r," \r\n\t\u00a0"]);e.push(["lit",/^@[a-z_$][a-z_$@0-9]*/i,r],["typ",/^(?:[@_]?[A-Z]+[a-z][A-Za-z_$@0-9]*|\w+_t\b)/,r],["pln",/^[a-z_$][a-z_$@0-9]*/i,r],["lit",/^(?:0x[a-f0-9]+|(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d\+)(?:e[+\-]?\d+)?)[a-z]*/i,r,"0123456789"],["pln",/^\\[\s\S]?/,r],["pun",/^.[^\s\w\.$@\'\"\`\/\#\\]*/,r]);return x(m,e)}function F(a, m){function e(a){switch(a.nodeType){case 1:if(k.test(a.className))break;if("BR"===a.nodeName)h(a),a.parentNode&&a.parentNode.removeChild(a);else for(a=a.firstChild;a;a=a.nextSibling)e(a);break;case 3:case 4:if(q){var b=a.nodeValue,d=b.match(u);if(d){var c=b.substring(0,d.index);a.nodeValue=c;(b=b.substring(d.index+d[0].length))&&a.parentNode.insertBefore(t.createTextNode(b),a.nextSibling);h(a);c||a.parentNode.removeChild(a)}}}}function h(a){function b(a,d){var e=d?a.cloneNode(A):a,f=a.parentNode; if(f){var f=b(f,1),g=a.nextSibling;f.appendChild(e);for(var h=g;h;h=g)g=h.nextSibling,f.appendChild(h)}return e}for(;!a.nextSibling;)if(a=a.parentNode,!a)return;for(var a=b(a.nextSibling,0),e;(e=a.parentNode)&&1===e.nodeType;)a=e;d.push(a)}var k=/(?:^|\s)nocode(?:\s|$)/,u=/\r\n?|\n/,t=a.ownerDocument,l;a.currentStyle?l=a.currentStyle.whiteSpace:window.getComputedStyle&&(l=t.defaultView.getComputedStyle(a,r).getPropertyValue("white-space"));var q=l&&"pre"===l.substring(0,3);for(l=t.createElement("LI");a.firstChild;)l.appendChild(a.firstChild); for(var d=[l],g=0;g=p&&(h+=2);e>=c&&(a+=2)}}catch(x){"console"in window&&console.log(x&&x.stack?x.stack:x)}}var w=["break,continue,do,else,for,if,return,while"],y=[[w,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"], "catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"],H=[y,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"],I=[y,"alias,align,asm,bool,cast,export,foreach,foreach_reverse,import,interface,module,null,assert,template,typeid,byte,ubyte,ushort,uint,ulong"], J=[y,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"],K=[J,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"],y=[y,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"],L= [w,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"],M=[w,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"],w=[w,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"],N=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/, Q=/\S/,R=v({keywords:[H,I,K,y,"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END"+L,M,w],hashComments:o,cStyleComments:o,multiLineStrings:o,regexLiterals:o}),C={};k(R,["default-code"]);k(x([],[["pln",/^[^]*(?:>|$)/],["com",/^<\!--[\s\S]*?(?:-\->|$)/],["lang-",/^<\?([\s\S]+?)(?:\?>|$)/],["lang-",/^<%([\s\S]+?)(?:%>|$)/],["pun",/^(?:<[%?]|[%?]>)/],["lang-", /^]*>([\s\S]+?)<\/xmp\b[^>]*>/i],["lang-js",/^]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\s\S]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]),"default-markup htm html mxml xhtml xml xsl".split(" "));k(x([["pln",/^[\s]+/,r," \t\r\n"],["atv",/^(?:\"[^\"]*\"?|\'[^\']*\'?)/,r,"\"'"]],[["tag",/^^<\/?[a-z](?:[\w.:-]*\w)?|\/?>$/i],["atn",/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^>\'\"\s]*(?:[^>\'\"\s\/]|\/(?=\s)))/],["pun", /^[=<>\/]+/],["lang-js",/^on\w+\s*=\s*\"([^\"]+)\"/i],["lang-js",/^on\w+\s*=\s*\'([^\']+)\'/i],["lang-js",/^on\w+\s*=\s*([^\"\'>\s]+)/i],["lang-css",/^style\s*=\s*\"([^\"]+)\"/i],["lang-css",/^style\s*=\s*\'([^\']+)\'/i],["lang-css",/^style\s*=\s*([^\"\'>\s]+)/i]]),["in.tag"]);k(x([],[["atv",/^[\s\S]+/]]),["uq.val"]);k(v({keywords:H,hashComments:o,cStyleComments:o,types:N}),"c cc cpp cxx cyc m".split(" "));k(v({keywords:I,hashComments:o,cStyleComments:o,types:/^(Object|string)/}),["d"]);k(v({keywords:"null,true,false"}), ["json"]);k(v({keywords:K,hashComments:o,cStyleComments:o,verbatimStrings:o,types:N}),["cs"]);k(v({keywords:J,cStyleComments:o}),["java"]);k(v({keywords:w,hashComments:o,multiLineStrings:o}),["bsh","csh","sh"]);k(v({keywords:L,hashComments:o,multiLineStrings:o,tripleQuotedStrings:o}),["cv","py"]);k(v({keywords:"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END",hashComments:o, multiLineStrings:o,regexLiterals:o}),["perl","pl","pm"]);k(v({keywords:M,hashComments:o,multiLineStrings:o,regexLiterals:o}),["rb"]);k(v({keywords:y,cStyleComments:o,regexLiterals:o}),["js"]);k(v({keywords:"all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes",hashComments:3,cStyleComments:o,multilineStrings:o,tripleQuotedStrings:o,regexLiterals:o}),["coffee"]);k(x([],[["str",/^[\s\S]+/]]),["regex"]); window.prettyPrintOne=function(a,m,e){var h=document.createElement("PRE");h.innerHTML=a;e&&F(h,e);G({g:m,i:e,h:h});return h.innerHTML};window.prettyPrint=function(a){function m(){for(var e=window.PR_SHOULD_USE_CONTINUATION?l.now()+250:Infinity;q"); foreach( att; type.attributes){ - dst.put(att); + dst.highlightDCode(att); dst.put(' '); } if( type.kind != TypeKind.Function && type.kind != TypeKind.Delegate ){ foreach( att; type.modifiers ){ - dst.put(att); - dst.put('('); + dst.highlightDCode(att); + dst.highlightDCode("("); } } - switch( type.kind ){ + switch (type.kind) { default: case TypeKind.Primitive: if (type.typeDecl && !cast(TemplateParameterDeclaration)type.typeDecl) { auto mn = type.typeDecl.module_.qualifiedName; auto qn = type.typeDecl.nestedName; if( qn.startsWith(mn~".") ) qn = qn[mn.length+1 .. $]; - formattedWrite(dst, "%s", link_to(type.typeDecl), qn.replace(".", ".")); // TODO: avoid allocating replace + formattedWrite(dst, "%s", link_to(type.typeDecl), highlightDCode(qn).replace(".", ".")); // TODO: avoid allocating replace } else { - dst.put(type.typeName.replace(".", ".")); // TODO: avoid allocating replace + dst.highlightDCode(type.typeName); } if( type.templateArgs.length ){ dst.put('!'); @@ -230,21 +232,21 @@ void formatType(R)(ref R dst, Type type, string delegate(Entity) link_to, bool i case TypeKind.Delegate: formatType(dst, type.returnType, link_to, false); dst.put(' '); - dst.put(type.kind == TypeKind.Function ? "function" : "delegate"); - dst.put('('); + dst.highlightDCode(type.kind == TypeKind.Function ? "function" : "delegate"); + dst.highlightDCode("("); foreach( size_t i, pt; type.parameterTypes ){ - if( i > 0 ) dst.put(", "); + if( i > 0 ) dst.highlightDCode(", "); formatType(dst, pt, link_to, false); if( type._parameterNames[i].length ){ dst.put(' '); dst.put(type._parameterNames[i]); } if( type._parameterDefaultValues[i] ){ - dst.put(" = "); + dst.highlightDCode(" = "); dst.put(type._parameterDefaultValues[i].valueString); } } - dst.put(')'); + dst.highlightDCode(")"); foreach( att; type.modifiers ){ dst.put(' '); dst.put(att); @@ -252,25 +254,27 @@ void formatType(R)(ref R dst, Type type, string delegate(Entity) link_to, bool i break; case TypeKind.Pointer: formatType(dst, type.elementType, link_to, false); - dst.put('*'); + dst.highlightDCode("*"); break; case TypeKind.Array: formatType(dst, type.elementType, link_to, false); - dst.put("[]"); + dst.highlightDCode("[]"); break; case TypeKind.StaticArray: formatType(dst, type.elementType, link_to, false); - formattedWrite(dst, "[%s]", type.arrayLength); + dst.highlightDCode("["); + dst.highlightDCode(type.arrayLength.to!string); + dst.highlightDCode("]"); break; case TypeKind.AssociativeArray: formatType(dst, type.elementType, link_to, false); - dst.put('['); + dst.highlightDCode("["); formatType(dst, type.keyType, link_to, false); - dst.put(']'); + dst.highlightDCode("]"); break; } if( type.kind != TypeKind.Function && type.kind != TypeKind.Delegate ){ - foreach( att; type.modifiers ) dst.put(')'); + foreach( att; type.modifiers ) dst.highlightDCode(")"); } if (include_code_tags) dst.put(""); } diff --git a/source/ddox/ddoc.d b/source/ddox/ddoc.d index 6697fdc7..f8c9f160 100644 --- a/source/ddox/ddoc.d +++ b/source/ddox/ddoc.d @@ -60,7 +60,7 @@ shared static this() `BACKTICK`: "`", `DDOC_BACKQUOTED`: `$(D_INLINECODE $0)`, //`D_INLINECODE`: `
$0
`, - `D_INLINECODE`: `$0`, + `D_INLINECODE`: `$0`, `DDOC` : ` @@ -450,11 +450,11 @@ private void parseSection(R)(ref R dst, string sect, string[] lines, DdocContext i = j; break; case CODE: - dst.put("
");
+						dst.put("
");
 						auto j = skipCodeBlock(i);
 						auto base_indent = baseIndent(lines[i+1 .. j]);
 						renderCodeLine(dst, lines[i+1 .. j].map!(ln => ln.unindent(base_indent)).join("\n"), context);
-						dst.put("\n
\n"); + dst.put("
\n"); i = j+1; break; } @@ -560,14 +560,15 @@ private void renderTextLine(R)(ref R dst, string line, DdocContext context) auto ident = skipIdent(line); auto link = context.lookupScopeSymbolLink(ident); - if( link.length ){ + if (link.length) { + import ddox.highlight : highlightDCode; if( link != "#" ){ dst.put(""); } - if (!inCode) dst.put(""); - dst.put(ident); + if (!inCode) dst.put(""); + dst.highlightDCode(ident, null); if (!inCode) dst.put(""); if( link != "#" ) dst.put(""); } else { @@ -585,34 +586,17 @@ private void renderTextLine(R)(ref R dst, string line, DdocContext context) /// private private void renderCodeLine(R)(ref R dst, string line, DdocContext context) { - while( line.length > 0 ){ - switch( line[0] ){ - default: - dst.put(line[0]); - line = line[1 .. $]; - break; - case '&': dst.put("&"); line = line[1 .. $]; break; - case '<': dst.put("<"); line = line[1 .. $]; break; - case '>': dst.put(">"); line = line[1 .. $]; break; - case '.': - if (line.length > 1 && (line[1].isAlpha() || line[1] == '_')) - goto case; - else goto default; - case 'a': .. case 'z': - case 'A': .. case 'Z': - case '_': - auto ident = skipIdent(line); - auto link = context.lookupScopeSymbolLink(ident); - if( link.length && link != "#" ){ - dst.put(""); - dst.put(ident); - dst.put(""); - } else dst.put(ident); - break; - } - } + import ddox.highlight : highlightDCode; + dst.highlightDCode(line, (string ident, scope void delegate() insert_ident) { + auto link = context.lookupScopeSymbolLink(ident); + if (link.length && link != "#") { + dst.put(""); + insert_ident(); + dst.put(""); + } else insert_ident(); + }); } /// private @@ -1031,25 +1015,25 @@ unittest { unittest { auto src = "Testing `inline `."; - auto dst = "Testing inline <code>.\n"; + auto dst = "Testing inline <code>.\n"; assert(formatDdocComment(src) == dst); } unittest { auto src = "Testing `inline $(CODE)`."; - auto dst = "Testing inline $(CODE).\n"; + auto dst = "Testing inline $(CODE).\n"; assert(formatDdocComment(src)); } unittest { auto src = "---\nthis is a `string`.\n---"; - auto dst = "
this is a `string`.\n
\n
\n"; + auto dst = "
this is a `string`.
\n
\n"; assert(formatDdocComment(src) == dst); } unittest { // test for properly removed indentation in code blocks - auto src = " ---\n this is a `string`.\n ---"; - auto dst = "
this is a `string`.\n
\n
\n"; + auto src = " ---\n testing\n ---"; + auto dst = "
testing
\n
\n"; assert(formatDdocComment(src) == dst); } @@ -1119,13 +1103,13 @@ unittest { // more whitespace testing unittest { // escape in backtick code auto src = "`&`"; - auto dst = "<b>&amp;\n"; - assert(formatDdocComment(src) == dst); + auto dst = "<b>&amp;\n"; + assert(formatDdocComment(src) == dst,formatDdocComment(src) ); } unittest { // escape in code blocks auto src = "---\n&\n---"; - auto dst = "
<b>&amp;\n
\n
\n"; + auto dst = "
<b>&amp;
\n
\n"; assert(formatDdocComment(src) == dst); } diff --git a/source/ddox/highlight.d b/source/ddox/highlight.d new file mode 100644 index 00000000..7d8d7457 --- /dev/null +++ b/source/ddox/highlight.d @@ -0,0 +1,145 @@ +/** + D syntax highlighting. + + Copyright: © 2015 RejectedSoftware e.K. + License: Subject to the terms of the MIT license, as written in the included LICENSE.txt file. + Authors: Sönke Ludwig +*/ +module ddox.highlight; + +import std.algorithm : any; +import std.array : Appender, appender, replace; +import std.range; +import std.string : strip; +import std.uni : isLower, isUpper; + + +/** + Takes a piece of D code and outputs a sequence of HTML elements useful for syntax highlighting. + + The output will contain $(LT)span$(GT) elements with the class attribute + set to the kind of entity that it contains. The class names are kept + compatible with the ones used for Google's prettify library: "typ", "kwd", + "com", "str", "lit", "pun", "pln", "spc" + + The only addition is "spc", which denotes a special token sequence starting + with a "#", such as "#line" or "#!/bin/sh". + + Note that this function will only perform actual syntax highlighting if + the libdparse package is available as a DUB dependency. + + --- + void main(string[] args) + { + #line 2 + import std.stdio; // yeah + writefln("Hello, "~"World!"); + Package pack; + ddox.entities.Module mod; + } + --- + + Params: + dst = Output range where to write the HTML output + code = The D source code to process + ident_render = Optional delegate to customize how (qualified) + identifiers are rendered +*/ +void highlightDCode(R)(ref R dst, string code, scope IdentifierRenderCallback ident_render = null) + if (isOutputRange!(R, char)) +{ + string last_class; + dst.highlightDCodeImpl(code, ident_render, last_class); + if (last_class.length) dst.put(""); +} + +/// ditto +string highlightDCode(string str, IdentifierRenderCallback ident_render = null) +{ + auto dst = appender!string(); + dst.highlightDCode(str, ident_render); + return dst.data; +} + + +void highlightDCodeImpl(R)(ref R dst, string code, scope IdentifierRenderCallback ident_render, ref string last_class) + if (isOutputRange!(R, char)) +{ + import dparse.lexer : DLexer, LexerConfig, StringBehavior, StringCache, WhitespaceBehavior, + isBasicType, isKeyword, isStringLiteral, isNumberLiteral, + isOperator, str, tok; + import std.algorithm : endsWith; + + StringCache cache = StringCache(1024 * 4); + + LexerConfig config; + config.stringBehavior = StringBehavior.source; + config.whitespaceBehavior = WhitespaceBehavior.include; + + void writeWithClass(string text, string cls) + { + import std.format : formattedWrite; + if (last_class != cls) { + if (last_class.length) dst.put(""); + dst.formattedWrite("", cls); + last_class = cls; + } + + foreach (char ch; text) { + switch (ch) { + default: dst.put(ch); break; + case '&': dst.put("&"); break; + case '<': dst.put("<"); break; + case '>': dst.put(">"); break; + } + } + } + + + auto symbol = appender!string; + + foreach (t; DLexer(cast(ubyte[])code, config, &cache)) { + if (ident_render) { + if (t.type == tok!"." && !symbol.data.endsWith(".")) { + symbol ~= "."; + continue; + } else if (t.type == tok!"identifier" && (symbol.data.empty || symbol.data.endsWith("."))) { + symbol ~= t.text; + continue; + } else if (symbol.data.length) { + ident_render(symbol.data, { highlightDCodeImpl(dst, symbol.data, null, last_class); }); + symbol = appender!string(); + } + } + + if (t.type == tok!".") dst.put(""); + + if (isBasicType(t.type)) writeWithClass(str(t.type), "typ"); + else if (isKeyword(t.type)) writeWithClass(str(t.type), "kwd"); + else if (t.type == tok!"comment") writeWithClass(t.text, "com"); + else if (isStringLiteral(t.type) || t.type == tok!"characterLiteral") writeWithClass(t.text, "str"); + else if (isNumberLiteral(t.type)) writeWithClass(t.text, "lit"); + else if (isOperator(t.type)) writeWithClass(str(t.type), "pun"); + else if (t.type == tok!"specialTokenSequence" || t.type == tok!"scriptLine") writeWithClass(t.text, "spc"); + else if (t.text.strip == "string") writeWithClass(t.text, "typ"); + else if (t.type == tok!"identifier" && t.text.isCamelCase) writeWithClass(t.text, "typ"); + else if (t.type == tok!"identifier") writeWithClass(t.text, "pln"); + else if (t.type == tok!"whitespace") writeWithClass(t.text, last_class.length ? last_class : "pln"); + else writeWithClass(t.text, "pun"); + } + + if (symbol.data.length) + ident_render(symbol.data, { highlightDCodeImpl(dst, symbol.data, null, last_class); }); +} + + +alias IdentifierRenderCallback = void delegate(string ident, scope void delegate() insert_ident); + +private bool isCamelCase(string text) +{ + text = text.strip(); + if (text.length < 2) return false; + if (!text[0].isUpper) return false; + if (!text.any!(ch => ch.isLower)) return false; + return true; +} diff --git a/source/ddox/main.d b/source/ddox/main.d index 3fa5d6a9..d7d59fba 100644 --- a/source/ddox/main.d +++ b/source/ddox/main.d @@ -39,9 +39,7 @@ int ddoxMain(string[] args) case "generate-html": return cmdGenerateHtml(args); case "serve-html": return cmdServeHtml(args); case "filter": return cmdFilterDocs(args); - version (Have_libdparse) { - case "serve-test": return cmdServeTest(args); - } + case "serve-test": return cmdServeTest(args); } } @@ -83,31 +81,29 @@ int cmdServeHtml(string[] args) return runEventLoop(); } -version (Have_libdparse) { - int cmdServeTest(string[] args) - { - string[] webfiledirs; - auto docsettings = new DdoxSettings; - auto gensettings = new GeneratorSettings; +int cmdServeTest(string[] args) +{ + string[] webfiledirs; + auto docsettings = new DdoxSettings; + auto gensettings = new GeneratorSettings; - auto pack = parseD(args[2 .. $]); + auto pack = parseD(args[2 .. $]); - processDocs(pack, docsettings); + processDocs(pack, docsettings); - // register the api routes and start the server - auto router = new URLRouter; - registerApiDocs(router, pack, gensettings); + // register the api routes and start the server + auto router = new URLRouter; + registerApiDocs(router, pack, gensettings); - foreach (dir; webfiledirs) - router.get("*", serveStaticFiles(dir)); + foreach (dir; webfiledirs) + router.get("*", serveStaticFiles(dir)); - writefln("Listening on port 8080..."); - auto settings = new HTTPServerSettings; - settings.port = 8080; - listenHTTP(settings, router); + writefln("Listening on port 8080..."); + auto settings = new HTTPServerSettings; + settings.port = 8080; + listenHTTP(settings, router); - return runEventLoop(); - } + return runEventLoop(); } int setupGeneratorInput(ref string[] args, out GeneratorSettings gensettings, out Package pack) diff --git a/source/ddox/parsers/dparse.d b/source/ddox/parsers/dparse.d index 7d673ed5..8ddb771a 100644 --- a/source/ddox/parsers/dparse.d +++ b/source/ddox/parsers/dparse.d @@ -7,13 +7,11 @@ */ module ddox.parsers.dparse; -version (Have_libdparse): - import ddox.ddox; import ddox.entities; -import dparse = std.d.parser; -import dlex = std.d.lexer; -import dformat = std.d.formatter; +import dparse = dparse.parser; +import dlex = dparse.lexer; +import dformat = dparse.formatter; import std.algorithm; import std.conv; @@ -151,7 +149,7 @@ private struct DParser mod.members = parseDeclList(dmod.declarations, mod); } - Declaration[] parseDeclList(dparse.Declaration[] decls, Entity parent) + Declaration[] parseDeclList(const(dparse.Declaration)[] decls, Entity parent) { DocGroup lastdoc; Declaration[] ret; @@ -171,7 +169,7 @@ private struct DParser return ret; } - Declaration[] parseDecl(dparse.Declaration decl, Entity parent, dparse.Attribute[] additional_attribs = null) + Declaration[] parseDecl(in dparse.Declaration decl, Entity parent, const(dparse.Attribute)[] additional_attribs = null) { if (auto ad = decl.attributeDeclaration) { additional_attribs ~= decl.attributes; @@ -335,7 +333,7 @@ private struct DParser return ret; } - void addAttributes(Declaration decl, dparse.Attribute[] attrs) + void addAttributes(Declaration decl, const(dparse.Attribute)[] attrs) { return addAttributes(decl, attrs.map!(att => formatNode(att)).array); } @@ -356,7 +354,7 @@ private struct DParser } } - VariableDeclaration[] parseParameters(dparse.Parameters dparams, FunctionDeclaration parent) + VariableDeclaration[] parseParameters(in dparse.Parameters dparams, FunctionDeclaration parent) { VariableDeclaration[] ret; foreach (p; dparams.parameters) { @@ -368,7 +366,7 @@ private struct DParser return ret; } - VariableDeclaration parseParameter(dparse.Parameter dparam, FunctionDeclaration parent) + VariableDeclaration parseParameter(in dparse.Parameter dparam, FunctionDeclaration parent) { auto ret = new VariableDeclaration(parent, dparam.name.text.idup); ret.type = parseType(dparam.type, parent); @@ -381,7 +379,7 @@ private struct DParser return ret; } - Type parseType(dparse.Type type, Entity scope_) + Type parseType(in dparse.Type type, Entity scope_) { auto ret = parseType(type.type2, scope_); foreach (tc; type.typeConstructors) @@ -405,7 +403,7 @@ private struct DParser return ret; } - Type parseType(dparse.Type2 type, Entity scope_) + Type parseType(in dparse.Type2 type, Entity scope_) { auto ret = new Type; if (type.builtinType) { diff --git a/views/ddox.inc.function.dt b/views/ddox.inc.function.dt index a953c60e..fba5994a 100644 --- a/views/ddox.inc.function.dt +++ b/views/ddox.inc.function.dt @@ -1,4 +1,5 @@ - import ddox.api; +- import ddox.highlight; - import std.algorithm; - void outputFunctionDescription(FunctionDeclaration item) @@ -7,7 +8,7 @@ - auto heading = docgroup.members.length > 1 ? "Prototypes" : "Prototype"; h3= heading .prototype - code.prettyprint.lang-d + code.lang-d - auto mems = docgroup.members; - foreach( size_t pi, pd; mems ) - auto proto = cast(FunctionDeclaration)pd; @@ -26,25 +27,25 @@ - attribs[i] = attribs[$-1]; - attribs.length--; - break; - - auto attribute_prefix = getAttributeString(attribs, AttributeStringKind.functionPrefix); - - auto attribute_suffix = getAttributeString(attribs, AttributeStringKind.functionSuffix); - - if (!proto.templateConstraint.length) attribute_suffix ~= ";"; + - auto attribute_prefix = highlightDCode(getAttributeString(attribs, AttributeStringKind.functionPrefix)); + - auto attribute_suffix = highlightDCode(getAttributeString(attribs, AttributeStringKind.functionSuffix)); + - if (!proto.templateConstraint.length) attribute_suffix ~= ";"; - if (proto.parameters.length) - |#{attribute_prefix}!{rettype}#{proto.name}#{proto.templateArgsString}( + |!{attribute_prefix}!{rettype}#{proto.name}!{highlightDCode(proto.templateArgsString)}( br - foreach (size_t i, p; proto.parameters) - - auto pattribs = getAttributeString(p.attributes, AttributeStringKind.normal); - - auto suffix = i+1 < proto.parameters.length ? "," : ""; + - auto pattribs = highlightDCode(getAttributeString(p.attributes, AttributeStringKind.normal)); + - auto suffix = i+1 < proto.parameters.length ? "," : ""; - if (p.initializer) - |  #{pattribs}!{info.formatType(p.type, false)} #{p.name} = #{p.initializer.valueString}#{suffix} + |  !{pattribs}!{info.formatType(p.type, false)} #{p.name} = !{highlightDCode(p.initializer.valueString)}!{suffix} - else - |  #{pattribs}!{info.formatType(p.type, false)} #{p.name}#{suffix} + |  !{pattribs}!{info.formatType(p.type, false)} #{p.name}!{suffix} br - |)#{attribute_suffix} + |)!{attribute_suffix} - else - |#{attribute_prefix}!{rettype}#{proto.name}#{proto.templateArgsString}()#{attribute_suffix} + |!{attribute_prefix}!{rettype}#{proto.name}!{highlightDCode(proto.templateArgsString)}()!{attribute_suffix} - if (proto.templateConstraint.length) br - |if (#{proto.templateConstraint}); + |if (!{highlightDCode(proto.templateConstraint)}); diff --git a/views/ddox.inc.template.dt b/views/ddox.inc.template.dt index 6b8fa626..3c2bf1fe 100644 --- a/views/ddox.inc.template.dt +++ b/views/ddox.inc.template.dt @@ -1,4 +1,5 @@ - import ddox.api; +- import ddox.highlight; - import std.algorithm; - import std.typetuple; @@ -7,8 +8,8 @@ h2 Arguments .prototype - code.prettyprint.lang-d - |template #{item.name}#{item.templateArgsString}; + code.lang-d + |template #{item.name}!{highlightDCode(item.templateArgsString)}; - void outputTemplateMembers(TemplateDeclaration item) - alias TypeTuple!(FunctionDeclaration, InterfaceDeclaration, ClassDeclaration, StructDeclaration, UnionDeclaration, EnumDeclaration, AliasDeclaration, TemplateDeclaration) kinds; diff --git a/views/ddox.inc.variable.dt b/views/ddox.inc.variable.dt index 57416da3..c8b086cb 100644 --- a/views/ddox.inc.variable.dt +++ b/views/ddox.inc.variable.dt @@ -6,54 +6,54 @@ section h3 Declaration .prototype - code.prettyprint.lang-d + code.lang-d - string value; - - string terminator = ";"; + - string terminator = ";"; - string attributes; - if (auto a = getAttributeString(item, AttributeStringKind.normal)) - - attributes ~= a; + - attributes ~= highlightDCode(a); - if (auto var = cast(VariableDeclaration)item) - if (var.type) attributes ~= info.formatType(var.type, false) ~ " "; - - if (var.initializer) value = var.initializer.valueString; + - if (var.initializer) value = highlightDCode(var.initializer.valueString); - else if (auto ev = cast(EnumMemberDeclaration)item) - if (ev.type) attributes ~= info.formatType(ev.type, false) ~ " "; - - if (ev.value) value = ev.value.valueString; + - if (ev.value) value = highlightDCode(ev.value.valueString); - if (ev.parent && cast(EnumDeclaration)ev.parent) - - terminator = ","; + - terminator = ","; - else - - attributes = "enum " ~ attributes; + - attributes = "enum " ~ attributes; - else if (auto ad = cast(AliasDeclaration)item) - - attributes = "alias " ~ attributes; + - attributes = "alias " ~ attributes; - if (ad.targetType) - value = info.formatType(ad.targetType, false); - else if (ad.targetDecl) //- TODO! - - auto itemname = item.name ~ item.templateArgsString; + - auto itemname = "" ~ item.name ~ "" ~ highlightDCode(item.templateArgsString); - if (auto m = cast(Module)item.parent) //- |module #{item.parent.qualifiedName}; //- | //- |// ... - if (value.length) - |!{attributes}#{itemname} = !{value}; + |!{attributes}!{itemname} = !{value}; - else - |!{attributes}#{itemname}; + |!{attributes}!{itemname}; //- |// ... - else - if( auto ctd = cast(Declaration)item.parent ) - |#{toLower(to!string(ctd.kind))} #{ctd.nestedName} + |#{toLower(to!string(ctd.kind))} #{ctd.nestedName} - else - |#{item.parent.qualifiedName} + |!{highlightDCode(item.parent.qualifiedName)} br - |{ + span.pun { br - |  // ... + |  // ... br - if (value.length) - |  !{attributes}#{itemname} = !{value}!{terminator} + |  !{attributes}!{itemname} = !{value}!{terminator} - else - |  !{attributes}#{itemname}!{terminator} + |  !{attributes}!{itemname}!{terminator} br - |  // ... + |  // ... br - |} + span.pun } diff --git a/views/layout.dt b/views/layout.dt index fe277777..5c930e46 100644 --- a/views/layout.dt +++ b/views/layout.dt @@ -8,12 +8,11 @@ html link(rel="stylesheet", type="text/css", href="#{info.linkTo(null)}styles/ddox.css") link(rel="stylesheet", href="#{info.linkTo(null)}prettify/prettify.css", type="text/css") script(type="text/javascript", src="#{info.linkTo(null)}scripts/jquery.js")/**/ - script(type="text/javascript", src="#{info.linkTo(null)}prettify/prettify.js")/**/ script(type="text/javascript", src="#{info.linkTo(null)}scripts/ddox.js")/**/ - body(onload="prettyPrint(); setupDdox();") + body(onload="setupDdox();") nav#main-nav block navigation #main-contents h1= title - block body \ No newline at end of file + block body