Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(77)

Side by Side Diff: pkg/csslib/lib/src/css_printer.dart

Issue 23168002: move csslib into dart svn (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « pkg/csslib/lib/src/analyzer.dart ('k') | pkg/csslib/lib/src/messages.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2013, 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 part of csslib.visitor;
6
7 /**
8 * Visitor that produces a formatted string representation of the CSS tree.
9 */
10 class CssPrinter extends Visitor {
11 StringBuffer _buff = new StringBuffer();
12 bool prettyPrint = true;
13
14 /**
15 * Walk the [tree] Stylesheet. [pretty] if true emits line breaks, extra
16 * spaces, friendly property values, etc., if false emits compacted output.
17 */
18 void visitTree(StyleSheet tree, {bool pretty: false}) {
19 prettyPrint = pretty;
20 _buff = new StringBuffer();
21 visitStyleSheet(tree);
22 }
23
24 /** Appends [str] to the output buffer. */
25 void emit(String str) {
26 _buff.write(str);
27 }
28
29 /** Returns the output buffer. */
30 String toString() => _buff.toString().trim();
31
32 String get _newLine => prettyPrint ? '\n' : ' ';
33 String get _sp => prettyPrint ? ' ' : '';
34
35 // TODO(terry): When adding obfuscation we'll need isOptimized (compact w/
36 // obufuscation) and have isTesting (compact no obfuscation) and
37 // isCompact would be !prettyPrint. We'll need another boolean
38 // flag for obfuscation.
39 bool get _isTesting => !prettyPrint;
40
41 void visitCssComment(CssComment node) {
42 emit('/* ${node.comment} */');
43 }
44
45 void visitCommentDefinition(CommentDefinition node) {
46 emit('<!-- ${node.comment} -->');
47 }
48
49 void visitMediaExpression(MediaExpression node) {
50 emit(node.andOperator ? ' AND ' : ' ');
51 emit('(${node.mediaFeature}:');
52 visitExpressions(node.exprs);
53 emit(')');
54 }
55
56 void visitMediaQuery(MediaQuery query) {
57 var unary = query.hasUnary ? ' ${query.unary}' : '';
58 var mediaType = query.hasMediaType ? ' ${query.mediaType}' : '';
59 emit('$unary$mediaType');
60 for (var expression in query.expressions) {
61 visitMediaExpression(expression);
62 }
63 }
64
65 void emitMediaQueries(queries) {
66 var queriesLen = queries.length;
67 for (var i = 0; i < queriesLen; i++) {
68 var query = queries[i];
69 if (query.hasMediaType && i > 0) emit(',');
70 visitMediaQuery(query);
71 }
72 }
73
74 void visitMediaDirective(MediaDirective node) {
75 emit(' @media');
76 emitMediaQueries(node.mediaQueries);
77 emit(' {');
78 for (var ruleset in node.rulesets) {
79 ruleset.visit(this);
80 }
81 emit('$_newLine\}');
82 }
83
84 void visitHostDirective(HostDirective node) {
85 emit('\n@host {');
86 for (var ruleset in node.rulesets) {
87 ruleset.visit(this);
88 }
89 emit('$_newLine\}');
90 }
91
92 /**
93 * @page : pseudoPage {
94 * decls
95 * }
96 */
97 void visitPageDirective(PageDirective node) {
98 emit('$_newLine@page');
99 if (node.hasIdent || node.hasPseudoPage) {
100 if (node.hasIdent) emit(' ');
101 emit(node._ident);
102 emit(node.hasPseudoPage ? ':${node._pseudoPage}' : '');
103 }
104 emit(' ');
105
106 var declsMargin = node._declsMargin;
107 int declsMarginLength = declsMargin.length;
108 for (var i = 0; i < declsMarginLength; i++) {
109 if (i > 0) emit(_newLine);
110 emit('{$_newLine');
111 declsMargin[i].visit(this);
112 emit('}');
113 }
114 }
115
116 /** @charset "charset encoding" */
117 void visitCharsetDirective(CharsetDirective node) {
118 emit('$_newLine@charset "${node.charEncoding}";');
119 }
120
121 void visitImportDirective(ImportDirective node) {
122 bool isStartingQuote(String ch) => ('\'"'.indexOf(ch[0]) >= 0);
123
124 if (_isTesting) {
125 // Emit assuming url() was parsed; most suite tests use url function.
126 emit(' @import url(${node.import})');
127 } else if (isStartingQuote(node.import)) {
128 emit(' @import ${node.import}');
129 } else {
130 // url(...) isn't needed only a URI can follow an @import directive; emit
131 // url as a string.
132 emit(' @import "${node.import}"');
133 }
134 emitMediaQueries(node.mediaQueries);
135 emit(';');
136 }
137
138 void visitKeyFrameDirective(KeyFrameDirective node) {
139 emit('$_newLine${node.keyFrameName} ');
140 node._name.visit(this);
141 emit('$_sp{$_newLine');
142 for (final block in node._blocks) {
143 block.visit(this);
144 }
145 emit('}');
146 }
147
148 void visitFontFaceDirective(FontFaceDirective node) {
149 emit('$_newLine@font-face ');
150 emit('$_sp{$_newLine');
151 node._declarations.visit(this);
152 emit('}');
153 }
154
155 void visitKeyFrameBlock(KeyFrameBlock node) {
156 emit('$_sp$_sp');
157 node._blockSelectors.visit(this);
158 emit('$_sp{$_newLine');
159 node._declarations.visit(this);
160 emit('$_sp$_sp}$_newLine');
161 }
162
163 void visitStyletDirective(StyletDirective node) {
164 emit('/* @stylet export as ${node._dartClassName} */\n');
165 }
166
167 void visitNamespaceDirective(NamespaceDirective node) {
168 bool isStartingQuote(String ch) => ('\'"'.indexOf(ch) >= 0);
169
170 if (isStartingQuote(node._uri)) {
171 emit(' @namespace ${node.prefix}"${node._uri}"');
172 } else {
173 if (_isTesting) {
174 // Emit exactly was we parsed.
175 emit(' @namespace ${node.prefix}url(${node._uri})');
176 } else {
177 // url(...) isn't needed only a URI can follow a:
178 // @namespace prefix directive.
179 emit(' @namespace ${node.prefix}${node._uri}');
180 }
181 }
182 emit(';');
183 }
184
185 void visitVarDefinitionDirective(VarDefinitionDirective node) {
186 visitVarDefinition(node.def);
187 emit(';$_newLine');
188 }
189
190 void visitRuleSet(RuleSet node) {
191 emit("$_newLine");
192 node._selectorGroup.visit(this);
193 emit(" {$_newLine");
194 node._declarationGroup.visit(this);
195 emit("}");
196 }
197
198 void visitDeclarationGroup(DeclarationGroup node) {
199 var declarations = node._declarations;
200 var declarationsLength = declarations.length;
201 for (var i = 0; i < declarationsLength; i++) {
202 if (i > 0) emit(_newLine);
203 emit("$_sp$_sp");
204 declarations[i].visit(this);
205 emit(";");
206 }
207 if (declarationsLength > 0) emit(_newLine);
208 }
209
210 void visitMarginGroup(MarginGroup node) {
211 var margin_sym_name =
212 TokenKind.idToValue(TokenKind.MARGIN_DIRECTIVES, node.margin_sym);
213
214 emit("@$margin_sym_name {$_newLine");
215
216 visitDeclarationGroup(node);
217
218 emit("}$_newLine");
219 }
220
221 void visitDeclaration(Declaration node) {
222 String importantAsString() => node.important ? '$_sp!important' : '';
223
224 emit("${node.property}: ");
225 node._expression.visit(this);
226
227 emit("${importantAsString()}");
228 }
229
230 void visitVarDefinition(VarDefinition node) {
231 emit("var-${node.definedName}: ");
232 node._expression.visit(this);
233 }
234
235 void visitSelectorGroup(SelectorGroup node) {
236 var selectors = node._selectors;
237 var selectorsLength = selectors.length;
238 for (var i = 0; i < selectorsLength; i++) {
239 if (i > 0) emit(',$_sp');
240 selectors[i].visit(this);
241 }
242 }
243
244 void visitSimpleSelectorSequence(SimpleSelectorSequence node) {
245 emit('${node._combinatorToString}');
246 node._selector.visit(this);
247 }
248
249 void visitSimpleSelector(SimpleSelector node) {
250 emit(node.name);
251 }
252
253 void visitNamespaceSelector(NamespaceSelector node) {
254 emit("${node.namespace}|${node.nameAsSimpleSelector.name}");
255 }
256
257 void visitElementSelector(ElementSelector node) {
258 emit("${node.name}");
259 }
260
261 void visitAttributeSelector(AttributeSelector node) {
262 emit("[${node.name}${node.matchOperator()}${node.valueToString()}]");
263 }
264
265 void visitIdSelector(IdSelector node) {
266 emit("#${node.name}");
267 }
268
269 void visitClassSelector(ClassSelector node) {
270 emit(".${node.name}");
271 }
272
273 void visitPseudoClassSelector(PseudoClassSelector node) {
274 emit(":${node.name}");
275 }
276
277 void visitPseudoElementSelector(PseudoElementSelector node) {
278 emit("::${node.name}");
279 }
280
281 void visitPseudoClassFunctionSelector(PseudoClassFunctionSelector node) {
282 emit(":${node.name}(");
283 node.expression.visit(this);
284 emit(')');
285 }
286
287 void visitPseudoElementFunctionSelector(PseudoElementFunctionSelector node) {
288 emit("::${node.name}(");
289 node.expression.visit(this);
290 emit(')');
291 }
292
293 void visitNegationSelector(NegationSelector node) {
294 emit(':not(');
295 node.negationArg.visit(this);
296 emit(')');
297 }
298
299 void visitSelectorExpression(SelectorExpression node) {
300 var expressions = node._expressions;
301 var expressionsLength = expressions.length;
302 for (var i = 0; i < expressionsLength; i++) {
303 // Add space seperator between terms without an operator.
304 var expression = expressions[i];
305 expression.visit(this);
306 }
307 }
308
309 void visitUnicodeRangeTerm(UnicodeRangeTerm node) {
310 if (node.hasSecond) {
311 emit("U+${node.first}-${node.second}");
312 } else {
313 emit("U+${node.first}");
314 }
315 }
316
317 void visitLiteralTerm(LiteralTerm node) {
318 emit(node.text);
319 }
320
321 void visitHexColorTerm(HexColorTerm node) {
322 var mappedName;
323 if (_isTesting && (node.value is! BAD_HEX_VALUE)) {
324 mappedName = TokenKind.hexToColorName(node.value);
325 }
326 if (mappedName == null) {
327 mappedName = '#${node.text}';
328 }
329
330 emit(mappedName);
331 }
332
333 void visitNumberTerm(NumberTerm node) {
334 visitLiteralTerm(node);
335 }
336
337 void visitUnitTerm(UnitTerm node) {
338 emit(node.toString());
339 }
340
341 void visitLengthTerm(LengthTerm node) {
342 emit(node.toString());
343 }
344
345 void visitPercentageTerm(PercentageTerm node) {
346 emit('${node.text}%');
347 }
348
349 void visitEmTerm(EmTerm node) {
350 emit('${node.text}em');
351 }
352
353 void visitExTerm(ExTerm node) {
354 emit('${node.text}ex');
355 }
356
357 void visitAngleTerm(AngleTerm node) {
358 emit(node.toString());
359 }
360
361 void visitTimeTerm(TimeTerm node) {
362 emit(node.toString());
363 }
364
365 void visitFreqTerm(FreqTerm node) {
366 emit(node.toString());
367 }
368
369 void visitFractionTerm(FractionTerm node) {
370 emit('${node.text}fr');
371 }
372
373 void visitUriTerm(UriTerm node) {
374 emit('url("${node.text}")');
375 }
376
377 void visitResolutionTerm(ResolutionTerm node) {
378 emit(node.toString());
379 }
380
381 void visitViewportTerm(ViewportTerm node) {
382 emit(node.toString());
383 }
384
385 void visitFunctionTerm(FunctionTerm node) {
386 // TODO(terry): Optimize rgb to a hexcolor.
387 emit('${node.text}(');
388 node._params.visit(this);
389 emit(')');
390 }
391
392 void visitGroupTerm(GroupTerm node) {
393 emit('(');
394 var terms = node._terms;
395 var termsLength = terms.length;
396 for (var i = 0; i < termsLength; i++) {
397 if (i > 0) emit('$_sp');
398 terms[i].visit(this);
399 }
400 emit(')');
401 }
402
403 void visitItemTerm(ItemTerm node) {
404 emit('[${node.text}]');
405 }
406
407 void visitIE8Term(IE8Term node) {
408 visitLiteralTerm(node);
409 }
410
411 void visitOperatorSlash(OperatorSlash node) {
412 emit('/');
413 }
414
415 void visitOperatorComma(OperatorComma node) {
416 emit(',');
417 }
418
419 void visitOperatorPlus(OperatorPlus node) {
420 emit('+');
421 }
422
423 void visitOperatorMinus(OperatorMinus node) {
424 emit('-');
425 }
426
427 void visitVarUsage(VarUsage node) {
428 emit('var(${node.name}');
429 if (!node.defaultValues.isEmpty) {
430 emit(',');
431 for (var defaultValue in node.defaultValues) {
432 emit(' ');
433 defaultValue.visit(this);
434 }
435 }
436 emit(')');
437 }
438
439 void visitExpressions(Expressions node) {
440 var expressions = node.expressions;
441 var expressionsLength = expressions.length;
442 for (var i = 0; i < expressionsLength; i++) {
443 // Add space seperator between terms without an operator.
444 // TODO(terry): Should have a BinaryExpression to solve this problem.
445 var expression = expressions[i];
446 if (i > 0 &&
447 !(expression is OperatorComma || expression is OperatorSlash)) {
448 emit(' ');
449 }
450 expression.visit(this);
451 }
452 }
453
454 void visitBinaryExpression(BinaryExpression node) {
455 // TODO(terry): TBD
456 throw UnimplementedError;
457 }
458
459 void visitUnaryExpression(UnaryExpression node) {
460 // TODO(terry): TBD
461 throw UnimplementedError;
462 }
463
464 void visitIdentifier(Identifier node) {
465 emit(node.name);
466 }
467
468 void visitWildcard(Wildcard node) {
469 emit('*');
470 }
471
472 void visitDartStyleExpression(DartStyleExpression node) {
473 // TODO(terry): TBD
474 throw UnimplementedError;
475 }
476 }
OLDNEW
« no previous file with comments | « pkg/csslib/lib/src/analyzer.dart ('k') | pkg/csslib/lib/src/messages.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698