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

Unified Diff: editor/tools/plugins/com.google.dart.tools.ui.web/src/com/google/dart/tools/ui/web/html/HtmlCustomPartitionScanner.java

Issue 11673007: Improve our html editor; add syntax highlighting for script tags; hyperlink detection and navigatio… (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 7 years, 12 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 side-by-side diff with in-line comments
Download patch
Index: editor/tools/plugins/com.google.dart.tools.ui.web/src/com/google/dart/tools/ui/web/html/HtmlCustomPartitionScanner.java
===================================================================
--- editor/tools/plugins/com.google.dart.tools.ui.web/src/com/google/dart/tools/ui/web/html/HtmlCustomPartitionScanner.java (revision 0)
+++ editor/tools/plugins/com.google.dart.tools.ui.web/src/com/google/dart/tools/ui/web/html/HtmlCustomPartitionScanner.java (revision 0)
@@ -0,0 +1,234 @@
+package com.google.dart.tools.ui.web.html;
+
+import com.google.dart.tools.core.html.HtmlParser;
+import com.google.dart.tools.core.html.XmlDocument;
+import com.google.dart.tools.core.html.XmlNode;
+
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.rules.IPartitionTokenScanner;
+import org.eclipse.jface.text.rules.IToken;
+import org.eclipse.jface.text.rules.Token;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+public class HtmlCustomPartitionScanner implements IPartitionTokenScanner {
+ private static class HtmlToken {
+ private IToken token;
+ private HtmlToken next;
+ private int offset;
+ private int length;
+
+ public HtmlToken() {
+
+ }
+
+ public HtmlToken(IToken token, int offset, int length) {
+ this.token = token;
+ this.offset = offset;
+ this.length = length;
+ }
+
+ @Override
+ public String toString() {
+ return "[" + token.getData() + "," + offset + "," + length + "]";
+ }
+ }
+
+ private static IToken DEFAULT_TOKEN = new Token(null);
+ private static IToken COMMENT_TOKEN = new Token(HtmlEditor.HTML_COMMENT_PARTITION);
+ private static IToken BRACKET_TOKEN = new Token(HtmlEditor.HTML_BRACKET_PARTITION);
+ private static IToken STYLE_TOKEN = new Token(HtmlEditor.HTML_STYLE_PARTITION);
+ private static IToken CODE_TOKEN = new Token(HtmlEditor.HTML_CODE_PARTITION);
+
+ private HtmlToken root;
+ private HtmlToken current;
+
+ public HtmlCustomPartitionScanner() {
+
+ }
+
+ @Override
+ public int getTokenLength() {
+ return current.length;
+ }
+
+ @Override
+ public int getTokenOffset() {
+ return current.offset;
+ }
+
+ @Override
+ public IToken nextToken() {
+ if (current == null) {
+ current = root;
+ } else {
+ current = current.next;
+ }
+
+ return current.token;
+ }
+
+ @Override
+ public void setPartialRange(IDocument document, int offset, int length, String contentType,
+ int partitionOffset) {
+ setRange(document, partitionOffset, length + offset - partitionOffset);
+ }
+
+ @Override
+ public void setRange(IDocument document, int offset, int length) {
+ current = null;
+
+ if (offset != 0 || length != document.getLength()) {
+ root = trimTokenData(parse(document.get(), offset), offset, length);
+ } else {
+ root = parse(document.get(), 0);
+ }
+
+ //print(root);
+ }
+
+ private HtmlToken convertToLinkedList(List<HtmlToken> tokens, int docLength) {
+ Collections.sort(tokens, new Comparator<HtmlToken>() {
+ @Override
+ public int compare(HtmlToken one, HtmlToken two) {
+ return one.offset - two.offset;
+ }
+ });
+
+ // set up the next pointers and add any necessary default tokens
+ HtmlToken fakeHead = new HtmlToken();
+ HtmlToken current = fakeHead;
+ int lastEmitted = 0;
+
+ for (HtmlToken token : tokens) {
+ if (lastEmitted < token.offset) {
+ current.next = new HtmlToken(DEFAULT_TOKEN, lastEmitted, token.offset - lastEmitted);
+ lastEmitted = token.offset;
+ current = current.next;
+ }
+
+ current.next = token;
+
+ current = token;
+
+ lastEmitted = token.offset + token.length;
+ }
+
+ if (lastEmitted < docLength) {
+ current.next = new HtmlToken(DEFAULT_TOKEN, lastEmitted, docLength - lastEmitted);
+ current = current.next;
+ lastEmitted = current.offset;
+ }
+
+ current.next = new HtmlToken(Token.EOF, docLength, 0);
+
+ return fakeHead.next;
+ }
+
+ private HtmlToken convertToTokens(XmlDocument document, int length) {
+ List<HtmlToken> tokens = createTokensFrom(document);
+
+ return convertToLinkedList(tokens, length);
+ }
+
+ private List<HtmlToken> createTokensFrom(XmlDocument document) {
+ List<HtmlToken> tokens = new ArrayList<HtmlToken>();
+
+ for (XmlNode node : document.getChildren()) {
+ createTokensFrom(node, tokens);
+ }
+
+ return tokens;
+ }
+
+ private void createTokensFrom(XmlNode node, List<HtmlToken> tokens) {
+ boolean recurse = true;
+
+ if (node.isComment()) {
+ tokens.add(new HtmlToken(
+ COMMENT_TOKEN,
+ node.getStartToken().getLocation(),
+ node.getEndOffset() - node.getStartOffset()));
+ } else {
+ tokens.add(new HtmlToken(BRACKET_TOKEN, node.getStartOffset(), node.getEndOffset()
+ - node.getStartOffset()));
+
+ if (node.getEndNode() != null) {
+ XmlNode endNode = node.getEndNode();
+
+ tokens.add(new HtmlToken(BRACKET_TOKEN, endNode.getStartOffset(), endNode.getEndOffset()
+ - endNode.getStartOffset()));
+
+ if ("style".equals(node.getLabel())) {
+ recurse = false;
+
+ tokens.add(new HtmlToken(STYLE_TOKEN, node.getEndOffset(), endNode.getStartOffset()
+ - node.getEndOffset()));
+ } else if ("script".equals(node.getLabel())) {
+ recurse = false;
+
+ tokens.add(new HtmlToken(CODE_TOKEN, node.getEndOffset(), endNode.getStartOffset()
+ - node.getEndOffset()));
+ }
+ }
+ }
+
+ if (recurse) {
+ for (XmlNode n : node.getChildren()) {
+ createTokensFrom(n, tokens);
+ }
+ }
+ }
+
+ private HtmlToken parse(String str, int offset) {
+ HtmlParser parser = new HtmlParser(str);
+
+ return convertToTokens(parser.parse(), str.length());
+ }
+
+ @SuppressWarnings("unused")
+ private void print(HtmlToken token) {
+ while (token != null) {
+ System.out.println(token);
+ token = token.next;
+ }
+ }
+
+ /**
+ * Adjust the linked list of tokens so that only those that encompass the given range of
+ * characters will be returned.
+ *
+ * @param offset the offset of the first character to be included in a token
+ * @param length the number of characters to be included in tokens
+ */
+ private HtmlToken trimTokenData(HtmlToken start, int offset, int length) {
+ // Skip over any tokens that should not be returned. currentToken is assumed to be the fake
+ // token created before the first real token.
+ HtmlToken nextToken = start;
+ while (nextToken != nextToken.next && nextToken.next.offset <= offset) {
+ nextToken = nextToken.next;
+ }
+ start = nextToken;
+
+ // Trim the tail of the list to cover only the requested length.
+ int totalLength = nextToken.length - (offset - nextToken.offset);
+ while (nextToken.next != null && totalLength < length) {
+ nextToken = nextToken.next;
+ totalLength += nextToken.length;
+ }
+
+ if (totalLength > length) {
+ HtmlToken lastToken = nextToken.next;
+ while (lastToken.next != null) {
+ lastToken = lastToken.next;
+ }
+ nextToken.next = lastToken;
+ }
+
+ return start;
+ }
+
+}

Powered by Google App Engine
This is Rietveld 408576698