Chromium Code Reviews| Index: dart/site/try/src/editor.dart |
| diff --git a/dart/site/try/src/editor.dart b/dart/site/try/src/editor.dart |
| index 885295de9c167a69860620832964cdb048f71f0c..47fa0df7a5dc79b9b978bc9d4c2e24fedbe97221 100644 |
| --- a/dart/site/try/src/editor.dart |
| +++ b/dart/site/try/src/editor.dart |
| @@ -6,6 +6,12 @@ library trydart.editor; |
| import 'dart:html'; |
| +import 'dart:async' show |
| + Timer; |
| + |
| +import 'dart:convert' show |
| + JSON; |
| + |
| import '../../../sdk/lib/_internal/compiler/implementation/scanner/scannerlib.dart' |
| show |
| EOF_TOKEN, |
| @@ -19,6 +25,7 @@ import 'compilation.dart' show |
| scheduleCompilation; |
| import 'ui.dart' show |
| + applyingSettings, |
| currentTheme, |
| hackDiv, |
| inputPre, |
| @@ -26,6 +33,7 @@ import 'ui.dart' show |
| outputDiv; |
| import 'decoration.dart' show |
| + CodeCompletionDecoration, |
| Decoration, |
| DiagnosticDecoration, |
| error, |
| @@ -34,7 +42,17 @@ import 'decoration.dart' show |
| const String INDENT = '\u{a0}\u{a0}'; |
| +Set<String> seenIdentifiers; |
| + |
| onKeyUp(KeyboardEvent e) { |
| + scheduleCodeCompletion(); |
| + |
| + if (e.keyCode == 40 && activeCompletion != null) { |
| + e.preventDefault(); |
| + print('${e.keyCode}: ${e}'); |
| + return; |
| + } |
| + |
| if (e.keyCode == 13) { |
| e.preventDefault(); |
| Selection selection = window.getSelection(); |
| @@ -51,16 +69,94 @@ onKeyUp(KeyboardEvent e) { |
| hackDiv = newDiv; |
| } |
| +Timer codeCompletionTimer; |
| + |
| +void scheduleCodeCompletion() { |
| + if (applyingSettings) return; |
| + if (codeCompletionTimer != null) { |
| + codeCompletionTimer.cancel(); |
| + codeCompletionTimer = null; |
| + } |
| + codeCompletionTimer = |
| + new Timer(const Duration(milliseconds: 1), displayCodeCompletion); |
| +} |
| + |
| +var activeCompletion; |
| + |
| +void displayCodeCompletion() { |
| + if (activeCompletion != null) { |
| + activeCompletion.classes.remove('active'); |
| + activeCompletion = null; |
| + } |
| + Selection selection = window.getSelection(); |
| + if (!selection.isCollapsed) return; |
| + var anchorNode = selection.anchorNode; |
| + if (!inputPre.contains(anchorNode)) return; |
| + int anchorOffset = selection.anchorOffset; |
| + int type = anchorNode.nodeType; |
| + if (type != Node.TEXT_NODE) return; |
| + Text text = anchorNode; |
| + var parent = text.parent; |
| + if (parent is! Element) return; |
| + parent.classes.add('active'); |
| + var ui = parent.query('.dart-code-completion'); |
| + if (ui == null) return; |
| + activeCompletion = parent; |
| + observer.disconnect(); |
| + ui.nodes.clear(); |
| + String prefix = text.data.substring(0, anchorOffset).trim(); |
| + if (!prefix.isEmpty) { |
| + String encodedArg0 = Uri.encodeComponent('"$prefix"'); |
| + String mindQuery = |
| + 'http://dart-mind.appspot.com/rpc' |
| + '?action=GetExportingPubCompletions' |
| + '&arg0=$encodedArg0'; |
| + HttpRequest request = new HttpRequest(); |
| + request.open('GET', mindQuery, async: false); |
| + try { |
| + List<String> response = <String>[]; |
| + var sw = new Stopwatch(); |
| + if (false) { |
| + sw.start(); |
| + request.send(); |
| + sw.stop(); |
| + if (request.status == 200) { |
| + response = JSON.decode(request.responseText); |
| + } |
| + } else { |
| + sw.start(); |
| + response = |
| + seenIdentifiers.where( |
| + (String identifier) => identifier != prefix && identifier.startsWith(prefix)) |
|
kasperl
2014/03/13 07:39:58
Long line.
|
| + .toList(growable: false) |
| + ..sort(); |
|
kasperl
2014/03/13 07:39:58
I think I'd prefer to not use .. for this. It's a
|
| + sw.stop(); |
| + } |
| + response.forEach((String completion) { |
| + ui.appendHtml('$completion<br>'); |
| + }); |
| + ui.appendHtml('${sw.elapsedMilliseconds}ms<br>'); |
| + } catch (e) { |
| + window.console.dir(e); |
| + } |
| + } |
| + observer.observe(inputPre, childList: true, characterData: true, subtree: true); |
|
kasperl
2014/03/13 07:39:58
Long line.
|
| +} |
| + |
| bool isMalformedInput = false; |
| String currentSource = ""; |
| // TODO(ahe): This method should be cleaned up. It is too large. |
| onMutation(List<MutationRecord> mutations, MutationObserver observer) { |
| - scheduleCompilation(); |
| + // scheduleCompilation(); |
| - for (Element element in inputPre.queryAll('a[class="diagnostic"]>span')) { |
| + for (Element element in inputPre.queryAll('a.diagnostic>span')) { |
| + element.remove(); |
| + } |
| + for (Element element in inputPre.queryAll('.dart-code-completion')) { |
| element.remove(); |
| } |
| + |
| // Discard clean-up mutations. |
| observer.takeRecords(); |
| @@ -181,6 +277,7 @@ onMutation(List<MutationRecord> mutations, MutationObserver observer) { |
| Token token = new StringScanner( |
| new StringSourceFile('', text), includeComments: true).tokenize(); |
| int offset = 0; |
| + seenIdentifiers = new Set<String>(); |
| for (;token.kind != EOF_TOKEN; token = token.next) { |
| Decoration decoration = getDecoration(token); |
| if (decoration == null) continue; |
| @@ -213,6 +310,14 @@ onMutation(List<MutationRecord> mutations, MutationObserver observer) { |
| window.localStorage['currentSource'] = currentSource; |
| + if (activeCompletion != null) { |
| + if (codeCompletionTimer != null) { |
| + codeCompletionTimer.cancel(); |
| + codeCompletionTimer = null; |
| + } |
| + displayCodeCompletion(); |
| + } |
| + |
| // Discard highlighting mutations. |
| observer.takeRecords(); |
| } |
| @@ -295,7 +400,12 @@ Decoration getDecoration(Token token) { |
| String tokenValue = token.value; |
| String tokenInfo = token.info.value; |
| if (tokenInfo == 'string') return currentTheme.string; |
| - // if (tokenInfo == 'identifier') return identifier; |
| + if (tokenInfo == 'identifier') { |
| + seenIdentifiers.add(tokenValue); |
| + |
| + print(seenIdentifiers); |
| + return CodeCompletionDecoration.from(currentTheme.foreground); |
| + } |
| if (tokenInfo == 'keyword') return currentTheme.keyword; |
| if (tokenInfo == 'comment') return currentTheme.singleLineComment; |
| if (tokenInfo == 'malformed input') { |