org.chromium.debug.ui/src/org/chromium/debug/ui/editors/JavascriptUtil.java
changeset 2 e4420d2515f1
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/org.chromium.debug.ui/src/org/chromium/debug/ui/editors/JavascriptUtil.java	Wed Dec 23 17:13:18 2009 -0800
@@ -0,0 +1,142 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.debug.ui.editors;
+
+import java.util.regex.Pattern;
+
+import org.chromium.debug.core.ChromiumDebugPlugin;
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.IRegion;
+import org.eclipse.jface.text.Region;
+
+/**
+ * A utility for handling JavaScript-related data.
+ */
+public class JavascriptUtil {
+
+  private static final String OPEN_BRACKET = "["; //$NON-NLS-1$
+
+  private static final String CLOSE_BRACKET = "]"; //$NON-NLS-1$
+
+  private static final String ID_CHARS_REGEX = "\\p{L}_$\\d"; //$NON-NLS-1$
+
+  private static final String QUALIFIED_ID_CHARS_REGEX = ID_CHARS_REGEX + "\\.\\[\\]"; //$NON-NLS-1$
+
+  /**
+   * Contains chars acceptable as part of expression to inspect to the right of
+   * the cursor.
+   */
+  public static final Pattern ID_PATTERN =
+      Pattern.compile(OPEN_BRACKET + ID_CHARS_REGEX + CLOSE_BRACKET);
+
+  /**
+   * Contains chars acceptable as part of expression to inspect to the left of
+   * the cursor.
+   */
+  public static final Pattern QUALIFIED_ID_PATTERN =
+      Pattern.compile(OPEN_BRACKET + QUALIFIED_ID_CHARS_REGEX + CLOSE_BRACKET);
+
+  public static boolean isJsIdentifierCharacter(char ch, boolean qualified) {
+    return qualified
+        ? QUALIFIED_ID_PATTERN.matcher(String.valueOf(ch)).find()
+        : ID_PATTERN.matcher(String.valueOf(ch)).find();
+  }
+
+  /**
+   * Returns a JavaScript qualified identifier surrounding the character at
+   * {@code offset} position in the given {@code document}.
+   *
+   * @param document to extract an identifier from
+   * @param offset of the pivot character (before, in, or after the identifier)
+   * @return JavaScript identifier, or {@code null} if none found
+   */
+  public static String extractSurroundingJsIdentifier(IDocument document, int offset) {
+    IRegion region = getSurroundingIdentifierRegion(document, offset, true);
+    try {
+      return region == null
+          ? null
+          : document.get(region.getOffset(), region.getLength());
+    } catch (BadLocationException e) {
+      ChromiumDebugPlugin.log(e);
+      return null;
+    }
+  }
+
+  /**
+   * Returns a region enclosing a JavaScript identifier found in {@code doc} at
+   * the {@code offset} position. If {@code qualified == true}, all leading
+   * qualifying names will be included into the region, otherwise the member
+   * operator (".") will be considered as an identifier terminator.
+   *
+   * @param doc the document to extract an identifier region from
+   * @param offset of the pivot character (before, in, or after the identifier)
+   * @param qualified whether to read qualified identifiers rather than simple
+   *        ones
+   * @return an IRegion corresponding to the JavaScript identifier overlapping
+   *         offset, or null if none
+   */
+  public static IRegion getSurroundingIdentifierRegion(
+      IDocument doc, int offset, boolean qualified) {
+    if (doc == null) {
+      return null;
+    }
+    try {
+      int squareBrackets = 0;
+      char ch = doc.getChar(offset);
+      if (!isJsIdentifierCharacter(ch, qualified) && offset > 0) {
+        --offset; // cursor is AFTER the identifier
+      }
+      int start = offset;
+      int end = offset;
+      int goodStart = offset;
+      while (start >= 0) {
+        ch = doc.getChar(start);
+        if (!isJsIdentifierCharacter(ch, qualified)) {
+          break;
+        }
+        if (ch == '[') {
+          squareBrackets--;
+        } else if (ch == ']') {
+          squareBrackets++;
+        }
+        if (squareBrackets < 0) {
+          break;
+        }
+        goodStart = start;
+        --start;
+      }
+      start = goodStart;
+
+      int length = doc.getLength();
+      while (end < length) {
+        try {
+          ch = doc.getChar(end);
+          if (!isJsIdentifierCharacter(ch, false)) {
+            // stop at the current name qualifier
+            // rather than scan through the entire qualified id
+            break;
+          }
+          ++end;
+        } catch (BadLocationException e) {
+          ChromiumDebugPlugin.log(e);
+        }
+      }
+      if (start >= end) {
+        return null;
+      } else {
+        return new Region(start, end - start);
+      }
+    } catch (BadLocationException e) {
+      ChromiumDebugPlugin.log(e);
+      return null;
+    }
+  }
+
+  private JavascriptUtil() {
+    // not instantiable
+  }
+
+}