1 /** 2 Internal functions for use inside the HTML templates. 3 4 Copyright: © 2012 RejectedSoftware e.K. 5 License: Subject to the terms of the MIT license, as written in the included LICENSE.txt file. 6 Authors: Sönke Ludwig 7 */ 8 module ddox.api; 9 10 public import ddox.ddox; 11 public import ddox.ddoc; 12 13 import std.algorithm; 14 import std.array; 15 import std.conv; 16 import std.format; 17 import std.string; 18 import vibe.core.log; 19 import vibe.data.json; 20 21 22 23 class DocGroupContext : DdocContext { 24 private { 25 DocGroup m_group; 26 string delegate(Entity ent) m_linkTo; 27 } 28 29 this(DocGroup grp, string delegate(Entity ent) link_to) 30 { 31 m_group = grp; 32 m_linkTo = link_to; 33 } 34 35 @property string docText() { return m_group.text; } 36 @property string[] overrideMacroDefinitions() { return null; } 37 @property string[] defaultMacroDefinitions() { return null; } 38 string lookupScopeSymbolLink(string name) 39 { 40 if (name == "this") return null; 41 42 foreach( def; m_group.members ){ 43 // if this is a function, first search the parameters 44 // TODO: maybe do the same for function/delegate variables/type aliases 45 if( auto fn = cast(FunctionDeclaration)def ){ 46 foreach( p; fn.parameters ) 47 if( p.name == name ) 48 return m_linkTo(p); 49 } 50 51 // then look up the name in the outer scope 52 auto n = def.lookup(name); 53 54 // packages are not linked 55 if( cast(Package)n ) continue; 56 57 // module names must be fully qualified 58 if( auto mod = cast(Module)n ) 59 if( mod.qualifiedName != name ) 60 continue; 61 62 // don't return links to the declaration itself, but 63 // the sepcial string # that will still print the identifier 64 // as code 65 if( n is def ) return "#"; 66 67 if( n ) return m_linkTo(n); 68 } 69 return null; 70 } 71 } 72 73 74 string getFunctionName(Json proto) 75 { 76 auto n = proto.name.get!string; 77 if( auto ptn = "templateName" in proto ){ 78 auto tn = ptn.get!string; 79 if( tn.startsWith(n~"(") ) 80 return tn; 81 return tn ~ "." ~ n; 82 } 83 return n; 84 } 85 86 DocGroup[] docGroups(Declaration[] items) 87 { 88 DocGroup[] ret; 89 foreach( itm; items ){ 90 bool found = false; 91 foreach( g; ret ) 92 if( g is itm.docGroup ){ 93 found = true; 94 break; 95 } 96 if( !found ) ret ~= itm.docGroup; 97 } 98 return ret; 99 } 100 101 102 bool hasChild(T)(Module mod){ return hasChild!T(mod.members); } 103 bool hasChild(T)(CompositeTypeDeclaration decl){ return hasChild!T(decl.members); } 104 bool hasChild(T)(TemplateDeclaration mod){ return hasChild!T(mod.members); } 105 bool hasChild(T)(Declaration[] decls){ foreach( m; decls ) if( cast(T)m ) return true; return false; } 106 107 T[] getChildren(T)(Module mod){ return getChildren!T(mod.members); } 108 T[] getChildren(T)(CompositeTypeDeclaration decl){ return getChildren!T(decl.members); } 109 T[] getChildren(T)(TemplateDeclaration decl){ return getChildren!T(decl.members); } 110 T[] getChildren(T)(Declaration[] decls) 111 { 112 T[] ret; 113 foreach( ch; decls ) 114 if( auto ct = cast(T)ch ) 115 ret ~= ct; 116 return ret; 117 } 118 119 T[] getDocGroups(T)(Module mod){ return getDocGroups!T(mod.members); } 120 T[] getDocGroups(T)(CompositeTypeDeclaration decl){ return getDocGroups!T(decl.members); } 121 T[] getDocGroups(T)(TemplateDeclaration decl){ return getDocGroups!T(decl.members); } 122 T[] getDocGroups(T)(Declaration[] decls) 123 { 124 T[] ret; 125 DocGroup dg; 126 string name; 127 foreach( d; decls ){ 128 auto dt = cast(T)d; 129 if( !dt ) continue; 130 if( dt.docGroup !is dg || dt.name != name ){ 131 ret ~= dt; 132 dg = d.docGroup; 133 name = d.name; 134 } 135 } 136 return ret; 137 } 138 139 string[] declStyleClasses(Declaration decl) 140 { 141 string[] ret; 142 ret ~= decl.protection.to!string().toLower(); 143 if (decl.inheritingDecl) ret ~= "inherited"; 144 if (auto tdecl = cast(TypedDeclaration)decl) { 145 assert(tdecl.type !is null, typeid(tdecl).name~" declaration without type!?"); 146 if (tdecl.type.attributes.canFind("@property")) ret ~= "property"; 147 if (tdecl.type.attributes.canFind("static")) ret ~= "static"; 148 } 149 return ret; 150 } 151 152 string formatType()(Type type, string delegate(Entity) link_to, bool include_code_tags = true) 153 { 154 if( !type ) return "{null}"; 155 //logDebug("format type: %s", type); 156 auto ret = appender!string(); 157 formatType(ret, type, link_to, include_code_tags); 158 return ret.data(); 159 } 160 161 void formatType(R)(ref R dst, Type type, string delegate(Entity) link_to, bool include_code_tags = true) 162 { 163 if (include_code_tags) dst.put("<code class=\"prettyprint lang-d\">"); 164 foreach( att; type.attributes){ 165 dst.put(att); 166 dst.put(' '); 167 } 168 if( type.kind != TypeKind.Function && type.kind != TypeKind.Delegate ){ 169 foreach( att; type.modifiers ){ 170 dst.put(att); 171 dst.put('('); 172 } 173 } 174 switch( type.kind ){ 175 default: 176 case TypeKind.Primitive: 177 if (type.typeDecl && !cast(TemplateParameterDeclaration)type.typeDecl) { 178 auto mn = type.typeDecl.module_.qualifiedName; 179 auto qn = type.typeDecl.nestedName; 180 if( qn.startsWith(mn~".") ) qn = qn[mn.length+1 .. $]; 181 formattedWrite(dst, "<a href=\"%s\">%s</a>", link_to(type.typeDecl), qn); 182 } else { 183 dst.put(type.typeName); 184 } 185 if( type.templateArgs.length ){ 186 dst.put('!'); 187 dst.put(type.templateArgs); 188 } 189 break; 190 case TypeKind.Function: 191 case TypeKind.Delegate: 192 formatType(dst, type.returnType, link_to, false); 193 dst.put(' '); 194 dst.put(type.kind == TypeKind.Function ? "function" : "delegate"); 195 dst.put('('); 196 foreach( size_t i, pt; type.parameterTypes ){ 197 if( i > 0 ) dst.put(", "); 198 formatType(dst, pt, link_to, false); 199 if( type._parameterNames[i].length ){ 200 dst.put(' '); 201 dst.put(type._parameterNames[i]); 202 } 203 if( type._parameterDefaultValues[i] ){ 204 dst.put(" = "); 205 dst.put(type._parameterDefaultValues[i].valueString); 206 } 207 } 208 dst.put(')'); 209 foreach( att; type.modifiers ){ 210 dst.put(' '); 211 dst.put(att); 212 } 213 break; 214 case TypeKind.Pointer: 215 formatType(dst, type.elementType, link_to, false); 216 dst.put('*'); 217 break; 218 case TypeKind.Array: 219 formatType(dst, type.elementType, link_to, false); 220 dst.put("[]"); 221 break; 222 case TypeKind.StaticArray: 223 formatType(dst, type.elementType, link_to, false); 224 formattedWrite(dst, "[%s]", type.arrayLength); 225 break; 226 case TypeKind.AssociativeArray: 227 formatType(dst, type.elementType, link_to, false); 228 dst.put('['); 229 formatType(dst, type.keyType, link_to, false); 230 dst.put(']'); 231 break; 232 } 233 if( type.kind != TypeKind.Function && type.kind != TypeKind.Delegate ){ 234 foreach( att; type.modifiers ) dst.put(')'); 235 } 236 if (include_code_tags) dst.put("</code>"); 237 } 238 239 Type getPropertyType(Entity[] mems...) 240 { 241 foreach (ov; mems) { 242 auto ovf = cast(FunctionDeclaration)ov; 243 if (!ovf) continue; 244 auto rt = ovf.returnType; 245 if (rt.typeName != "void") return rt; 246 if (ovf.parameters.length == 0) continue; 247 return ovf.parameters[0].type; 248 } 249 return null; 250 } 251 252 bool anyPropertyGetter(Entity[] mems...) 253 { 254 foreach (ov; mems) { 255 auto ovf = cast(FunctionDeclaration)ov; 256 if (!ovf) continue; 257 if (ovf.returnType.typeName == "void") continue; 258 if (ovf.parameters.length == 0) return true; 259 } 260 return false; 261 } 262 263 bool anyPropertySetter(Entity[] mems...) 264 { 265 foreach (ov; mems) { 266 auto ovf = cast(FunctionDeclaration)ov; 267 if (!ovf) continue; 268 if (ovf.parameters.length == 1) return true; 269 } 270 return false; 271 }