diff --git a/editor.document/src/org/netbeans/api/editor/document/LineDocumentUtils.java b/editor.document/src/org/netbeans/api/editor/document/LineDocumentUtils.java --- a/editor.document/src/org/netbeans/api/editor/document/LineDocumentUtils.java +++ b/editor.document/src/org/netbeans/api/editor/document/LineDocumentUtils.java @@ -195,6 +195,22 @@ } /** + * Get start of a previous word in backward direction. + * + * @param doc non-null document. + * @param offset >= 0 offset in document. + * @return previous word boundary offset. + */ + public static int getPreviousWordStart(@NonNull LineDocument doc, int offset) + throws BadLocationException + { + checkOffsetValid(doc, offset); + CharClassifier classifier = getValidClassifier(doc); + CharSequence docText = DocumentUtilities.getText(doc); + return TextSearchUtils.getPreviousWordStart(docText, classifier, offset); + } + + /** * Get first whitespace character in document in forward direction. * * @param doc document to operate on diff --git a/editor.document/src/org/netbeans/modules/editor/document/TextSearchUtils.java b/editor.document/src/org/netbeans/modules/editor/document/TextSearchUtils.java --- a/editor.document/src/org/netbeans/modules/editor/document/TextSearchUtils.java +++ b/editor.document/src/org/netbeans/modules/editor/document/TextSearchUtils.java @@ -238,6 +238,59 @@ } /** + * Get start of a previous word. + * + * @param text non-null text to search. + * @param classifier non-null character classifier. + * @param offset >= 0 offset in text. + * @return previous word start offset. + */ + public static int getPreviousWordStart(@NonNull CharSequence text, @NonNull CharClassifier classifier, int offset) { + int limitOffset = 0; + boolean inWhitespace = false; + boolean inIdentifier = false; + boolean inPunct = false; + for (int i = offset - 1; i >= limitOffset; i--) { + char ch = text.charAt(i); + if (ch == '\n') { + // If first char skip right below it + return (i == offset - 1) ? i : i + 1; + } + if (classifier.isWhitespace(ch)) { + if (inIdentifier) { + return i + 1; + } + inWhitespace = true; // Current impl skips WS after identifier + } else { + boolean identifierChar = classifier.isIdentifierPart(ch); + if (inWhitespace) { // non-WS char in front of WS + if (identifierChar) { + // Search for identifier start + inIdentifier = true; + continue; + } + } + if (inIdentifier) { + if (!identifierChar) { // Start of ident + return i + 1; + } + } + if (inPunct) { + if (identifierChar) { // Identifier after punct + return i + 1; + } + } + if (identifierChar) { + inIdentifier = true; + } else { + inPunct = true; + } + } + } + return limitOffset; + } + + /** * Get first whitespace character in text in forward direction. * * @param text text to operate on. diff --git a/editor.document/test/unit/src/org/netbeans/modules/editor/document/TextSearchUtilsTest.java b/editor.document/test/unit/src/org/netbeans/modules/editor/document/TextSearchUtilsTest.java new file mode 100644 --- /dev/null +++ b/editor.document/test/unit/src/org/netbeans/modules/editor/document/TextSearchUtilsTest.java @@ -0,0 +1,154 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2015 Oracle and/or its affiliates. All rights reserved. + * + * Oracle and Java are registered trademarks of Oracle and/or its affiliates. + * Other names may be trademarks of their respective owners. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + * + * Contributor(s): + * + * Portions Copyrighted 2015 Sun Microsystems, Inc. + */ +package org.netbeans.modules.editor.document; + +import org.junit.Test; +import static org.junit.Assert.*; +import org.netbeans.modules.editor.document.implspi.CharClassifier; + +/** + * + * @author Miloslav Metelka + */ +public class TextSearchUtilsTest { + + public TextSearchUtilsTest() { + } + + private static final String THREE_IDENTIFIERS_TEXT = "One Two Three"; + + /** + * Test of getWordStart method, of class TextSearchUtils. + */ + @Test + public void testGetWordStart() throws Exception { + } + + /** + * Test of getWordEnd method, of class TextSearchUtils. + */ + @Test + public void testGetWordEnd() { + } + + /** + * Test of getWord method, of class TextSearchUtils. + */ + @Test + public void testGetWord() throws Exception { + } + + /** + * Test of getNextWordStart method, of class TextSearchUtils. + */ + @Test + public void testGetNextWordStart() { + } + + /** + * Test of getPreviousWordEnd method, of class TextSearchUtils. + */ + @Test + public void testGetPreviousWordEnd() { + } + + /** + * Test of getPreviousWordBoundary method, of class TextSearchUtils. + */ + @Test + public void testGetPreviousWordStart() { + assertEquals(8, TextSearchUtils.getPreviousWordStart( + THREE_IDENTIFIERS_TEXT, TextSearchUtils.DEFAULT_CLASSIFIER, THREE_IDENTIFIERS_TEXT.length())); + assertEquals(4, TextSearchUtils.getPreviousWordStart( + THREE_IDENTIFIERS_TEXT, TextSearchUtils.DEFAULT_CLASSIFIER, 8)); + } + + /** + * Test of getNextWhitespace method, of class TextSearchUtils. + */ + @Test + public void testGetNextWhitespace() { + } + + /** + * Test of getPreviousWhitespace method, of class TextSearchUtils. + */ + @Test + public void testGetPreviousWhitespace() { + } + + /** + * Test of getNextNonWhitespace method, of class TextSearchUtils. + */ + @Test + public void testGetNextNonWhitespace() { + } + + /** + * Test of getPreviousNonWhitespace method, of class TextSearchUtils. + */ + @Test + public void testGetPreviousNonWhitespace() { + } + + /** + * Test of getNextNonNewline method, of class TextSearchUtils. + */ + @Test + public void testGetNextNonNewline() { + } + + /** + * Test of getPreviousNonNewline method, of class TextSearchUtils. + */ + @Test + public void testGetPreviousNonNewline() { + } + + /** + * Test of isLineEmpty method, of class TextSearchUtils. + */ + @Test + public void testIsLineEmpty() { + } + +} diff --git a/editor.lib/src/org/netbeans/editor/Utilities.java b/editor.lib/src/org/netbeans/editor/Utilities.java --- a/editor.lib/src/org/netbeans/editor/Utilities.java +++ b/editor.lib/src/org/netbeans/editor/Utilities.java @@ -446,7 +446,7 @@ @Deprecated public static int getPreviousWord(BaseDocument doc, int offset) throws BadLocationException { - return LineDocumentUtils.getPreviousWordEnd(doc, offset); + return LineDocumentUtils.getPreviousWordStart(doc, offset); } /** Get first white character in document in forward direction