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

Side by Side Diff: runtime/observatory/lib/src/elements/script_inset.dart

Issue 959043003: Build script views programmatically. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 5 years, 9 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
OLDNEW
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file 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 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. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 library script_inset_element; 5 library script_inset_element;
6 6
7 import 'dart:html'; 7 import 'dart:html';
8 import 'observatory_element.dart'; 8 import 'observatory_element.dart';
9 import 'package:observatory/service.dart'; 9 import 'package:observatory/service.dart';
10 import 'package:polymer/polymer.dart'; 10 import 'package:polymer/polymer.dart';
11 11
12 const nbsp = "\u00A0";
13
14 class Annotation {
15 int line;
16 int columnStart;
17 int columnStop;
18 String title;
19
20 void applyStyleTo(element) {
21 element.style.color = "blue";
22 element.style.textDecoration = "underline";
23 element.title = title;
24 print("Annotated ${element.text} as $title");
Cutch 2015/02/27 14:44:33 Remove before committing.
rmacnak 2015/02/27 20:55:34 Done.
25 }
26 }
27
12 /// Box with script source code in it. 28 /// Box with script source code in it.
13 @CustomTag('script-inset') 29 @CustomTag('script-inset')
14 class ScriptInsetElement extends ObservatoryElement { 30 class ScriptInsetElement extends ObservatoryElement {
15 @published Script script; 31 @published Script script;
16 32
17 /// Set the height to make the script inset scroll. Otherwise it 33 /// Set the height to make the script inset scroll. Otherwise it
18 /// will show from startPos to endPos. 34 /// will show from startPos to endPos.
19 @published String height = null; 35 @published String height = null;
20 36
21 @published int currentPos; 37 @published int currentPos;
22 @published int startPos; 38 @published int startPos;
23 @published int endPos; 39 @published int endPos;
24 40
25 @observable int currentLine; 41 @observable int currentLine;
26 @observable int currentCol; 42 @observable int currentCol;
27 @observable int startLine; 43 @observable int startLine;
28 @observable int endLine; 44 @observable int endLine;
29 @observable bool linesReady = false; 45 @observable bool linesReady = false;
30 46
31 // Contents are either ScriptLine or ScriptElipsis. 47 var annotations = [];
32 @observable List lines = toObservable([]); 48 var annotationsCursor;
49
50 StreamSubscription scriptChangeSubscription;
33 51
34 String makeLineId(int line) { 52 String makeLineId(int line) {
35 return 'line-$line'; 53 return 'line-$line';
36 } 54 }
37 55
38 String clip(String line, int start, [int limit]) {
39 try {
40 return line.substring(start, limit);
41 } catch (_) {
42 // NOTE(turnidge): Sometimes polymer updates give us garbage
43 // starts and limits during page updates.
44 return "OOB";
45 }
46 }
47
48 MutationObserver _observer;
49
50 void _scrollToCurrentPos() { 56 void _scrollToCurrentPos() {
51 var line = shadowRoot.querySelector('#line-$currentLine'); 57 var line = querySelector('#${makeLineId(currentLine)}');
52 if (line != null) { 58 if (line != null) {
53 line.scrollIntoView(); 59 line.scrollIntoView();
54 } 60 }
55 } 61 }
56 62
57 void _onMutation(mutations, observer) {
58 _scrollToCurrentPos();
59 }
60
61 void attached() {
62 super.attached();
63 var table = shadowRoot.querySelector('.sourceTable');
64 if (table != null) {
65 _observer = new MutationObserver(_onMutation);
66 _observer.observe(table, childList:true);
67 }
68 }
69
70 void detached() { 63 void detached() {
71 if (_observer != null) { 64 if (scriptChangeSubscription != null) {
72 _observer.disconnect(); 65 // Don't leak. If only Dart and Javascript exposed weak references...
73 _observer = null; 66 scriptChangeSubscription.cancel();
67 scriptChangeSubscription = null;
74 } 68 }
75 super.detached(); 69 super.detached();
76 } 70 }
77 71
78 void currentPosChanged(oldValue) { 72 void currentPosChanged(oldValue) {
79 _updateLines(); 73 update();
80 _scrollToCurrentPos(); 74 _scrollToCurrentPos();
81 } 75 }
82 76
83 void startPosChanged(oldValue) { 77 void startPosChanged(oldValue) {
84 _updateLines(); 78 update();
85 } 79 }
86 80
87 void endPosChanged(oldValue) { 81 void endPosChanged(oldValue) {
88 _updateLines(); 82 update();
89 } 83 }
90 84
91 void scriptChanged(oldValue) { 85 void scriptChanged(oldValue) {
92 _updateLines(); 86 update();
93 } 87 }
94 88
95 var _updateFuture; 89 // Styles.
90 Element a(String text) => new AnchorElement()..text = text;
91 Element span(String text) => new SpanElement()..text = text;
92 Element monospace(Element element) {
93 element.style.fontFamily = "consolas, courier, monospace";
94 return element;
95 }
96 Element row(Element element) {
97 element.style.display = "table-row";
98 return element;
99 }
100 Element cell(Element element) {
101 element.style.display = "table-cell";
102 element.style.verticalAlign = "top";
103 return element;
104 }
105 Element hitsUnknown(Element element) {
106 element.style.backgroundColor = "";
107 element.title = "";
108 return element;
109 }
110 Element hitsNotExecuted(Element element) {
111 element.style.backgroundColor = "#e66";
112 element.title = "Line did not execute";
113 return element;
114 }
115 Element hitsExecuted(Element element) {
116 element.style.backgroundColor = "#6d6";
117 element.title = "Line did execute";
118 return element;
119 }
96 120
97 void _updateLines() { 121 void update() {
98 linesReady = false; 122 if (script == null) return;
Cutch 2015/02/27 14:44:33 curlies- if ( ... ) { return; } should you ensure
rmacnak 2015/02/27 20:55:34 Done.
99 if (_updateFuture != null) { 123 if (!script.loaded) {
100 // Already scheduled. 124 return script.load().then((_) => update());
101 return;
102 } 125 }
103 if (script == null) { 126
104 // Wait for script to be assigned. 127 if (scriptChangeSubscription == null) {
105 return; 128 scriptChangeSubscription = script.changes.listen((_) => update());
106 } 129 }
107 if (!script.loaded) { 130
108 _updateFuture = script.load().then((_) { 131 computeAnnotations();
109 if (script.loaded) { 132
110 _updateFuture = null; 133 var table = linesTable();
111 _updateLines(); 134 children.clear();
112 } 135 children.add(table);
113 }); 136 }
114 return; 137
115 } 138 void computeAnnotations() {
116 startLine = (startPos != null 139 startLine = (startPos != null
117 ? script.tokenToLine(startPos) 140 ? script.tokenToLine(startPos)
118 : 1); 141 : 1);
119 currentLine = (currentPos != null 142 currentLine = (currentPos != null
120 ? script.tokenToLine(currentPos) 143 ? script.tokenToLine(currentPos)
121 : null); 144 : null);
122 currentCol = (currentPos != null 145 currentCol = (currentPos != null
123 ? (script.tokenToCol(currentPos) - 1) // make this 0-based. 146 ? (script.tokenToCol(currentPos) - 1) // make this 0-based.
124 : null); 147 : null);
125 endLine = (endPos != null 148 endLine = (endPos != null
126 ? script.tokenToLine(endPos) 149 ? script.tokenToLine(endPos)
127 : script.lines.length); 150 : script.lines.length);
128 151
129 lines.clear(); 152 annotations.clear();
130 int blankLineCount = 0; 153 if (currentLine != null) {
131 for (int i = (startLine - 1); i <= (endLine - 1); i++) { 154 var a = new Annotation();
132 if (script.lines[i].isBlank) { 155 a.line = currentLine;
133 // Try to introduce elipses if there are 4 or more contiguous blank line s. 156 a.columnStart = currentCol;
134 blankLineCount++; 157 a.columnStop = currentCol + 1;
135 } else { 158 a.title = "Current invocation";
136 if (blankLineCount > 0) { 159 annotations.add(a);
137 int firstBlank = i - blankLineCount; 160 }
138 int lastBlank = i - 1; 161
139 if (blankLineCount < 4) { 162 // TODO(rmacnak): Call site data.
140 // Too few blank lines for an elipsis. 163 }
141 for (int j = firstBlank; j <= lastBlank; j++) { 164
142 lines.add(script.lines[j]); 165 Element linesTable() {
143 } 166 var table = new DivElement();
144 } else { 167 table.style.fontFamily = "monospace";
Cutch 2015/02/27 14:44:33 use css classes defined in html instead of setting
rmacnak 2015/02/27 20:55:34 Done.
145 // Add an elipsis for the skipped region. 168 table.style.fontWeight = "400";
146 lines.add(script.lines[firstBlank]); 169 table.style.display = "table";
147 lines.add(null); 170 table.style.backgroundColor = "#f5f5f5";
148 lines.add(script.lines[lastBlank]); 171 table.style.border = "1px solid #ccc";
149 } 172 table.style.padding = "10px";
150 blankLineCount = 0; 173 table.style.overflowY = "auto";
151 } 174 table.style.width = "100%";
152 lines.add(script.lines[i]); 175
176 int lineNumber = 1;
177 annotationsCursor = 0;
178 for (ScriptLine line in script.lines) {
179 if (startLine <= lineNumber && lineNumber <= endLine) {
180 table.append(lineElement(line));
153 } 181 }
182 lineNumber++;
154 } 183 }
155 linesReady = true; 184
185 return table;
186 }
187
188 // Assumes annotations are sorted.
189 Annotation nextAnnotationOnLine(int line) {
190 if (annotationsCursor >= annotations.length) return null;
191 var annotation = annotations[annotationsCursor];
192 if (annotation.line != line) return null;
193 annotationsCursor++;
194 return annotation;
195 }
196
197 Element lineElement(ScriptLine line) {
198 return row(new DivElement())
199 ..append(cell(lineBreakpointElement(line)))
200 ..append(cell(lineNumberElement(line)))
201 ..append(cell(lineSourceElement(line)));
202 }
203
204 Element lineBreakpointElement(ScriptLine line) {
205 return new Element.tag("breakpoint-toggle")
206 ..line = line;
207 }
208
209 Element lineNumberElement(ScriptLine line) {
210 var lineNumber = line.line;
211 var node = monospace(span("$nbsp$lineNumber$nbsp"));
212 node.style.textAlign = "right";
213 node.style.color = "#a8a8a8";
214
215 if (line.hits == null) hitsUnknown(node);
Cutch 2015/02/27 14:44:33 braces and new lines please
rmacnak 2015/02/27 20:55:34 Done.
216 else if (line.hits == 0) hitsNotExecuted(node);
217 else hitsExecuted(node);
218
219 return node;
220 }
221
222 Element lineSourceElement(ScriptLine line) {
223 var node = new DivElement();
224 node.style.whiteSpace = "pre";
225 node.id = makeLineId(line.line);
226
227 var position = 0;
228 consumeUntil(var stop) {
229 if (stop <= position) return; // Empty gap between annotations/boundries.
230 var chunk = line.text.substring(position, stop);
231 var chunkNode = monospace(span(chunk));
232 node.append(chunkNode);
233 position = stop;
234 return chunkNode;
235 }
236
237 // TODO(rmacnak): Tolerate overlapping annotations.
238 var annotation;
239 while ((annotation = nextAnnotationOnLine(line.line)) != null) {
240 consumeUntil(annotation.columnStart);
241 annotation.applyStyleTo(consumeUntil(annotation.columnStop));
242 }
243 consumeUntil(line.text.length);
244
245 return node;
156 } 246 }
157 247
158 ScriptInsetElement.created() : super.created(); 248 ScriptInsetElement.created() : super.created();
159 } 249 }
160 250
161 @CustomTag('breakpoint-toggle') 251 @CustomTag('breakpoint-toggle')
162 class BreakpointToggleElement extends ObservatoryElement { 252 class BreakpointToggleElement extends ObservatoryElement {
163 @published ScriptLine line; 253 @published ScriptLine line;
164 @observable bool busy = false; 254 @observable bool busy = false;
165 255
(...skipping 10 matching lines...) Expand all
176 } else { 266 } else {
177 // Existing breakpoint. Remove it. 267 // Existing breakpoint. Remove it.
178 line.script.isolate.removeBreakpoint(line.bpt).then((_) { 268 line.script.isolate.removeBreakpoint(line.bpt).then((_) {
179 busy = false; 269 busy = false;
180 }); 270 });
181 } 271 }
182 } 272 }
183 273
184 BreakpointToggleElement.created() : super.created(); 274 BreakpointToggleElement.created() : super.created();
185 } 275 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698