1 /* This file is part of the 'hgen' project.
2  *
3  * Copyright (c) 2014-2022
4  *     Economic Modeling Specialists, Intl.,
5  *     the D Community.
6  *
7  * Main contributors:
8  *     Ferdinand Majerech
9  *     Ilya Yaroshenko
10  *     Basile Burg
11  *     Eugene Stulin
12  *
13  * Distributed under the Boost Software License, Version 1.0.
14  *
15  * You should have received a copy of the Boost Software License
16  * along with this program. If not, see <http://www.boost.org/LICENSE_1_0.txt>.
17  * This file is offered as-is, without any warranty.
18  */
19 
20 module formatter;
21 
22 import dparse.ast;
23 import dparse.lexer;
24 import dparse.formatter;
25 import std.stdio;
26 
27 
28 /*******************************************************************************
29  * Modified D formatter for Harbored.
30  *
31  * Currently the only modification is that multi-parameter parameter lists
32  * are split into multiple lines.
33  */
34 class HarboredFormatter(Sink) : Formatter!Sink {
35     /// Nesting level for nested parameter lists (see format(const Parameters)).
36     private uint level;
37 
38     /// Function to process types with for cross-referencing.
39     private string delegate(string) @safe nothrow crossReference;
40 
41     /**
42      * Params:
43      *
44      * sink        = the output range that the formatted source code
45      *               is placed in
46      * processCode = Function to process types with for cross-referencing.
47      * useTabs     = if true, tabs are used for indent levels instead of spaces
48      * style       = the brace style
49      * indentWidth = the number of spaces used for indentation
50      *               if useTabs is false
51      */
52     this(Sink sink,
53          string delegate(string) @safe nothrow crossReference,
54          bool useTabs = false,
55          IndentStyle style = IndentStyle.otbs,
56          uint indentWidth = 4
57     ) {
58         this.crossReference = crossReference;
59         super(sink, useTabs, style, indentWidth);
60     }
61 
62     alias format = Formatter!Sink.format;
63 
64     /** A modified version
65      * of  dparse.formatter.Formatter.format(const Parameters)
66     */
67     override void format(const Parameters parameters) {
68         debug(verbose) writeln("Parameters (HarboredFormatter)");
69 
70         // No need to break the list into multiple lines for a single argument
71         // TODO ability to set this in "doxyfile"
72         const maxParamsForSingleLineParamList = 1;
73         if (parameters.parameters.length <= maxParamsForSingleLineParamList) {
74             super.format(parameters);
75             return;
76         }
77         level++;
78         scope(exit) level--;
79         put("(");
80         bool moreThanThreeArgs = parameters.parameters.length > 3;
81         auto interArgSep = moreThanThreeArgs ? "\n" : "";
82         foreach (count, param; parameters.parameters) {
83             if (count) {
84                 put(", ");
85             }
86             put(interArgSep);
87             if (moreThanThreeArgs) {
88                 foreach(i; 0 .. level) {
89                     put("    ");
90                 }
91             }
92             format(param);
93         }
94         if (parameters.hasVarargs) {
95             if (parameters.parameters.length) {
96                 put(", ");
97             }
98             put(interArgSep);
99             if (moreThanThreeArgs) {
100                 foreach(i; 0 .. level) {
101                     put("    ");
102                 }
103             }
104             put("...");
105         }
106         if (level > 1) {
107             put("\n");
108             foreach(i; 0..level) {
109                 put("    ");
110             }
111         }
112         put(interArgSep);
113         put(")");
114     }
115 
116     // Overridden for builtin type referencing.
117     override void format(const Type2 type2) {
118         debug(verbose) writeln("Type2 (HarboredFormatter)");
119 
120         /**
121         IdType builtinType;
122         Symbol symbol;
123         TypeofExpression typeofExpression;
124         IdentifierOrTemplateChain identifierOrTemplateChain;
125         IdType typeConstructor;
126         Type type;
127         **/
128 
129         if (type2.typeIdentifierPart !is null) {
130             format(type2.typeIdentifierPart);
131         } else if (type2.typeofExpression !is null) {
132             format(type2.typeofExpression);
133             if (type2.typeIdentifierPart) {
134                 put(".");
135                 format(type2.typeIdentifierPart);
136             }
137             return;
138         } else if (type2.typeConstructor != tok!"") {
139             put(tokenRep(type2.typeConstructor));
140             put("(");
141             format(type2.type);
142             put(")");
143         } else {
144             // Link to language reference for builtin types.
145             put(`<a href="http://dlang.org/type.html#basic-data-types">`);
146             put(tokenRep(type2.builtinType));
147             put("</a>");
148         }
149     }
150 
151     // Overridden for cross-referencing.
152     override void format(const Token token) {
153         debug(verbose) writeln("Token (HarboredFormatter) ", tokenRep(token));
154         put(crossReference(tokenRep(token)));
155     }
156 
157 }
158