|
What this is
Other links
The source code/* * Sun Public License Notice * * The contents of this file are subject to the Sun Public License * Version 1.0 (the "License"). You may not use this file except in * compliance with the License. A copy of the License is available at * http://www.sun.com/ * * The Original Code is NetBeans. The Initial Developer of the Original * Code is Sun Microsystems, Inc. Portions Copyright 1997-2000 Sun * Microsystems, Inc. All Rights Reserved. */ package org.netbeans.editor.ext.java; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.HashMap; import javax.swing.text.BadLocationException; import javax.swing.event.DocumentListener; import javax.swing.event.DocumentEvent; import javax.swing.text.JTextComponent; import org.netbeans.editor.SyntaxSupport; import org.netbeans.editor.BaseDocument; import org.netbeans.editor.Utilities; import org.netbeans.editor.TextBatchProcessor; import org.netbeans.editor.FinderFactory; import org.netbeans.editor.Syntax; import org.netbeans.editor.Analyzer; import org.netbeans.editor.TokenID; import org.netbeans.editor.TokenContextPath; import org.netbeans.editor.ext.ExtSyntaxSupport; /** * Support methods for syntax analyzes * * @author Miloslav Metelka * @version 1.00 */ abstract public class JavaSyntaxSupport extends ExtSyntaxSupport { // Internal java declaration token processor states static final int INIT = 0; static final int AFTER_TYPE = 1; static final int AFTER_VARIABLE = 2; static final int AFTER_COMMA = 3; static final int AFTER_DOT = 4; static final int AFTER_TYPE_LSB = 5; static final int AFTER_MATCHING_VARIABLE_LSB = 6; static final int AFTER_MATCHING_VARIABLE = 7; static final int AFTER_EQUAL = 8; // in decl after "var =" private static final TokenID[] COMMENT_TOKENS = new TokenID[] { JavaTokenContext.LINE_COMMENT, JavaTokenContext.BLOCK_COMMENT }; private static final TokenID[] BRACKET_SKIP_TOKENS = new TokenID[] { JavaTokenContext.LINE_COMMENT, JavaTokenContext.BLOCK_COMMENT, JavaTokenContext.CHAR_LITERAL, JavaTokenContext.STRING_LITERAL }; private static final char[] COMMAND_SEPARATOR_CHARS = new char[] { ';', '{', '}' }; private JavaImport javaImport; /** Whether java 1.5 constructs are recognized. */ private boolean java15; public JavaSyntaxSupport(BaseDocument doc) { super(doc); tokenNumericIDsValid = true; } abstract protected JCFinder getFinder(); protected JavaImport createJavaImport(){ return new JavaImport(this); } protected void documentModified(DocumentEvent evt) { super.documentModified(evt); if (javaImport != null) { javaImport.documentModifiedAtPosition(evt.getOffset(), getDocument()); } } protected void setJava15(boolean java15) { this.java15 = java15; } public TokenID[] getCommentTokens() { return COMMENT_TOKENS; } public TokenID[] getBracketSkipTokens() { return BRACKET_SKIP_TOKENS; } /** Return the position of the last command separator before * the given position. */ public int getLastCommandSeparator(int pos) throws BadLocationException { TextBatchProcessor tbp = new TextBatchProcessor() { public int processTextBatch(BaseDocument doc, int startPos, int endPos, boolean lastBatch) { try { int[] blks = getCommentBlocks(endPos, startPos); FinderFactory.CharArrayBwdFinder cmdFinder = new FinderFactory.CharArrayBwdFinder(COMMAND_SEPARATOR_CHARS); int lastSeparatorOffset = findOutsideBlocks(cmdFinder, startPos, endPos, blks); if (lastSeparatorOffset<1) return lastSeparatorOffset; TokenID separatorID = getTokenID(lastSeparatorOffset); if (separatorID.getNumericID() == JavaTokenContext.RBRACE_ID) { int matchingBrkPos = findMatchingBlock(lastSeparatorOffset, true)[0]; int prev = Utilities.getFirstNonWhiteBwd(getDocument(), matchingBrkPos); if (getTokenID(prev).getNumericID() == JavaTokenContext.RBRACKET_ID) return getLastCommandSeparator(prev); } if (separatorID.getNumericID() != JavaTokenContext.LBRACE_ID && separatorID.getNumericID() != JavaTokenContext.RBRACE_ID && separatorID.getNumericID() != JavaTokenContext.SEMICOLON_ID){ lastSeparatorOffset = processTextBatch(doc, lastSeparatorOffset, 0, lastBatch); } return lastSeparatorOffset; } catch (BadLocationException e) { e.printStackTrace(); return -1; } } }; return getDocument().processText(tbp, pos, 0); } /** Get the class from name. The import sections are consulted to find * the proper package for the name. If the search in import sections fails * the method can ask the finder to search just by the given name. * @param className name to resolve. It can be either the full name * or just the name without the package. * @param searchByName if true and the resolving through the import sections fails * the finder is asked to find the class just by the given name */ public JCClass getClassFromName(String className, boolean searchByName) { refreshJavaImport(); JCClass ret = JavaCompletion.getPrimitiveClass(className); if (ret == null) { ret = getJavaImport().getClazz(className); } if (ret == null && searchByName) { if (isUnknownImport(className)) return null; List clsList = getFinder().findClasses(null, className, true); if (clsList != null && clsList.size() > 0) { if (clsList.size() > 0) { // more matching classes ret = (JCClass)clsList.get(0); // get the first one } } } return ret; } public synchronized JavaImport getJavaImport(){ if (javaImport == null) { javaImport = createJavaImport(); } javaImport.update(getDocument()); return javaImport; } protected boolean isUnknownImport(String className){ return getJavaImport().isUnknownImport(className); } /** Returns all imports that aren't in Code Completion DB yet */ protected List getUnknownImports(){ return getJavaImport().getUnknownImports(); } /** Returns true if the given class is in the import statement directly or * indirectly (package.name.*) */ public boolean isImported(JCClass cls){ return getJavaImport().isImported(cls); } public void refreshJavaImport() { if (javaImport != null) { javaImport.update(getDocument()); } } protected void refreshClassInfo() { } protected List getImportedInnerClasses(){ refreshJavaImport(); return getJavaImport().getInnerClasses(); } /** Get the class that belongs to the given position */ public JCClass getClass(int pos) { return null; } public boolean isStaticBlock(int pos) { return false; } protected DeclarationTokenProcessor createDeclarationTokenProcessor( String varName, int startPos, int endPos) { return java15 ? (DeclarationTokenProcessor)new JavaDeclarationProcessor(this, varName) : (DeclarationTokenProcessor)new JavaDeclarationTokenProcessor(this, varName); } protected VariableMapTokenProcessor createVariableMapTokenProcessor( int startPos, int endPos) { return java15 ? (VariableMapTokenProcessor)new JavaDeclarationProcessor(this, null) : (VariableMapTokenProcessor)new JavaDeclarationTokenProcessor(this, null); } /** Checks, whether caret is inside method */ private boolean insideMethod(JTextComponent textComp, int startPos){ try{ int level = 0; BaseDocument doc = (BaseDocument)textComp.getDocument(); for(int i = startPos-1; i>0; i--){ char ch = doc.getChars(i, 1)[0]; if (ch == ';') return false; if (ch == ')') level++; if (ch == '('){ if (level == 0){ return true; }else{ level--; } } } return false; } catch (BadLocationException e) { return false; } } /** Check and possibly popup, hide or refresh the completion */ public int checkCompletion(JTextComponent target, String typedText, boolean visible ) { if (!visible) { // pane not visible yet int dotPos = target.getCaret().getDot(); switch (typedText.charAt(0)) { case ' ': BaseDocument doc = (BaseDocument)target.getDocument(); if (dotPos >= 2) { // last char before inserted space int pos = Math.max(dotPos - 8, 0); try { String txtBeforeSpace = doc.getText(pos, dotPos - pos); if ( txtBeforeSpace.endsWith("import ") // NOI18N && !Character.isJavaIdentifierPart(txtBeforeSpace.charAt(0))) { return ExtSyntaxSupport.COMPLETION_POPUP; } if (txtBeforeSpace.endsWith(", ")) { // NOI18N // autoPopup completion only if caret is inside method if (insideMethod(target, dotPos)) return ExtSyntaxSupport.COMPLETION_POPUP; } } catch (BadLocationException e) { } } break; case '.': return ExtSyntaxSupport.COMPLETION_POPUP; case ',': // autoPopup completion only if caret is inside method if (insideMethod(target, dotPos)) return ExtSyntaxSupport.COMPLETION_POPUP; default: if (Character.isJavaIdentifierStart(typedText.charAt(0))) { if (dotPos >= 5) { // last char before inserted space try { String maybeNew = target.getDocument().getText(dotPos - 5, 4); if (maybeNew.equals("new ")){ // NOI18N return ExtSyntaxSupport.COMPLETION_POPUP; } } catch (BadLocationException e) { } } } } return ExtSyntaxSupport.COMPLETION_CANCEL; } else { // the pane is already visible switch (typedText.charAt(0)) { case '=': case '{': case ';': return ExtSyntaxSupport.COMPLETION_HIDE; default: return ExtSyntaxSupport.COMPLETION_POST_REFRESH; } } } public boolean isAssignable(JCType from, JCType to) { JCClass fromCls = from.getClazz(); JCClass toCls = to.getClazz(); if (fromCls.equals(JavaCompletion.NULL_CLASS)) { return to.getArrayDepth() > 0 || !JavaCompletion.isPrimitiveClass(toCls); } if (toCls.equals(JavaCompletion.OBJECT_CLASS)) { // everything is object return (from.getArrayDepth() > to.getArrayDepth()) || (from.getArrayDepth() == to.getArrayDepth() && !JavaCompletion.isPrimitiveClass(fromCls)); } if (from.getArrayDepth() != to.getArrayDepth()) { return false; } if (fromCls.equals(toCls)) { return true; // equal classes } if (fromCls.isInterface()) { return toCls.isInterface() && (JCUtilities.getAllInterfaces(getFinder(), fromCls).indexOf(toCls) >= 0); } else { // fromCls is a class TokenID fromClsKwd = JavaTokenContext.getKeyword(fromCls.getName()); if (fromClsKwd != null) { // primitive class TokenID toClsKwd = JavaTokenContext.getKeyword(toCls.getName()); return toClsKwd != null && JCUtilities.getPrimitivesAssignable(fromClsKwd.getNumericID(), toClsKwd.getNumericID()); } else { if (toCls.isInterface()) { return (JCUtilities.getAllInterfaces(getFinder(), fromCls).indexOf(toCls) >= 0); } else { // toCls is a class return (JCUtilities.getSuperclasses(getFinder(), fromCls).indexOf(toCls) >= 0); } } } } public JCType getCommonType(JCType typ1, JCType typ2) { if (typ1.equals(typ2)) { return typ1; } // The following part TokenID cls1Kwd = JavaTokenContext.getKeyword(typ1.getClazz().getName()); TokenID cls2Kwd = JavaTokenContext.getKeyword(typ2.getClazz().getName()); if (cls1Kwd == null && cls2Kwd == null) { // non-primitive classes if (isAssignable(typ1, typ2)) { return typ1; } else if (isAssignable(typ2, typ1)) { return typ2; } else { return null; } } else { // at least one primitive class if (typ1.getArrayDepth() != typ2.getArrayDepth()) { return null; } if (cls1Kwd != null && cls2Kwd != null) { return JavaCompletion.getType( JCUtilities.getPrimitivesCommonClass(cls1Kwd.getNumericID(), cls2Kwd.getNumericID()), typ1.getArrayDepth()); } else { // one primitive but other not return null; } } } /** Filter the list of the methods (usually returned from * Finder.findMethods()) or the list of the constructors * by the given parameter specification. * @param methodList list of the methods. They should have the same * name but in fact they don't have to. * @param parmTypes parameter types specification. If set to null, no filtering * is performed and the same list is returned. If a particular * @param acceptMoreParameters useful for code completion to get * even the methods with more parameters. */ public List filterMethods(List methodList, List parmTypeList, boolean acceptMoreParameters) { if (parmTypeList == null) { return methodList; } List ret = new ArrayList(); int parmTypeCnt = parmTypeList.size(); int cnt = methodList.size(); for (int i = 0; i < cnt; i++) { // Use constructor conversion to allow to use it too for the constructors JCConstructor m = (JCConstructor)methodList.get(i); JCParameter[] methodParms = m.getParameters(); if (methodParms.length == parmTypeCnt || (acceptMoreParameters && methodParms.length >= parmTypeCnt) ) { boolean accept = true; boolean bestMatch = !acceptMoreParameters; for (int j = 0; accept && j < parmTypeCnt; j++) { JCType mpt = methodParms[j].getType(); JCType t = (JCType)parmTypeList.get(j); if (t != null) { if (!t.equals(mpt)) { bestMatch = false; if (!isAssignable(t, mpt)) { accept = false; break; } } } else { // type in list is null bestMatch = false; } } if (accept) { if (bestMatch) { ret.clear(); } ret.add(m); if (bestMatch) { break; } } } } return ret; } /** * Interface that can be implemented by the values (in the key-value Map terminology) * of the variableMap provided by VariableMapTokenProcessor implementations. */ public interface JavaVariable { /** * Get type expression of the variable declaration. * |
... this post is sponsored by my books ... | |
#1 New Release! |
FP Best Seller |
Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.
A percentage of advertising revenue from
pages under the /java/jwarehouse
URI on this website is
paid back to open source projects.