Refactor code to prepare for line-based tokenization.

R=kasperl@google.com

Review URL: https://codereview.chromium.org//225893002

git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@34775 260f80e4-7a28-3924-810f-c04153c831b5
This commit is contained in:
ahe@google.com 2014-04-07 09:31:55 +00:00
parent 9ed4cf1cb6
commit 8db4e3ed9d
3 changed files with 78 additions and 68 deletions

View file

@ -7,7 +7,15 @@ library trydart.htmlToText;
import 'dart:math' show
max;
import 'dart:html';
import 'dart:html' show
Element,
Node,
NodeFilter,
Text,
TreeWalker;
import 'selection.dart' show
TrySelection;
/// Returns true if [node] is a block element, that is, not inline.
bool isBlockElement(Node node) {
@ -37,7 +45,7 @@ void skip(Node node, TreeWalker walker) {
/// Writes the text of [root] to [buffer]. Keeps track of [selection] and
/// returns the new anchorOffset from beginning of [buffer] or -1 if the
/// selection isn't in [root].
int htmlToText(Node root, StringBuffer buffer, Selection selection) {
int htmlToText(Node root, StringBuffer buffer, TrySelection selection) {
int selectionOffset = -1;
TreeWalker walker = new TreeWalker(root, NodeFilter.SHOW_ALL);
@ -45,7 +53,7 @@ int htmlToText(Node root, StringBuffer buffer, Selection selection) {
switch (node.nodeType) {
case Node.CDATA_SECTION_NODE:
case Node.TEXT_NODE:
if (selection.isCollapsed && selection.anchorNode == node) {
if (selection.anchorNode == node) {
selectionOffset = selection.anchorOffset + buffer.length;
}
Text text = node;

View file

@ -216,7 +216,6 @@ class InitialState extends InteractionState {
hackDiv = newDiv;
}
// TODO(ahe): This method should be cleaned up. It is too large.
void onMutation(List<MutationRecord> mutations, MutationObserver observer) {
print('onMutation');
@ -227,27 +226,14 @@ class InitialState extends InteractionState {
}
Selection selection = window.getSelection();
Node anchorNode = selection.anchorNode;
int anchorOffset = selection.isCollapsed ? selection.anchorOffset : -1;
TrySelection trySelection = new TrySelection(mainEditorPane, selection);
for (MutationRecord record in mutations) {
if (record.addedNodes.isEmpty) continue;
for (Node node in record.addedNodes) {
if (node.parent == null) continue;
StringBuffer buffer = new StringBuffer();
int selectionOffset = htmlToText(node, buffer, selection);
Text newNode = new Text('$buffer');
node.replaceWith(newNode);
if (selectionOffset != -1) {
anchorNode = newNode;
anchorOffset = selectionOffset;
}
}
normalizeMutationRecord(record, trySelection);
}
String currentText = mainEditorPane.text;
TrySelection trySelection =
new TrySelection(mainEditorPane, selection, currentText);
trySelection.updateText(currentText);
context.currentCompilationUnit.content = currentText;
@ -256,37 +242,8 @@ class InitialState extends InteractionState {
editor.isMalformedInput = false;
int offset = 0;
List<Node> nodes = <Node>[];
// + offset + charOffset + globalOffset + (charOffset + charCount)
// v v v v
// do identifier_abcdefghijklmnopqrst
for (Token token = tokenize(currentText);
token.kind != EOF_TOKEN;
token = token.next) {
int charOffset = token.charOffset;
int charCount = token.charCount;
if (charOffset < offset) continue; // Happens for scanner errors.
Decoration decoration = editor.getDecoration(token);
if (decoration == null) continue;
// Add a node for text before current token.
trySelection.addNodeFromSubstring(offset, charOffset, nodes);
// Add a node for current token.
trySelection.addNodeFromSubstring(
charOffset, charOffset + charCount, nodes, decoration);
offset = charOffset + charCount;
}
// Add a node for anything after the last (decorated) token.
trySelection.addNodeFromSubstring(offset, currentText.length, nodes);
// Ensure text always ends with a newline.
if (!currentText.endsWith('\n')) {
nodes.add(new Text('\n'));
}
tokenizeAndHighlight(currentText, offset, trySelection, nodes);
mainEditorPane
..nodes.clear()
@ -392,7 +349,7 @@ class InitialState extends InteractionState {
continue;
}
if (context.currentCompilationUnit.name == name) {
mainEditorPane.contentEditable = false;
mainEditorPane.contentEditable = 'false';
statusDiv.text = 'Modified on disk';
}
}
@ -711,3 +668,55 @@ bool computeHasModifier(KeyboardEvent event) {
event.getModifierState("SymbolLock") ||
event.getModifierState("OS");
}
void tokenizeAndHighlight(String currentText,
int offset,
TrySelection trySelection,
List<Node> nodes) {
// + offset + charOffset + globalOffset + (charOffset + charCount)
// v v v v
// do identifier_abcdefghijklmnopqrst
for (Token token = tokenize(currentText);
token.kind != EOF_TOKEN;
token = token.next) {
int charOffset = token.charOffset;
int charCount = token.charCount;
if (charOffset < offset) continue; // Happens for scanner errors.
Decoration decoration = editor.getDecoration(token);
if (decoration == null) continue;
// Add a node for text before current token.
trySelection.addNodeFromSubstring(offset, charOffset, nodes);
// Add a node for current token.
trySelection.addNodeFromSubstring(
charOffset, charOffset + charCount, nodes, decoration);
offset = charOffset + charCount;
}
// Add a node for anything after the last (decorated) token.
trySelection.addNodeFromSubstring(offset, currentText.length, nodes);
// Ensure text always ends with a newline.
if (!currentText.endsWith('\n')) {
nodes.add(new Text('\n'));
}
}
void normalizeMutationRecord(MutationRecord record, TrySelection selection) {
if (record.addedNodes.isEmpty) return;
for (Node node in record.addedNodes) {
if (node.parent == null) continue;
StringBuffer buffer = new StringBuffer();
int selectionOffset = htmlToText(node, buffer, selection);
Text newNode = new Text('$buffer');
node.replaceWith(newNode);
if (selectionOffset != -1) {
selection.anchorNode = newNode;
selection.anchorOffset = selectionOffset;
}
}
}

View file

@ -16,27 +16,15 @@ import 'decoration.dart';
class TrySelection {
final Node root;
final String text;
final int globalOffset;
Node anchorNode;
int anchorOffset;
TrySelection.internal(
this.root, this.text, this.globalOffset,
this.anchorNode, this.anchorOffset);
String text;
int globalOffset = -1;
factory TrySelection(Node root, Selection selection, String text) {
if (selection.isCollapsed) {
Node anchorNode = selection.anchorNode;
int anchorOffset = selection.anchorOffset;
return new TrySelection.internal(
root, text, computeGlobalOffset(root, anchorNode, anchorOffset),
anchorNode, anchorOffset);
} else {
return new TrySelection.internal(root, text, -1, null, -1);
}
}
TrySelection(this.root, Selection selection)
: this.anchorNode = selection.isCollapsed ? selection.anchorNode : null,
this.anchorOffset = selection.isCollapsed ? selection.anchorOffset : -1;
Text addNodeFromSubstring(int start,
int end,
@ -62,6 +50,11 @@ class TrySelection {
}
}
void updateText(String newText) {
text = newText;
globalOffset = computeGlobalOffset(root, anchorNode, anchorOffset);
}
/// Computes the global offset, that is, the offset from [root].
static int computeGlobalOffset(Node root, Node anchorNode, int anchorOffset) {
if (anchorOffset == -1) return -1;