org.chromium.debug.ui/src/org/chromium/debug/ui/editors/JavascriptUtil.java
changeset 2 e4420d2515f1
equal deleted inserted replaced
1:ef76fc2ac88c 2:e4420d2515f1
       
     1 // Copyright (c) 2009 The Chromium Authors. All rights reserved.
       
     2 // Use of this source code is governed by a BSD-style license that can be
       
     3 // found in the LICENSE file.
       
     4 
       
     5 package org.chromium.debug.ui.editors;
       
     6 
       
     7 import java.util.regex.Pattern;
       
     8 
       
     9 import org.chromium.debug.core.ChromiumDebugPlugin;
       
    10 import org.eclipse.jface.text.BadLocationException;
       
    11 import org.eclipse.jface.text.IDocument;
       
    12 import org.eclipse.jface.text.IRegion;
       
    13 import org.eclipse.jface.text.Region;
       
    14 
       
    15 /**
       
    16  * A utility for handling JavaScript-related data.
       
    17  */
       
    18 public class JavascriptUtil {
       
    19 
       
    20   private static final String OPEN_BRACKET = "["; //$NON-NLS-1$
       
    21 
       
    22   private static final String CLOSE_BRACKET = "]"; //$NON-NLS-1$
       
    23 
       
    24   private static final String ID_CHARS_REGEX = "\\p{L}_$\\d"; //$NON-NLS-1$
       
    25 
       
    26   private static final String QUALIFIED_ID_CHARS_REGEX = ID_CHARS_REGEX + "\\.\\[\\]"; //$NON-NLS-1$
       
    27 
       
    28   /**
       
    29    * Contains chars acceptable as part of expression to inspect to the right of
       
    30    * the cursor.
       
    31    */
       
    32   public static final Pattern ID_PATTERN =
       
    33       Pattern.compile(OPEN_BRACKET + ID_CHARS_REGEX + CLOSE_BRACKET);
       
    34 
       
    35   /**
       
    36    * Contains chars acceptable as part of expression to inspect to the left of
       
    37    * the cursor.
       
    38    */
       
    39   public static final Pattern QUALIFIED_ID_PATTERN =
       
    40       Pattern.compile(OPEN_BRACKET + QUALIFIED_ID_CHARS_REGEX + CLOSE_BRACKET);
       
    41 
       
    42   public static boolean isJsIdentifierCharacter(char ch, boolean qualified) {
       
    43     return qualified
       
    44         ? QUALIFIED_ID_PATTERN.matcher(String.valueOf(ch)).find()
       
    45         : ID_PATTERN.matcher(String.valueOf(ch)).find();
       
    46   }
       
    47 
       
    48   /**
       
    49    * Returns a JavaScript qualified identifier surrounding the character at
       
    50    * {@code offset} position in the given {@code document}.
       
    51    *
       
    52    * @param document to extract an identifier from
       
    53    * @param offset of the pivot character (before, in, or after the identifier)
       
    54    * @return JavaScript identifier, or {@code null} if none found
       
    55    */
       
    56   public static String extractSurroundingJsIdentifier(IDocument document, int offset) {
       
    57     IRegion region = getSurroundingIdentifierRegion(document, offset, true);
       
    58     try {
       
    59       return region == null
       
    60           ? null
       
    61           : document.get(region.getOffset(), region.getLength());
       
    62     } catch (BadLocationException e) {
       
    63       ChromiumDebugPlugin.log(e);
       
    64       return null;
       
    65     }
       
    66   }
       
    67 
       
    68   /**
       
    69    * Returns a region enclosing a JavaScript identifier found in {@code doc} at
       
    70    * the {@code offset} position. If {@code qualified == true}, all leading
       
    71    * qualifying names will be included into the region, otherwise the member
       
    72    * operator (".") will be considered as an identifier terminator.
       
    73    *
       
    74    * @param doc the document to extract an identifier region from
       
    75    * @param offset of the pivot character (before, in, or after the identifier)
       
    76    * @param qualified whether to read qualified identifiers rather than simple
       
    77    *        ones
       
    78    * @return an IRegion corresponding to the JavaScript identifier overlapping
       
    79    *         offset, or null if none
       
    80    */
       
    81   public static IRegion getSurroundingIdentifierRegion(
       
    82       IDocument doc, int offset, boolean qualified) {
       
    83     if (doc == null) {
       
    84       return null;
       
    85     }
       
    86     try {
       
    87       int squareBrackets = 0;
       
    88       char ch = doc.getChar(offset);
       
    89       if (!isJsIdentifierCharacter(ch, qualified) && offset > 0) {
       
    90         --offset; // cursor is AFTER the identifier
       
    91       }
       
    92       int start = offset;
       
    93       int end = offset;
       
    94       int goodStart = offset;
       
    95       while (start >= 0) {
       
    96         ch = doc.getChar(start);
       
    97         if (!isJsIdentifierCharacter(ch, qualified)) {
       
    98           break;
       
    99         }
       
   100         if (ch == '[') {
       
   101           squareBrackets--;
       
   102         } else if (ch == ']') {
       
   103           squareBrackets++;
       
   104         }
       
   105         if (squareBrackets < 0) {
       
   106           break;
       
   107         }
       
   108         goodStart = start;
       
   109         --start;
       
   110       }
       
   111       start = goodStart;
       
   112 
       
   113       int length = doc.getLength();
       
   114       while (end < length) {
       
   115         try {
       
   116           ch = doc.getChar(end);
       
   117           if (!isJsIdentifierCharacter(ch, false)) {
       
   118             // stop at the current name qualifier
       
   119             // rather than scan through the entire qualified id
       
   120             break;
       
   121           }
       
   122           ++end;
       
   123         } catch (BadLocationException e) {
       
   124           ChromiumDebugPlugin.log(e);
       
   125         }
       
   126       }
       
   127       if (start >= end) {
       
   128         return null;
       
   129       } else {
       
   130         return new Region(start, end - start);
       
   131       }
       
   132     } catch (BadLocationException e) {
       
   133       ChromiumDebugPlugin.log(e);
       
   134       return null;
       
   135     }
       
   136   }
       
   137 
       
   138   private JavascriptUtil() {
       
   139     // not instantiable
       
   140   }
       
   141 
       
   142 }