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

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 }
25 }
26
12 /// Box with script source code in it. 27 /// Box with script source code in it.
13 @CustomTag('script-inset') 28 @CustomTag('script-inset')
14 class ScriptInsetElement extends ObservatoryElement { 29 class ScriptInsetElement extends ObservatoryElement {
15 @published Script script; 30 @published Script script;
16 31
17 /// Set the height to make the script inset scroll. Otherwise it 32 /// Set the height to make the script inset scroll. Otherwise it
18 /// will show from startPos to endPos. 33 /// will show from startPos to endPos.
19 @published String height = null; 34 @published String height = null;
20 35
21 @published int currentPos; 36 @published int currentPos;
22 @published int startPos; 37 @published int startPos;
23 @published int endPos; 38 @published int endPos;
24 39
25 @observable int currentLine; 40 @observable int currentLine;
26 @observable int currentCol; 41 @observable int currentCol;
27 @observable int startLine; 42 @observable int startLine;
28 @observable int endLine; 43 @observable int endLine;
29 @observable bool linesReady = false; 44 @observable bool linesReady = false;
30 45
31 // Contents are either ScriptLine or ScriptElipsis. 46 var annotations = [];
32 @observable List lines = toObservable([]); 47 var annotationsCursor;
48
49 StreamSubscription scriptChangeSubscription;
33 50
34 String makeLineId(int line) { 51 String makeLineId(int line) {
35 return 'line-$line'; 52 return 'line-$line';
36 } 53 }
37 54
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() { 55 void _scrollToCurrentPos() {
51 var line = shadowRoot.querySelector('#line-$currentLine'); 56 var line = querySelector('#${makeLineId(currentLine)}');
52 if (line != null) { 57 if (line != null) {
53 line.scrollIntoView(); 58 line.scrollIntoView();
54 } 59 }
55 } 60 }
56 61
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() { 62 void detached() {
71 if (_observer != null) { 63 if (scriptChangeSubscription != null) {
72 _observer.disconnect(); 64 // Don't leak. If only Dart and Javascript exposed weak references...
73 _observer = null; 65 scriptChangeSubscription.cancel();
66 scriptChangeSubscription = null;
74 } 67 }
75 super.detached(); 68 super.detached();
76 } 69 }
77 70
78 void currentPosChanged(oldValue) { 71 void currentPosChanged(oldValue) {
79 _updateLines(); 72 update();
80 _scrollToCurrentPos(); 73 _scrollToCurrentPos();
81 } 74 }
82 75
83 void startPosChanged(oldValue) { 76 void startPosChanged(oldValue) {
84 _updateLines(); 77 update();
85 } 78 }
86 79
87 void endPosChanged(oldValue) { 80 void endPosChanged(oldValue) {
88 _updateLines(); 81 update();
89 } 82 }
90 83
91 void scriptChanged(oldValue) { 84 void scriptChanged(oldValue) {
92 _updateLines(); 85 update();
93 } 86 }
94 87
95 var _updateFuture; 88 Element a(String text) => new AnchorElement()..text = text;
89 Element span(String text) => new SpanElement()..text = text;
96 90
97 void _updateLines() { 91 Element hitsUnknown(Element element) {
98 linesReady = false; 92 element.classes.add('hitsNone');
99 if (_updateFuture != null) { 93 element.title = "";
100 // Already scheduled. 94 return element;
101 return; 95 }
102 } 96 Element hitsNotExecuted(Element element) {
97 element.classes.add('hitsNotExecuted');
98 element.title = "Line did not execute";
99 return element;
100 }
101 Element hitsExecuted(Element element) {
102 element.classes.add('hitsExecuted');
103 element.title = "Line did execute";
104 return element;
105 }
106
107 Element container;
108
109 void update() {
103 if (script == null) { 110 if (script == null) {
104 // Wait for script to be assigned.
105 return; 111 return;
Cutch 2015/02/28 00:37:04 In the case that a script was not null and then re
rmacnak 2015/03/02 19:08:26 Done.
106 } 112 }
107 if (!script.loaded) { 113 if (!script.loaded) {
108 _updateFuture = script.load().then((_) { 114 return script.load().then((_) => update());
109 if (script.loaded) {
110 _updateFuture = null;
111 _updateLines();
112 }
113 });
114 return;
115 } 115 }
116
117 if (scriptChangeSubscription == null) {
118 scriptChangeSubscription = script.changes.listen((_) => update());
119 }
120
121 computeAnnotations();
122
123 var table = linesTable();
124 if (container == null) {
125 // Indirect to avoid deleting the style element.
126 container = new DivElement();
127 shadowRoot.append(container);
128 }
129 container.children.clear();
130 container.children.add(table);
131 }
132
133 void computeAnnotations() {
116 startLine = (startPos != null 134 startLine = (startPos != null
117 ? script.tokenToLine(startPos) 135 ? script.tokenToLine(startPos)
118 : 1); 136 : 1);
119 currentLine = (currentPos != null 137 currentLine = (currentPos != null
120 ? script.tokenToLine(currentPos) 138 ? script.tokenToLine(currentPos)
121 : null); 139 : null);
122 currentCol = (currentPos != null 140 currentCol = (currentPos != null
123 ? (script.tokenToCol(currentPos) - 1) // make this 0-based. 141 ? (script.tokenToCol(currentPos) - 1) // make this 0-based.
124 : null); 142 : null);
125 endLine = (endPos != null 143 endLine = (endPos != null
126 ? script.tokenToLine(endPos) 144 ? script.tokenToLine(endPos)
127 : script.lines.length); 145 : script.lines.length);
128 146
129 lines.clear(); 147 annotations.clear();
148 if (currentLine != null) {
149 var a = new Annotation();
150 a.line = currentLine;
151 a.columnStart = currentCol;
152 a.columnStop = currentCol + 1;
153 a.title = "Current invocation";
Cutch 2015/02/28 00:37:04 currentPos doesn't imply invocation. It is just th
rmacnak 2015/03/02 19:08:26 We should replace use currentPos with specific ann
154 annotations.add(a);
155 }
156
157 // TODO(rmacnak): Call site data.
158 }
159
160 Element linesTable() {
161 var table = new DivElement();
162 table.classes.add("sourceTable");
163
164 annotationsCursor = 0;
165
130 int blankLineCount = 0; 166 int blankLineCount = 0;
131 for (int i = (startLine - 1); i <= (endLine - 1); i++) { 167 for (int i = (startLine - 1); i <= (endLine - 1); i++) {
132 if (script.lines[i].isBlank) { 168 if (script.lines[i].isBlank) {
133 // Try to introduce elipses if there are 4 or more contiguous blank line s. 169 // Try to introduce elipses if there are 4 or more contiguous
170 // blank lines.
134 blankLineCount++; 171 blankLineCount++;
135 } else { 172 } else {
136 if (blankLineCount > 0) { 173 if (blankLineCount > 0) {
137 int firstBlank = i - blankLineCount; 174 int firstBlank = i - blankLineCount;
138 int lastBlank = i - 1; 175 int lastBlank = i - 1;
139 if (blankLineCount < 4) { 176 if (blankLineCount < 4) {
140 // Too few blank lines for an elipsis. 177 // Too few blank lines for an elipsis.
141 for (int j = firstBlank; j <= lastBlank; j++) { 178 for (int j = firstBlank; j <= lastBlank; j++) {
142 lines.add(script.lines[j]); 179 table.append(lineElement(script.lines[j]));
143 } 180 }
144 } else { 181 } else {
145 // Add an elipsis for the skipped region. 182 // Add an elipsis for the skipped region.
146 lines.add(script.lines[firstBlank]); 183 table.append(lineElement(script.lines[firstBlank]));
147 lines.add(null); 184 table.append(lineElement(null));
148 lines.add(script.lines[lastBlank]); 185 table.append(lineElement(script.lines[lastBlank]));
149 } 186 }
150 blankLineCount = 0; 187 blankLineCount = 0;
151 } 188 }
152 lines.add(script.lines[i]); 189 table.append(lineElement(script.lines[i]));
153 } 190 }
154 } 191 }
155 linesReady = true; 192
193 return table;
Cutch 2015/02/28 00:37:04 You no longer update linesReady- why?
rmacnak 2015/03/02 19:08:26 Unused. Removed the field.
194 }
195
196 // Assumes annotations are sorted.
197 Annotation nextAnnotationOnLine(int line) {
198 if (annotationsCursor >= annotations.length) return null;
199 var annotation = annotations[annotationsCursor];
200 if (annotation.line != line) return null;
201 annotationsCursor++;
202 return annotation;
203 }
204
205 Element lineElement(ScriptLine line) {
206 var e = new DivElement();
207 e.classes.add("sourceRow");
208 e.append(lineBreakpointElement(line));
209 e.append(lineNumberElement(line));
210 e.append(lineSourceElement(line));
211 return e;
212 }
213
214 Element lineBreakpointElement(ScriptLine line) {
215 return new Element.tag("breakpoint-toggle")
216 ..line = line;
217 }
218
219 Element lineNumberElement(ScriptLine line) {
220 var lineNumber = line == null ? "..." : line.line;
221 var e = span("$nbsp$lineNumber$nbsp");
222
223 if ((line == null) || (line.hits == null)) {
224 hitsUnknown(e);
225 } else if (line.hits == 0) {
226 hitsNotExecuted(e);
227 } else {
228 hitsExecuted(e);
229 }
230
231 return e;
232 }
233
234 Element lineSourceElement(ScriptLine line) {
235 var e = new DivElement();
236 e.classes.add("sourceItem");
237
238 if (line != null) {
239 if (line.line == currentLine) {
240 e.classes.add("sourceItemCurrent");
241 }
242
243 e.id = makeLineId(line.line);
244
245 var position = 0;
246 consumeUntil(var stop) {
247 if (stop <= position) return; // Empty gap between annotations/boundrie s.
248 var chunk = line.text.substring(position, stop);
249 var chunkNode = span(chunk);
250 e.append(chunkNode);
251 position = stop;
252 return chunkNode;
253 }
254
255 // TODO(rmacnak): Tolerate overlapping annotations.
256 var annotation;
257 while ((annotation = nextAnnotationOnLine(line.line)) != null) {
258 consumeUntil(annotation.columnStart);
259 annotation.applyStyleTo(consumeUntil(annotation.columnStop));
260 }
261 consumeUntil(line.text.length);
262 }
263
264 return e;
156 } 265 }
157 266
158 ScriptInsetElement.created() : super.created(); 267 ScriptInsetElement.created() : super.created();
159 } 268 }
160 269
161 @CustomTag('breakpoint-toggle') 270 @CustomTag('breakpoint-toggle')
162 class BreakpointToggleElement extends ObservatoryElement { 271 class BreakpointToggleElement extends ObservatoryElement {
163 @published ScriptLine line; 272 @published ScriptLine line;
164 @observable bool busy = false; 273 @observable bool busy = false;
165 274
(...skipping 10 matching lines...) Expand all
176 } else { 285 } else {
177 // Existing breakpoint. Remove it. 286 // Existing breakpoint. Remove it.
178 line.script.isolate.removeBreakpoint(line.bpt).then((_) { 287 line.script.isolate.removeBreakpoint(line.bpt).then((_) {
179 busy = false; 288 busy = false;
180 }); 289 });
181 } 290 }
182 } 291 }
183 292
184 BreakpointToggleElement.created() : super.created(); 293 BreakpointToggleElement.created() : super.created();
185 } 294 }
OLDNEW
« no previous file with comments | « no previous file | runtime/observatory/lib/src/elements/script_inset.html » ('j') | runtime/observatory/lib/src/service/object.dart » ('J')

Powered by Google App Engine
This is Rietveld 408576698