Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
Re: [eclipse-dev] New CamelCase implementation in CharOperation

The Open Type dialog uses SearchPattern.camelCaseMatch which is the camel
case
implementation using strings instead of char[]. The SearchPattern method
doesn't
forward to the CharOperation method to avoid unnecessary char[] creation.

Dirk


                                                                           
             Luiz-Otavio                                                   
             Zorzella                                                      
             <z0200@zorzella.c                                          To 
             om>                       eclipse-dev@xxxxxxxxxxx             
             Sent by:                                                   cc 
             eclipse-dev-bounc                                             
             es@xxxxxxxxxxx                                        Subject 
                                       [eclipse-dev] New CamelCase         
                                       implementation in CharOperation     
             14/02/2006 05:39                                              
             PM                                                            
                                                                           
                                                                           
             Please respond to                                             
                 "General                                                  
                development                                                
              mailing list of                                              
                the Eclipse                                                
                 project."                                                 
             <eclipse-dev@ecli                                             
                 pse.org>                                                  
                                                                           
                                                                           




I've never submitted a patch before. Please let me know if there is a
better way (e.g. file a bug report). I thought the list would be a
better place to get some feedback.

I've re-written the camelcase match procedure on CharOperation. This is
the one used by CTRL-SPC completion (though, I think, not for "Open
Type". I don't know why there are two implementations -- I'll look into
it later).

The new method is much more straightforward (I think), and it works
correctly for a more useful definition of camel case, where lowercase
may be used between the uppercases, and not only in the end. E.g.,
before, "TZon" would match "TimeZone", but "TiZo" would not!

I've also created a unit test for the method (for which I could not find
a unit test). The MATCHES and MIS_MATCHES in the test (also pasted
below) provide concrete examples of usage for the new method.

Find a patch attached.

Feedback is welcomed, of course, and help on how to take it from here.

    String[][] MATCHES = {
             {"TZ","TimeZone"},  //$NON-NLS-1$//$NON-NLS-2$
             {"TiZ","TimeZone"},  //$NON-NLS-1$//$NON-NLS-2$
             {"TiZon","TimeZone"},  //$NON-NLS-1$//$NON-NLS-2$
             {"TZon","TimeZone"},  //$NON-NLS-1$//$NON-NLS-2$
             {"TZone","TimeZone"},  //$NON-NLS-1$//$NON-NLS-2$
             {"TimeZone","TimeZone"},  //$NON-NLS-1$//$NON-NLS-2$
             {"TimeZ","TimeZ"},  //$NON-NLS-1$//$NON-NLS-2$
             {"TZ","TimeZ"},  //$NON-NLS-1$//$NON-NLS-2$
             {"T","TimeZ"},  //$NON-NLS-1$//$NON-NLS-2$
             {"T","TimeZone"},  //$NON-NLS-1$//$NON-NLS-2$
             {"TZ","TZ"},  //$NON-NLS-1$//$NON-NLS-2$
             {"aT","aTimeZone"},  //$NON-NLS-1$//$NON-NLS-2$
             {"aTi","aTimeZone"},  //$NON-NLS-1$//$NON-NLS-2$
             {"aTiZ","aTimeZone"},  //$NON-NLS-1$//$NON-NLS-2$
             {"aTZ","aTimeZone"},  //$NON-NLS-1$//$NON-NLS-2$
             {"aT","artTimeZone"},  //$NON-NLS-1$//$NON-NLS-2$
             {"aTi","artTimeZone"},  //$NON-NLS-1$//$NON-NLS-2$
             {"aTiZ","artTimeZone"},  //$NON-NLS-1$//$NON-NLS-2$
             {"aTZ","artTimeZone"},  //$NON-NLS-1$//$NON-NLS-2$
     };

     String[][] MIS_MATCHES = {
             {"TZ","Timezone"},  //$NON-NLS-1$//$NON-NLS-2$
             {"aTZ","TimeZone"},  //$NON-NLS-1$//$NON-NLS-2$
             {"aTZ","TZ"},  //$NON-NLS-1$//$NON-NLS-2$
             {"arT","aTimeZone"},  //$NON-NLS-1$//$NON-NLS-2$
             {"arTi","aTimeZone"},  //$NON-NLS-1$//$NON-NLS-2$
             {"arTiZ","aTimeZone"},  //$NON-NLS-1$//$NON-NLS-2$
             {"arTZ","aTimeZone"},  //$NON-NLS-1$//$NON-NLS-2$
             {"aT","atimeZone"},  //$NON-NLS-1$//$NON-NLS-2$

Z
### Eclipse Workspace Patch 1.0
#P org.eclipse.jdt.core.tests.compiler
Index:
src/org/eclipse/jdt/core/tests/compiler/regression/CharOperationTest.java
===================================================================
RCS file:
/cvsroot/eclipse/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/CharOperationTest.java,v

retrieving revision 1.1
diff -u -r1.1 CharOperationTest.java
---
src/org/eclipse/jdt/core/tests/compiler/regression/CharOperationTest.java
       25 Nov 2005 17:26:24 -0000          1.1
+++
src/org/eclipse/jdt/core/tests/compiler/regression/CharOperationTest.java
       14 Feb 2006 00:12:16 -0000
@@ -11,6 +11,7 @@
 package org.eclipse.jdt.core.tests.compiler.regression;

 import org.eclipse.jdt.core.compiler.CharOperation;
+import org.eclipse.jdt.internal.compiler.parser.ScannerHelper;

 import junit.framework.Test;

@@ -77,4 +78,51 @@
 public static Class testClass() {
             return CharOperationTest.class;
 }
+
+public void testCamel() {
+    String[][] MATCHES = {
+            {"TZ","TimeZone"},  //$NON-NLS-1$//$NON-NLS-2$
+            {"TiZ","TimeZone"},  //$NON-NLS-1$//$NON-NLS-2$
+            {"TiZon","TimeZone"},  //$NON-NLS-1$//$NON-NLS-2$
+            {"TZon","TimeZone"},  //$NON-NLS-1$//$NON-NLS-2$
+            {"TZone","TimeZone"},  //$NON-NLS-1$//$NON-NLS-2$
+            {"TimeZone","TimeZone"},  //$NON-NLS-1$//$NON-NLS-2$
+            {"TimeZ","TimeZ"},  //$NON-NLS-1$//$NON-NLS-2$
+            {"TZ","TimeZ"},  //$NON-NLS-1$//$NON-NLS-2$
+            {"T","TimeZ"},  //$NON-NLS-1$//$NON-NLS-2$
+            {"T","TimeZone"},  //$NON-NLS-1$//$NON-NLS-2$
+            {"TZ","TZ"},  //$NON-NLS-1$//$NON-NLS-2$
+            {"aT","aTimeZone"},  //$NON-NLS-1$//$NON-NLS-2$
+            {"aTi","aTimeZone"},  //$NON-NLS-1$//$NON-NLS-2$
+            {"aTiZ","aTimeZone"},  //$NON-NLS-1$//$NON-NLS-2$
+            {"aTZ","aTimeZone"},  //$NON-NLS-1$//$NON-NLS-2$
+            {"aT","artTimeZone"},  //$NON-NLS-1$//$NON-NLS-2$
+            {"aTi","artTimeZone"},  //$NON-NLS-1$//$NON-NLS-2$
+            {"aTiZ","artTimeZone"},  //$NON-NLS-1$//$NON-NLS-2$
+            {"aTZ","artTimeZone"},  //$NON-NLS-1$//$NON-NLS-2$
+    };
+
+    for (int i = 0; i<MATCHES.length ; i++) {
+        String[] match = MATCHES[i];
+        assertTrue (match[0] + ":" + match[1],
CharOperation.camelCaseMatch(match[0].toCharArray(),
match[1].toCharArray())); //$NON-NLS-1$
+    }
+
+    String[][] MIS_MATCHES = {
+            {"TZ","Timezone"},  //$NON-NLS-1$//$NON-NLS-2$
+            {"aTZ","TimeZone"},  //$NON-NLS-1$//$NON-NLS-2$
+            {"aTZ","TZ"},  //$NON-NLS-1$//$NON-NLS-2$
+            {"arT","aTimeZone"},  //$NON-NLS-1$//$NON-NLS-2$
+            {"arTi","aTimeZone"},  //$NON-NLS-1$//$NON-NLS-2$
+            {"arTiZ","aTimeZone"},  //$NON-NLS-1$//$NON-NLS-2$
+            {"arTZ","aTimeZone"},  //$NON-NLS-1$//$NON-NLS-2$
+            {"aT","atimeZone"},  //$NON-NLS-1$//$NON-NLS-2$
+    };
+
+    for (int i = 0; i<MIS_MATCHES.length ; i++) {
+        String[] match = MIS_MATCHES[i];
+        assertFalse (match[0] + ":" + match[1],
CharOperation.camelCaseMatch(match[0].toCharArray(),
match[1].toCharArray())); //$NON-NLS-1$
+    }
+
+}
+
 }
#P org.eclipse.jdt.core
Index: compiler/org/eclipse/jdt/core/compiler/CharOperation.java
===================================================================
RCS file:
/cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/CharOperation.java,v

retrieving revision 1.64
diff -u -r1.64 CharOperation.java
--- compiler/org/eclipse/jdt/core/compiler/CharOperation.java            10
Feb 2006 16:14:04 -0000        1.64
+++ compiler/org/eclipse/jdt/core/compiler/CharOperation.java            14
Feb 2006 00:12:19 -0000
@@ -284,64 +284,79 @@
                         return false;
             }
             char patternChar, nameChar;
-            int iPattern = patternStart+1;
-            int iName = nameStart+1;
-            nextPatternChar: while (iPattern < patternEnd) {
-                        // check patternChar, keep camelCasing only if
uppercase
-                        if ((patternChar = pattern[iPattern]) <
ScannerHelper.MAX_OBVIOUS) {
-                                    switch
(ScannerHelper.OBVIOUS_IDENT_CHAR_NATURES[patternChar]) {
-                                                case
ScannerHelper.C_UPPER_LETTER :
-                                                            // still
uppercase
-                                                            break;
-                                                default:
-                                                            // end of
camelCase part of pattern
-                                                            break
nextPatternChar;
-                                    }
-                        } else if
(Character.isJavaIdentifierPart(patternChar)
-                                                                        &&
!Character.isUpperCase(patternChar)) {
-                                    // end of camelCase part of pattern
-                                    break nextPatternChar;
-                        }
-                        nextNameChar: while (iName < nameEnd) {
-                                    if ((nameChar = name[iName]) !=
patternChar) {
-                                                if (nameChar <
ScannerHelper.MAX_OBVIOUS) {
-                                                            switch
(ScannerHelper.OBVIOUS_IDENT_CHAR_NATURES[nameChar]) {
-
case ScannerHelper.C_LOWER_LETTER :
-
case ScannerHelper.C_IDENT_PART :
-
case ScannerHelper.C_DIGIT :
-
       // lowercase/digit char is ignored
-
       iName++;
-
       continue nextNameChar;
-                                                            }
-                                                } else if
(Character.isJavaIdentifierPart(nameChar)
-
                   && !Character.isUpperCase(nameChar)) {
-                                                            // lowercase
name char is ignored
-                                                            iName++;
-                                                            continue
nextNameChar;
-                                                }
-                                                // mismatch, either
uppercase in name or non case char ('/' etc)--> reject
-                                                return false;
-                                    } else {
-                                                // pattern char == name
char (uppercase)
-                                                iName++;
-                                                iPattern++;
-                                                continue nextPatternChar;
-                                    }
-                        }
-                        if (iPattern == patternEnd) return true;
-                        if (iName == nameEnd) return false;
-                        continue nextPatternChar;
-            }
+
+            int iPattern = patternStart;
+            int iName = nameStart;
+
+            while (true) {

-            // check trailing part in case sensitive way
-            while (iPattern < patternEnd && iName < nameEnd) {
-                        if (pattern[iPattern] != name[iName]) {
-                                    return false;
-                        }
                         iPattern++;
                         iName++;
+
+                        if (iPattern == patternEnd) {
+                                    // We have exhausted pattern, so it's
a match
+                                    return true;
+                        }
+
+                        if (iName == nameEnd){
+                                    // We have exhausted name (and not
pattern), so it's not a match
+                                    return false;
+                        }
+
+                        patternChar = pattern[iPattern];
+
+                        // For as long as we're exactly matching, bring it
on
+                        if (patternChar == name[iName])
+                                    continue;
+
+                        if (
+              (patternChar < ScannerHelper.MAX_OBVIOUS
+                                        &&
+              ScannerHelper.OBVIOUS_IDENT_CHAR_NATURES[patternChar] !=
ScannerHelper.C_UPPER_LETTER)
+                                    ||
+              (Character.isJavaIdentifierPart(patternChar)
+                &&
+              !Character.isUpperCase(patternChar))
+                        ) {
+                                    // patternChar is lowercase, and it
does not match name, so it's not a match
+                                    return false;
+                        }
+
+                        // patternChar is uppercase, so let's find the
next uppercase in name
+                        while (true) {
+                                    if (iName == nameEnd){
+            //          We have exhausted name (and not pattern), so it's
not a match
+                                                return false;
+                                    }
+
+                                    nameChar = name[iName];
+
+                                    if (
+                                      (nameChar <
ScannerHelper.MAX_OBVIOUS
+                                                                &&
+
ScannerHelper.OBVIOUS_IDENT_CHAR_NATURES[nameChar] !=
ScannerHelper.C_UPPER_LETTER)
+                                                            ||
+
(Character.isJavaIdentifierPart(nameChar)
+                                        &&
+                                      !Character.isUpperCase(nameChar))
+                                                ) {
+                                                // nameChar is lowercase

+                                                iName++;
+                                    } else {
+                                                // nameChar is
uppercase...
+                                                if (patternChar !=
nameChar)
+                                                            //.. and it
does not match patternChar, so it's not a match
+                                                            return false;
+
+                                                //.. and it matched
patternChar. Back to the big loop
+                                                break;
+                                    }
+                        }
+
+                        // At this point, either name has been exhausted,
or it is at an uppercase letter.
+                        // Since pattern is also at an
+
             }
-            return iPattern == patternEnd;
 }

 /**
_______________________________________________
eclipse-dev mailing list
eclipse-dev@xxxxxxxxxxx
To change your delivery options, retrieve your password, or unsubscribe
from this list, visit
https://dev.eclipse.org/mailman/listinfo/eclipse-dev




Back to the top