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

Side by Side Diff: dart/site/try/src/editor.dart

Issue 197923002: Mock up code completion. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge
Patch Set: Created 6 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 trydart.editor; 5 library trydart.editor;
6 6
7 import 'dart:html'; 7 import 'dart:html';
8 8
9 import 'dart:async' show
10 Timer;
11
12 import 'dart:convert' show
13 JSON;
14
9 import '../../../sdk/lib/_internal/compiler/implementation/scanner/scannerlib.da rt' 15 import '../../../sdk/lib/_internal/compiler/implementation/scanner/scannerlib.da rt'
10 show 16 show
11 EOF_TOKEN, 17 EOF_TOKEN,
12 StringScanner, 18 StringScanner,
13 Token; 19 Token;
14 20
15 import '../../../sdk/lib/_internal/compiler/implementation/source_file.dart' sho w 21 import '../../../sdk/lib/_internal/compiler/implementation/source_file.dart' sho w
16 StringSourceFile; 22 StringSourceFile;
17 23
18 import 'compilation.dart' show 24 import 'compilation.dart' show
19 scheduleCompilation; 25 scheduleCompilation;
20 26
21 import 'ui.dart' show 27 import 'ui.dart' show
28 applyingSettings,
22 currentTheme, 29 currentTheme,
23 hackDiv, 30 hackDiv,
24 inputPre, 31 inputPre,
25 observer, 32 observer,
26 outputDiv; 33 outputDiv;
27 34
28 import 'decoration.dart' show 35 import 'decoration.dart' show
36 CodeCompletionDecoration,
29 Decoration, 37 Decoration,
30 DiagnosticDecoration, 38 DiagnosticDecoration,
31 error, 39 error,
32 info, 40 info,
33 warning; 41 warning;
34 42
35 const String INDENT = '\u{a0}\u{a0}'; 43 const String INDENT = '\u{a0}\u{a0}';
36 44
45 Set<String> seenIdentifiers;
46
37 onKeyUp(KeyboardEvent e) { 47 onKeyUp(KeyboardEvent e) {
48 scheduleCodeCompletion();
49
50 if (e.keyCode == 40 && activeCompletion != null) {
51 e.preventDefault();
52 print('${e.keyCode}: ${e}');
53 return;
54 }
55
38 if (e.keyCode == 13) { 56 if (e.keyCode == 13) {
39 e.preventDefault(); 57 e.preventDefault();
40 Selection selection = window.getSelection(); 58 Selection selection = window.getSelection();
41 if (selection.isCollapsed && selection.anchorNode is Text) { 59 if (selection.isCollapsed && selection.anchorNode is Text) {
42 Text text = selection.anchorNode; 60 Text text = selection.anchorNode;
43 int offset = selection.anchorOffset; 61 int offset = selection.anchorOffset;
44 text.insertData(offset, '\n'); 62 text.insertData(offset, '\n');
45 selection.collapse(text, offset + 1); 63 selection.collapse(text, offset + 1);
46 } 64 }
47 } 65 }
48 // This is a hack to get Safari to send mutation events on contenteditable. 66 // This is a hack to get Safari to send mutation events on contenteditable.
49 var newDiv = new DivElement(); 67 var newDiv = new DivElement();
50 hackDiv.replaceWith(newDiv); 68 hackDiv.replaceWith(newDiv);
51 hackDiv = newDiv; 69 hackDiv = newDiv;
52 } 70 }
53 71
72 Timer codeCompletionTimer;
73
74 void scheduleCodeCompletion() {
75 if (applyingSettings) return;
76 if (codeCompletionTimer != null) {
77 codeCompletionTimer.cancel();
78 codeCompletionTimer = null;
79 }
80 codeCompletionTimer =
81 new Timer(const Duration(milliseconds: 1), displayCodeCompletion);
82 }
83
84 var activeCompletion;
85
86 void displayCodeCompletion() {
87 if (activeCompletion != null) {
88 activeCompletion.classes.remove('active');
89 activeCompletion = null;
90 }
91 Selection selection = window.getSelection();
92 if (!selection.isCollapsed) return;
93 var anchorNode = selection.anchorNode;
94 if (!inputPre.contains(anchorNode)) return;
95 int anchorOffset = selection.anchorOffset;
96 int type = anchorNode.nodeType;
97 if (type != Node.TEXT_NODE) return;
98 Text text = anchorNode;
99 var parent = text.parent;
100 if (parent is! Element) return;
101 parent.classes.add('active');
102 var ui = parent.query('.dart-code-completion');
103 if (ui == null) return;
104 activeCompletion = parent;
105 observer.disconnect();
106 ui.nodes.clear();
107 String prefix = text.data.substring(0, anchorOffset).trim();
108 if (!prefix.isEmpty) {
109 String encodedArg0 = Uri.encodeComponent('"$prefix"');
110 String mindQuery =
111 'http://dart-mind.appspot.com/rpc'
112 '?action=GetExportingPubCompletions'
113 '&arg0=$encodedArg0';
114 HttpRequest request = new HttpRequest();
115 request.open('GET', mindQuery, async: false);
116 try {
117 List<String> response = <String>[];
118 var sw = new Stopwatch();
119 if (false) {
120 sw.start();
121 request.send();
122 sw.stop();
123 if (request.status == 200) {
124 response = JSON.decode(request.responseText);
125 }
126 } else {
127 sw.start();
128 response =
129 seenIdentifiers.where(
130 (String identifier) => identifier != prefix && identifier.starts With(prefix))
kasperl 2014/03/13 07:39:58 Long line.
131 .toList(growable: false)
132 ..sort();
kasperl 2014/03/13 07:39:58 I think I'd prefer to not use .. for this. It's a
133 sw.stop();
134 }
135 response.forEach((String completion) {
136 ui.appendHtml('$completion<br>');
137 });
138 ui.appendHtml('${sw.elapsedMilliseconds}ms<br>');
139 } catch (e) {
140 window.console.dir(e);
141 }
142 }
143 observer.observe(inputPre, childList: true, characterData: true, subtree: true );
kasperl 2014/03/13 07:39:58 Long line.
144 }
145
54 bool isMalformedInput = false; 146 bool isMalformedInput = false;
55 String currentSource = ""; 147 String currentSource = "";
56 148
57 // TODO(ahe): This method should be cleaned up. It is too large. 149 // TODO(ahe): This method should be cleaned up. It is too large.
58 onMutation(List<MutationRecord> mutations, MutationObserver observer) { 150 onMutation(List<MutationRecord> mutations, MutationObserver observer) {
59 scheduleCompilation(); 151 // scheduleCompilation();
60 152
61 for (Element element in inputPre.queryAll('a[class="diagnostic"]>span')) { 153 for (Element element in inputPre.queryAll('a.diagnostic>span')) {
62 element.remove(); 154 element.remove();
63 } 155 }
156 for (Element element in inputPre.queryAll('.dart-code-completion')) {
157 element.remove();
158 }
159
64 // Discard clean-up mutations. 160 // Discard clean-up mutations.
65 observer.takeRecords(); 161 observer.takeRecords();
66 162
67 Selection selection = window.getSelection(); 163 Selection selection = window.getSelection();
68 164
69 while (!mutations.isEmpty) { 165 while (!mutations.isEmpty) {
70 for (MutationRecord record in mutations) { 166 for (MutationRecord record in mutations) {
71 String type = record.type; 167 String type = record.type;
72 switch (type) { 168 switch (type) {
73 169
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after
174 270
175 isMalformedInput = false; 271 isMalformedInput = false;
176 for (var n in new List.from(inputPre.nodes)) { 272 for (var n in new List.from(inputPre.nodes)) {
177 if (n is! Text) continue; 273 if (n is! Text) continue;
178 Text node = n; 274 Text node = n;
179 String text = node.text; 275 String text = node.text;
180 276
181 Token token = new StringScanner( 277 Token token = new StringScanner(
182 new StringSourceFile('', text), includeComments: true).tokenize(); 278 new StringSourceFile('', text), includeComments: true).tokenize();
183 int offset = 0; 279 int offset = 0;
280 seenIdentifiers = new Set<String>();
184 for (;token.kind != EOF_TOKEN; token = token.next) { 281 for (;token.kind != EOF_TOKEN; token = token.next) {
185 Decoration decoration = getDecoration(token); 282 Decoration decoration = getDecoration(token);
186 if (decoration == null) continue; 283 if (decoration == null) continue;
187 bool hasSelection = false; 284 bool hasSelection = false;
188 int selectionOffset = selection.anchorOffset; 285 int selectionOffset = selection.anchorOffset;
189 286
190 if (selection.isCollapsed && selection.anchorNode == node) { 287 if (selection.isCollapsed && selection.anchorNode == node) {
191 hasSelection = true; 288 hasSelection = true;
192 selectionOffset = selection.anchorOffset; 289 selectionOffset = selection.anchorOffset;
193 } 290 }
(...skipping 12 matching lines...) Expand all
206 } else { 303 } else {
207 selection.collapse(str, selectionOffset); 304 selection.collapse(str, selectionOffset);
208 } 305 }
209 } 306 }
210 node = after; 307 node = after;
211 } 308 }
212 } 309 }
213 310
214 window.localStorage['currentSource'] = currentSource; 311 window.localStorage['currentSource'] = currentSource;
215 312
313 if (activeCompletion != null) {
314 if (codeCompletionTimer != null) {
315 codeCompletionTimer.cancel();
316 codeCompletionTimer = null;
317 }
318 displayCodeCompletion();
319 }
320
216 // Discard highlighting mutations. 321 // Discard highlighting mutations.
217 observer.takeRecords(); 322 observer.takeRecords();
218 } 323 }
219 324
220 addDiagnostic(String kind, String message, int begin, int end) { 325 addDiagnostic(String kind, String message, int begin, int end) {
221 observer.disconnect(); 326 observer.disconnect();
222 Selection selection = window.getSelection(); 327 Selection selection = window.getSelection();
223 int offset = 0; 328 int offset = 0;
224 int anchorOffset = 0; 329 int anchorOffset = 0;
225 bool hasSelection = false; 330 bool hasSelection = false;
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
288 child.remove(); 393 child.remove();
289 parent.insertBefore(child, element); 394 parent.insertBefore(child, element);
290 } 395 }
291 element.remove(); 396 element.remove();
292 } 397 }
293 398
294 Decoration getDecoration(Token token) { 399 Decoration getDecoration(Token token) {
295 String tokenValue = token.value; 400 String tokenValue = token.value;
296 String tokenInfo = token.info.value; 401 String tokenInfo = token.info.value;
297 if (tokenInfo == 'string') return currentTheme.string; 402 if (tokenInfo == 'string') return currentTheme.string;
298 // if (tokenInfo == 'identifier') return identifier; 403 if (tokenInfo == 'identifier') {
404 seenIdentifiers.add(tokenValue);
405
406 print(seenIdentifiers);
407 return CodeCompletionDecoration.from(currentTheme.foreground);
408 }
299 if (tokenInfo == 'keyword') return currentTheme.keyword; 409 if (tokenInfo == 'keyword') return currentTheme.keyword;
300 if (tokenInfo == 'comment') return currentTheme.singleLineComment; 410 if (tokenInfo == 'comment') return currentTheme.singleLineComment;
301 if (tokenInfo == 'malformed input') { 411 if (tokenInfo == 'malformed input') {
302 isMalformedInput = true; 412 isMalformedInput = true;
303 return new DiagnosticDecoration('error', tokenValue); 413 return new DiagnosticDecoration('error', tokenValue);
304 } 414 }
305 return currentTheme.foreground; 415 return currentTheme.foreground;
306 } 416 }
307 417
308 diagnostic(text, tip) { 418 diagnostic(text, tip) {
309 if (text is String) { 419 if (text is String) {
310 text = new Text(text); 420 text = new Text(text);
311 } 421 }
312 return new AnchorElement() 422 return new AnchorElement()
313 ..classes.add('diagnostic') 423 ..classes.add('diagnostic')
314 ..append(text) 424 ..append(text)
315 ..append(tip); 425 ..append(tip);
316 } 426 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698