OLD | NEW |
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 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 | 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.interaction_manager; | 5 library trydart.interaction_manager; |
6 | 6 |
7 import 'dart:html'; | 7 import 'dart:html'; |
8 | 8 |
9 import 'dart:convert' show | 9 import 'dart:convert' show |
10 JSON; | 10 JSON; |
11 | 11 |
12 import 'dart:math' show | 12 import 'dart:math' show |
13 max, | 13 max, |
14 min; | 14 min; |
15 | 15 |
16 import 'dart:async' show | 16 import 'dart:async' show |
17 Future; | 17 Future; |
18 | 18 |
19 import 'package:compiler/implementation/scanner/scannerlib.dart' show | 19 import 'package:compiler/implementation/scanner/scannerlib.dart' show |
20 BeginGroupToken, | 20 BeginGroupToken, |
21 EOF_TOKEN, | 21 EOF_TOKEN, |
22 ErrorToken, | 22 ErrorToken, |
23 StringScanner, | 23 StringScanner, |
24 Token; | 24 Token, |
| 25 UnmatchedToken, |
| 26 UnterminatedToken; |
25 | 27 |
26 import 'package:compiler/implementation/source_file.dart' show | 28 import 'package:compiler/implementation/source_file.dart' show |
27 StringSourceFile; | 29 StringSourceFile; |
28 | 30 |
29 import 'compilation.dart' show | 31 import 'compilation.dart' show |
30 currentSource, | 32 currentSource, |
31 scheduleCompilation; | 33 scheduleCompilation; |
32 | 34 |
33 import 'ui.dart' show | 35 import 'ui.dart' show |
34 currentTheme, | 36 currentTheme, |
(...skipping 232 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
267 trySelection.updateText(currentText); | 269 trySelection.updateText(currentText); |
268 | 270 |
269 context.currentCompilationUnit.content = currentText; | 271 context.currentCompilationUnit.content = currentText; |
270 | 272 |
271 editor.seenIdentifiers = new Set<String>.from(mock.identifiers); | 273 editor.seenIdentifiers = new Set<String>.from(mock.identifiers); |
272 | 274 |
273 editor.isMalformedInput = false; | 275 editor.isMalformedInput = false; |
274 int offset = 0; | 276 int offset = 0; |
275 List<Node> nodes = <Node>[]; | 277 List<Node> nodes = <Node>[]; |
276 | 278 |
277 tokenizeAndHighlight(currentText, offset, trySelection, nodes); | 279 String state = ''; |
| 280 for (String line in currentText.split(new RegExp('^', multiLine: true))) { |
| 281 List<Node> lineNodes = <Node>[]; |
| 282 state = |
| 283 tokenizeAndHighlight(line, state, offset, trySelection, lineNodes); |
| 284 offset += line.length; |
| 285 nodes.add(new SpanElement() |
| 286 ..nodes.addAll(lineNodes) |
| 287 ..classes.add('lineNumber')); |
| 288 } |
278 | 289 |
279 mainEditorPane | 290 mainEditorPane |
280 ..nodes.clear() | 291 ..nodes.clear() |
281 ..nodes.addAll(nodes); | 292 ..nodes.addAll(nodes); |
282 trySelection.adjust(selection); | 293 trySelection.adjust(selection); |
283 | 294 |
284 // Discard highlighting mutations. | 295 // Discard highlighting mutations. |
285 observer.takeRecords(); | 296 observer.takeRecords(); |
286 } | 297 } |
287 | 298 |
(...skipping 405 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
693 event.getModifierState("Meta") || | 704 event.getModifierState("Meta") || |
694 event.getModifierState("NumLock") || | 705 event.getModifierState("NumLock") || |
695 event.getModifierState("ScrollLock") || | 706 event.getModifierState("ScrollLock") || |
696 event.getModifierState("Scroll") || | 707 event.getModifierState("Scroll") || |
697 event.getModifierState("Win") || | 708 event.getModifierState("Win") || |
698 event.getModifierState("Shift") || | 709 event.getModifierState("Shift") || |
699 event.getModifierState("SymbolLock") || | 710 event.getModifierState("SymbolLock") || |
700 event.getModifierState("OS"); | 711 event.getModifierState("OS"); |
701 } | 712 } |
702 | 713 |
703 void tokenizeAndHighlight(String currentText, | 714 String tokenizeAndHighlight(String line, |
704 int offset, | 715 String state, |
705 TrySelection trySelection, | 716 int start, |
706 List<Node> nodes) { | 717 TrySelection trySelection, |
| 718 List<Node> nodes) { |
| 719 String newState = ''; |
| 720 int offset = state.length; |
| 721 int adjustedStart = start - state.length; |
| 722 |
707 // + offset + charOffset + globalOffset + (charOffset + charCount) | 723 // + offset + charOffset + globalOffset + (charOffset + charCount) |
708 // v v v v | 724 // v v v v |
709 // do identifier_abcdefghijklmnopqrst | 725 // do identifier_abcdefghijklmnopqrst |
710 for (Token token = tokenize(currentText); | 726 for (Token token = tokenize('$state$line'); |
711 token.kind != EOF_TOKEN; | 727 token.kind != EOF_TOKEN; |
712 token = token.next) { | 728 token = token.next) { |
713 int charOffset = token.charOffset; | 729 int charOffset = token.charOffset; |
714 int charCount = token.charCount; | 730 int charCount = token.charCount; |
715 | 731 |
716 if (charOffset < offset) continue; // Happens for scanner errors. | 732 Token tokenToDecorate = token; |
| 733 if (token is UnterminatedToken && isUnterminatedMultiLineToken(token)) { |
| 734 newState += '${token.start}'; |
| 735 continue; // This might not be an error. |
| 736 } else { |
| 737 Token follow = token.next; |
| 738 if (token is BeginGroupToken && token.endGroup != null) { |
| 739 follow = token.endGroup.next; |
| 740 } |
| 741 if (follow is ErrorToken && follow.charOffset == token.charOffset) { |
| 742 if (follow is UnmatchedToken) { |
| 743 newState += '${follow.begin.value}'; |
| 744 } else { |
| 745 tokenToDecorate = follow; |
| 746 } |
| 747 } |
| 748 } |
717 | 749 |
718 Decoration decoration = editor.getDecoration(token); | 750 if (charOffset < offset) { |
| 751 // Happens for scanner errors, or for the [state] prefix. |
| 752 continue; |
| 753 } |
719 | 754 |
720 Token follow = token.next; | 755 Decoration decoration = editor.getDecoration(tokenToDecorate); |
721 if (token is BeginGroupToken) { | |
722 follow = token.endGroup.next; | |
723 } | |
724 if (follow is ErrorToken) { | |
725 decoration = editor.getDecoration(follow); | |
726 } | |
727 | 756 |
728 if (decoration == null) continue; | 757 if (decoration == null) continue; |
729 | 758 |
730 // Add a node for text before current token. | 759 // Add a node for text before current token. |
731 trySelection.addNodeFromSubstring(offset, charOffset, nodes); | 760 trySelection.addNodeFromSubstring( |
| 761 adjustedStart + offset, adjustedStart + charOffset, nodes); |
732 | 762 |
733 // Add a node for current token. | 763 // Add a node for current token. |
734 trySelection.addNodeFromSubstring( | 764 trySelection.addNodeFromSubstring( |
735 charOffset, charOffset + charCount, nodes, decoration); | 765 adjustedStart + charOffset, |
| 766 adjustedStart + charOffset + charCount, nodes, decoration); |
736 | 767 |
737 offset = charOffset + charCount; | 768 offset = charOffset + charCount; |
738 } | 769 } |
739 | 770 |
740 // Add a node for anything after the last (decorated) token. | 771 // Add a node for anything after the last (decorated) token. |
741 trySelection.addNodeFromSubstring(offset, currentText.length, nodes); | 772 trySelection.addNodeFromSubstring( |
| 773 adjustedStart + offset, start + line.length, nodes); |
742 | 774 |
743 // Ensure text always ends with a newline. | 775 return newState; |
744 if (!currentText.endsWith('\n')) { | 776 } |
745 nodes.add(new Text('\n')); | 777 |
746 } | 778 bool isUnterminatedMultiLineToken(UnterminatedToken token) { |
| 779 return |
| 780 token.start == '/*' || |
| 781 token.start == "'''" || |
| 782 token.start == '"""' || |
| 783 token.start == "r'''" || |
| 784 token.start == 'r"""'; |
747 } | 785 } |
748 | 786 |
749 void normalizeMutationRecord(MutationRecord record, TrySelection selection) { | 787 void normalizeMutationRecord(MutationRecord record, TrySelection selection) { |
750 if (record.addedNodes.isEmpty) return; | 788 if (record.addedNodes.isEmpty) return; |
751 for (Node node in record.addedNodes) { | 789 for (Node node in record.addedNodes) { |
752 if (node.parent == null) continue; | 790 if (node.parent == null) continue; |
753 StringBuffer buffer = new StringBuffer(); | 791 StringBuffer buffer = new StringBuffer(); |
754 int selectionOffset = htmlToText(node, buffer, selection); | 792 int selectionOffset = htmlToText(node, buffer, selection); |
755 Text newNode = new Text('$buffer'); | 793 Text newNode = new Text('$buffer'); |
756 node.replaceWith(newNode); | 794 node.replaceWith(newNode); |
757 if (selectionOffset != -1) { | 795 if (selectionOffset != -1) { |
758 selection.anchorNode = newNode; | 796 selection.anchorNode = newNode; |
759 selection.anchorOffset = selectionOffset; | 797 selection.anchorOffset = selectionOffset; |
760 } | 798 } |
761 } | 799 } |
762 } | 800 } |
OLD | NEW |