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

Side by Side Diff: pkg/analysis_server/tool/spec/text_formatter.dart

Issue 1431683002: Refactor analysis server code generation to re-use logic from analyzer. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 5 years, 1 month 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
OLDNEW
(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 * Code for converting HTML into text, for use in doc comments.
7 */
8 library text.formatter;
9
10 import 'package:html/dom.dart' as dom;
11
12 import 'codegen_tools.dart';
13
14 final RegExp whitespace = new RegExp(r'\s');
15
16 /**
17 * Convert the HTML in [desc] into text, word wrapping at width [width].
18 *
19 * If [javadocStyle] is true, then the output is compatable with Javadoc,
20 * which understands certain HTML constructs.
21 */
22 String nodesToText(List<dom.Node> desc, int width, bool javadocStyle,
23 {bool removeTrailingNewLine: false}) {
24 _TextFormatter formatter = new _TextFormatter(width, javadocStyle);
25 return formatter.collectCode(() {
26 formatter.addAll(desc);
27 formatter.lineBreak(false);
28 }, removeTrailingNewLine: removeTrailingNewLine);
29 }
30
31 /**
32 * Engine that transforms HTML to text. The input HTML is processed one
33 * character at a time, gathering characters into words and words into lines.
34 */
35 class _TextFormatter extends CodeGenerator {
36 /**
37 * Word-wrapping width.
38 */
39 final int width;
40
41 /**
42 * The word currently being gathered.
43 */
44 String word = '';
45
46 /**
47 * The line currently being gathered.
48 */
49 String line = '';
50
51 /**
52 * True if a blank line should be inserted before the next word.
53 */
54 bool verticalSpaceNeeded = false;
55
56 /**
57 * True if no text has been output yet. This suppresses blank lines.
58 */
59 bool atStart = true;
60
61 /**
62 * True if we are processing a <pre> element, thus whitespace should be
63 * preserved.
64 */
65 bool preserveSpaces = false;
66
67 /**
68 * True if the output should be Javadoc compatible.
69 */
70 final bool javadocStyle;
71
72 _TextFormatter(this.width, this.javadocStyle);
73
74 /**
75 * Process an HTML node.
76 */
77 void add(dom.Node node) {
78 if (node is dom.Text) {
79 for (String char in node.text.split('')) {
80 if (preserveSpaces) {
81 wordBreak();
82 write(escape(char));
83 } else if (whitespace.hasMatch(char)) {
84 wordBreak();
85 } else {
86 resolveVerticalSpace();
87 word += escape(char);
88 }
89 }
90 } else if (node is dom.Element) {
91 switch (node.localName) {
92 case 'br':
93 lineBreak(false);
94 break;
95 case 'dl':
96 case 'dt':
97 case 'h1':
98 case 'h2':
99 case 'h3':
100 case 'h4':
101 case 'p':
102 lineBreak(true);
103 addAll(node.nodes);
104 lineBreak(true);
105 break;
106 case 'div':
107 lineBreak(false);
108 if (node.classes.contains('hangingIndent')) {
109 resolveVerticalSpace();
110 indentSpecial('', ' ', () {
111 addAll(node.nodes);
112 lineBreak(false);
113 });
114 } else {
115 addAll(node.nodes);
116 lineBreak(false);
117 }
118 break;
119 case 'ul':
120 lineBreak(false);
121 addAll(node.nodes);
122 lineBreak(false);
123 break;
124 case 'li':
125 lineBreak(false);
126 resolveVerticalSpace();
127 indentSpecial('- ', ' ', () {
128 addAll(node.nodes);
129 lineBreak(false);
130 });
131 break;
132 case 'dd':
133 lineBreak(true);
134 indent(() {
135 addAll(node.nodes);
136 lineBreak(true);
137 });
138 break;
139 case 'pre':
140 lineBreak(false);
141 resolveVerticalSpace();
142 if (javadocStyle) {
143 writeln('<pre>');
144 }
145 bool oldPreserveSpaces = preserveSpaces;
146 try {
147 preserveSpaces = true;
148 addAll(node.nodes);
149 } finally {
150 preserveSpaces = oldPreserveSpaces;
151 }
152 writeln();
153 if (javadocStyle) {
154 writeln('</pre>');
155 }
156 lineBreak(false);
157 break;
158 case 'a':
159 case 'b':
160 case 'body':
161 case 'html':
162 case 'i':
163 case 'span':
164 case 'tt':
165 addAll(node.nodes);
166 break;
167 case 'head':
168 break;
169 default:
170 throw new Exception('Unexpected HTML element: ${node.localName}');
171 }
172 } else {
173 throw new Exception('Unexpected HTML: $node');
174 }
175 }
176
177 /**
178 * Process a list of HTML nodes.
179 */
180 void addAll(List<dom.Node> nodes) {
181 for (dom.Node node in nodes) {
182 add(node);
183 }
184 }
185
186 /**
187 * Escape the given character for HTML.
188 */
189 String escape(String char) {
190 if (javadocStyle) {
191 switch (char) {
192 case '<':
193 return '&lt;';
194 case '>':
195 return '&gt;';
196 case '&':
197 return '&amp;';
198 }
199 }
200 return char;
201 }
202
203 /**
204 * Terminate the current word and/or line, if either is in progress.
205 */
206 void lineBreak(bool gap) {
207 wordBreak();
208 if (line.isNotEmpty) {
209 writeln(line);
210 line = '';
211 }
212 if (gap && !atStart) {
213 verticalSpaceNeeded = true;
214 }
215 }
216
217 /**
218 * Insert vertical space if necessary.
219 */
220 void resolveVerticalSpace() {
221 if (verticalSpaceNeeded) {
222 writeln();
223 verticalSpaceNeeded = false;
224 }
225 }
226
227 /**
228 * Terminate the current word, if a word is in progress.
229 */
230 void wordBreak() {
231 if (word.isNotEmpty) {
232 atStart = false;
233 if (line.isNotEmpty) {
234 if (indentWidth + line.length + 1 + word.length <= width) {
235 line += ' $word';
236 } else {
237 writeln(line);
238 line = word;
239 }
240 } else {
241 line = word;
242 }
243 word = '';
244 }
245 }
246 }
OLDNEW
« no previous file with comments | « pkg/analysis_server/tool/spec/implied_types.dart ('k') | pkg/analysis_server/tool/spec/to_html.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698