| OLD | NEW |
| (Empty) | |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. |
| 4 |
| 5 /** |
| 6 * Tools for code generation. |
| 7 */ |
| 8 library CodegenTools; |
| 9 |
| 10 import 'package:html5lib/dom.dart' as dom; |
| 11 |
| 12 import 'text_formatter.dart'; |
| 13 import 'html_tools.dart'; |
| 14 |
| 15 /** |
| 16 * Join the given strings using camelCase. If [capitalize] is true, the first |
| 17 * part will be capitalized as well. |
| 18 */ |
| 19 String camelJoin(List<String> parts, {bool capitalize: false}) { |
| 20 List<String> upcasedParts = <String>[]; |
| 21 for (int i = 0; i < parts.length; i++) { |
| 22 if (i == 0 && !capitalize) { |
| 23 upcasedParts.add(parts[i]); |
| 24 } else { |
| 25 upcasedParts.add(parts[i][0].toUpperCase() + parts[i].substring(1)); |
| 26 } |
| 27 } |
| 28 return upcasedParts.join(); |
| 29 } |
| 30 |
| 31 final RegExp trailingWhitespaceRegExp = new RegExp(r' +$', multiLine: true); |
| 32 |
| 33 /** |
| 34 * Mixin class for generating code. |
| 35 */ |
| 36 class CodeGenerator { |
| 37 _CodeGeneratorState _state; |
| 38 |
| 39 /** |
| 40 * Execute [callback], collecting any code that is output using [write] |
| 41 * or [writeln], and return the result as a string. |
| 42 */ |
| 43 String collectCode(void callback()) { |
| 44 _CodeGeneratorState oldState = _state; |
| 45 try { |
| 46 _state = new _CodeGeneratorState(); |
| 47 callback(); |
| 48 return _state.buffer.toString().replaceAll(trailingWhitespaceRegExp, ''); |
| 49 } finally { |
| 50 _state = oldState; |
| 51 } |
| 52 } |
| 53 |
| 54 /** |
| 55 * Output text without ending the current line. |
| 56 */ |
| 57 void write(Object obj) { |
| 58 _state.write(obj.toString()); |
| 59 } |
| 60 |
| 61 /** |
| 62 * Output text, ending the current line. |
| 63 */ |
| 64 void writeln([Object obj = '']) { |
| 65 _state.write('$obj\n'); |
| 66 } |
| 67 |
| 68 /** |
| 69 * Execute [callback], indenting any code it outputs by two spaces. |
| 70 */ |
| 71 void indent(void callback()) => indentSpecial(' ', ' ', callback); |
| 72 |
| 73 /** |
| 74 * Execute [callback], using [additionalIndent] to indent any code it outputs. |
| 75 */ |
| 76 void indentBy(String additionalIndent, void callback()) => indentSpecial( |
| 77 additionalIndent, additionalIndent, callback); |
| 78 |
| 79 /** |
| 80 * Execute [callback], using [additionalIndent] to indent any code it outputs. |
| 81 * The first line of output is indented by [firstAdditionalIndent] instead of |
| 82 * [additionalIndent]. |
| 83 */ |
| 84 void indentSpecial(String firstAdditionalIndent, String additionalIndent, void |
| 85 callback()) { |
| 86 String oldNextIndent = _state.nextIndent; |
| 87 String oldIndent = _state.indent; |
| 88 try { |
| 89 _state.nextIndent += firstAdditionalIndent; |
| 90 _state.indent += additionalIndent; |
| 91 callback(); |
| 92 } finally { |
| 93 _state.nextIndent = oldNextIndent; |
| 94 _state.indent = oldIndent; |
| 95 } |
| 96 } |
| 97 |
| 98 /** |
| 99 * Measure the width of the current indentation level. |
| 100 */ |
| 101 int get indentWidth => _state.nextIndent.length; |
| 102 |
| 103 /** |
| 104 * Generate a doc comment based on the HTML in [docs]. |
| 105 * |
| 106 * If [javadocStyle] is true, then the output is compatable with Javadoc, |
| 107 * which understands certain HTML constructs. |
| 108 */ |
| 109 void docComment(List<dom.Node> docs, bool javadocStyle) { |
| 110 writeln('/**'); |
| 111 indentBy(' * ', () { |
| 112 write(nodesToText(docs, 79 - _state.indent.length, javadocStyle)); |
| 113 }); |
| 114 writeln(' */'); |
| 115 } |
| 116 |
| 117 void outputHeader() { |
| 118 String header = |
| 119 ''' |
| 120 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file'); |
| 121 // for details. All rights reserved. Use of this source code is governed by a |
| 122 // BSD-style license that can be found in the LICENSE file. |
| 123 // |
| 124 // This file has been automatically generated. Please do not edit it manually. |
| 125 // To regenerate the file, use the script |
| 126 // "pkg/analysis_server/spec/generate_files". |
| 127 '''; |
| 128 writeln(header.trim()); |
| 129 writeln(); |
| 130 } |
| 131 } |
| 132 |
| 133 /** |
| 134 * State used by [CodeGenerator]. |
| 135 */ |
| 136 class _CodeGeneratorState { |
| 137 StringBuffer buffer = new StringBuffer(); |
| 138 String nextIndent = ''; |
| 139 String indent = ''; |
| 140 bool indentNeeded = true; |
| 141 |
| 142 void write(String text) { |
| 143 List<String> lines = text.split('\n'); |
| 144 for (int i = 0; i < lines.length; i++) { |
| 145 if (i == lines.length - 1 && lines[i].isEmpty) { |
| 146 break; |
| 147 } |
| 148 if (indentNeeded) { |
| 149 buffer.write(nextIndent); |
| 150 nextIndent = indent; |
| 151 } |
| 152 indentNeeded = false; |
| 153 buffer.write(lines[i]); |
| 154 if (i != lines.length - 1) { |
| 155 buffer.writeln(); |
| 156 indentNeeded = true; |
| 157 } |
| 158 } |
| 159 } |
| 160 } |
| 161 |
| 162 /** |
| 163 * Mixin class for generating HTML representations of code that are suitable |
| 164 * for enclosing inside a <pre> element. |
| 165 */ |
| 166 abstract class HtmlCodeGenerator { |
| 167 _HtmlCodeGeneratorState _state; |
| 168 |
| 169 /** |
| 170 * Execute [callback], collecting any code that is output using [write], |
| 171 * [writeln], [add], or [addAll], and return the result as a list of DOM |
| 172 * nodes. |
| 173 */ |
| 174 List<dom.Node> collectHtml(void callback()) { |
| 175 _HtmlCodeGeneratorState oldState = _state; |
| 176 try { |
| 177 _state = new _HtmlCodeGeneratorState(); |
| 178 if (callback != null) { |
| 179 callback(); |
| 180 } |
| 181 return _state.buffer; |
| 182 } finally { |
| 183 _state = oldState; |
| 184 } |
| 185 } |
| 186 |
| 187 /** |
| 188 * Add the given [node] to the HTML output. |
| 189 */ |
| 190 void add(dom.Node node) { |
| 191 _state.add(node); |
| 192 } |
| 193 |
| 194 /** |
| 195 * Add the given [nodes] to the HTML output. |
| 196 */ |
| 197 void addAll(Iterable<dom.Node> nodes) { |
| 198 for (dom.Node node in nodes) { |
| 199 _state.add(node); |
| 200 } |
| 201 } |
| 202 |
| 203 /** |
| 204 * Output text without ending the current line. |
| 205 */ |
| 206 void write(Object obj) { |
| 207 _state.write(obj.toString()); |
| 208 } |
| 209 |
| 210 /** |
| 211 * Output text, ending the current line. |
| 212 */ |
| 213 void writeln([Object obj = '']) { |
| 214 _state.write('$obj\n'); |
| 215 } |
| 216 |
| 217 /** |
| 218 * Execute [callback], indenting any code it outputs by two spaces. |
| 219 */ |
| 220 void indent(void callback()) { |
| 221 String oldIndent = _state.indent; |
| 222 try { |
| 223 _state.indent += ' '; |
| 224 callback(); |
| 225 } finally { |
| 226 _state.indent = oldIndent; |
| 227 } |
| 228 } |
| 229 |
| 230 /** |
| 231 * Execute [callback], wrapping its output in an element with the given |
| 232 * [name] and [attributes]. |
| 233 */ |
| 234 void element(String name, Map<String, String> attributes, [void callback()]) { |
| 235 add(makeElement(name, attributes, collectHtml(callback))); |
| 236 } |
| 237 } |
| 238 |
| 239 /** |
| 240 * State used by [HtmlCodeGenerator]. |
| 241 */ |
| 242 class _HtmlCodeGeneratorState { |
| 243 List<dom.Node> buffer = <dom.Node>[]; |
| 244 String indent = ''; |
| 245 bool indentNeeded = true; |
| 246 |
| 247 void add(dom.Node node) { |
| 248 if (node is dom.Text) { |
| 249 write(node.text); |
| 250 } else { |
| 251 buffer.add(node); |
| 252 } |
| 253 } |
| 254 |
| 255 void write(String text) { |
| 256 if (text.isEmpty) { |
| 257 return; |
| 258 } |
| 259 if (indentNeeded) { |
| 260 buffer.add(new dom.Text(indent)); |
| 261 } |
| 262 List<String> lines = text.split('\n'); |
| 263 if (lines.last.isEmpty) { |
| 264 lines.removeLast(); |
| 265 buffer.add(new dom.Text(lines.join('\n$indent') + '\n')); |
| 266 indentNeeded = true; |
| 267 } else { |
| 268 buffer.add(new dom.Text(lines.join('\n$indent'))); |
| 269 indentNeeded = false; |
| 270 } |
| 271 } |
| 272 } |
| OLD | NEW |