|
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.modules.web.core.syntax; import java.util.*; import javax.swing.text.JTextComponent; import javax.swing.text.BadLocationException; import javax.swing.text.Caret; import javax.servlet.jsp.tagext.TagInfo; import javax.servlet.jsp.tagext.TagAttributeInfo; import org.netbeans.editor.*; import org.netbeans.editor.ext.*; import org.netbeans.editor.ext.java.JavaSyntaxSupport; import org.openide.util.NbBundle; /** * JSP completion support finder * * @author Petr Nejedly * @version 1.00 */ public class JspCompletionQuery implements CompletionQuery { protected CompletionQuery contentQuery; protected CompletionQuery scriptingQuery; public JspCompletionQuery(CompletionQuery contentQuery, CompletionQuery scriptingQuery ) { super(); this.contentQuery = contentQuery; this.scriptingQuery = scriptingQuery; } /** Perform the query on the given component. The query usually * gets the component's document, the caret position and searches back * to find the last command start. Then it inspects the text up to the caret * position and returns the result. * @param component the component to use in this query. * @param offset position in the component's document to which the query will * be performed. Usually it's a caret position. * @param support syntax-support that will be used during resolving of the query. * @return result of the query or null if there's no result. */ public CompletionQuery.Result query(JTextComponent component, int offset, SyntaxSupport support) { //System.err.println("--------------------------------Query called------------------------"); BaseDocument doc = (BaseDocument)component.getDocument(); JspSyntaxSupport sup = (JspSyntaxSupport)support.get(JspSyntaxSupport.class); try { // find last separator position //TokenItem item = sup.getTokenChain( offset, Math.min( offset+100, doc.getLength() )/*, false*/ ); SyntaxElement elem = sup.getElementChain( offset ); //System.err.println("element = " + elem ); if (elem == null) // this is a legal option, when I don't have anything to say just return null return null; //System.err.println("JspCompetionQuery - element text = '" + elem.getImage() + "'"); CompletionData jspData; switch (elem.getCompletionContext()) { // TAG COMPLETION case JspSyntaxSupport.TAG_COMPLETION_CONTEXT : return queryJspTag(component, offset, sup, (SyntaxElement.Tag)elem); // ENDTAG COMPLETION case JspSyntaxSupport.ENDTAG_COMPLETION_CONTEXT : jspData = queryJspEndTag(offset, sup, (SyntaxElement.EndTag)elem, doc); //System.out.println(jspData.toString()); return new CompletionQuery.DefaultResult(component, NbBundle.getMessage (JspCompletionQuery.class, "CTL_JSP_Completion_Title"), jspData.completionItems, offset - jspData.removeLength, jspData.removeLength); // DIRECTIVE COMPLETION case JspSyntaxSupport.DIRECTIVE_COMPLETION_CONTEXT : return queryJspDirective(component, offset, sup, (SyntaxElement.Directive)elem, doc); // CONTENT LANGUAGE case JspSyntaxSupport.CONTENTL_COMPLETION_CONTEXT : // html results CompletionQuery.Result contentLResult = null; contentLResult = (contentQuery == null) ? null : contentQuery.query(component, offset, support); // JSP tags results jspData = queryJspTagInContent(offset, sup, (SyntaxElement.ContentL)elem, doc); // JSP directive results CompletionQuery.Result jspDirec = queryJspDirectiveInContent(component, offset, sup, doc); //some presumptions assert jspData != null : "queryJspTagInContent() cannot return null!"; //NOI18N assert jspData.completionItems != null : "jsp tags completion data cannot be null!"; //NOI18N assert jspDirec != null :"queryJspDirectiveInContent() cannot return null!"; //NOI18N assert jspDirec.getData() != null : "jsp directive completion data cannot be null!"; //NOI18N if(contentLResult != null) assert contentLResult.getData() != null : "html completion data cannot be null"; //NOI18N //return null (do not popup completion) if there are no items in any of the completions if(jspData.completionItems.isEmpty() && jspDirec.getData().isEmpty() && ((contentLResult == null) || contentLResult.getData().isEmpty())) return null; CompletionQuery.Result jspRes = new CompletionQuery.DefaultResult(component, NbBundle.getMessage (JspCompletionQuery.class, "CTL_JSP_Completion_Title"), jspData.completionItems, offset - jspData.removeLength, jspData.removeLength); CompletionItem.DelegatingResult result = new CompletionItem.DelegatingResult( NbBundle.getMessage (JspCompletionQuery.class, "CTL_JSP_Completion_Title") ); result.addResult(jspDirec); result.addResult(jspRes); result.addResult(contentLResult); // PENDING merge with JSP results return result; // SCRIPTING LANGUAGE case JspSyntaxSupport.SCRIPTINGL_COMPLETION_CONTEXT : //get java CC completion query CompletionQuery.Result scriptingLResult = (scriptingQuery == null) ? null : scriptingQuery.query(component, offset, support); //add a jsp directive code completion items if the CC is invoken on a <% token //find a token which I stand on TokenItem item = sup.getItemAtOrBefore(offset); //test whether it's a scriptlet delimiter (if the CC is invoken just after the <% if (item != null && item.getTokenID() == JspTagTokenContext.SYMBOL2) { //we are after <% => get tag directive CC items CompletionQuery.Result jspDirectResult = queryJspDirectiveInContent(component, offset, sup, doc); //make a delegating completion result CompletionItem.DelegatingResult delegatingCompletionResult = new CompletionItem.DelegatingResult(NbBundle.getMessage (JspCompletionQuery.class, "CTL_JSP_Completion_Title")); //add both results delegatingCompletionResult.addResult(jspDirectResult); delegatingCompletionResult.addResult(scriptingLResult); return delegatingCompletionResult; } else { //CC is invoked somewhere in the middle of a scriptlet - use only Java CC items return scriptingLResult; } } } catch (BadLocationException e) { e.printStackTrace(); } return null; } /** Gets a list of completion items for JSP tags. * @param component editor component * @param offset position of caret * @param sup JSP syntax support * @param elem syntax element representing the current JSP tag * @return list of completion items */ protected CompletionQuery.Result queryJspTag(JTextComponent component, int offset, JspSyntaxSupport sup, SyntaxElement.Tag elem) throws BadLocationException { BaseDocument doc = (BaseDocument)component.getDocument(); // find the current item List compItems = new ArrayList(); int removeLength = 0; TokenItem item = sup.getItemAtOrBefore(offset); if (item == null) { return result (component, offset, new CompletionData(compItems, 0)); } TokenID id = item.getTokenID(); String tokenPart = item.getImage().substring(0, offset - item.getOffset()); String token = item.getImage().trim(); // SYMBOL if (id == JspTagTokenContext.SYMBOL) { if (tokenPart.equals("<")) { // NOI18N // just after the beginning of the tag removeLength = 0; addTagPrefixItems(sup, compItems, sup.getTagPrefixes("")); // NOI18N } if (tokenPart.endsWith("\"")) { // NOI18N // try an attribute value String attrName = findAttributeForValue(sup, item); if (attrName != null) { AttributeValueSupport attSup = AttributeValueSupport.getSupport(true, elem.getName(), attrName); if (attSup != null) { return attSup.getResult (component, offset, sup, elem, ""); // NOI18N } } } } // TAG if (id == JspTagTokenContext.TAG) { // inside a JSP tag name if (isBlank(tokenPart.charAt(tokenPart.length() - 1))) { // blank character - do attribute completion removeLength = 0; addAttributeItems(sup, compItems, elem, sup.getTagAttributes(elem.getName(), ""), null); // NOI18N } else { int colonIndex = tokenPart.indexOf(":"); // NOI18N if (colonIndex == -1) { removeLength = tokenPart.length(); addTagPrefixItems(sup, compItems, sup.getTagPrefixes(tokenPart)); } else { String prefix = tokenPart.substring(0, colonIndex); removeLength = tokenPart.length(); addTagPrefixItems(sup, compItems, prefix, sup.getTags(tokenPart), elem); } } } // ATTRIBUTE if (id == JspTagTokenContext.ATTRIBUTE) { // inside or after an attribute if (isBlank(tokenPart.charAt(tokenPart.length() - 1))) { // blank character - do attribute completion removeLength = 0; addAttributeItems(sup, compItems, elem, sup.getTagAttributes(elem.getName(), ""), null); // NOI18N } else { removeLength = tokenPart.length(); addAttributeItems(sup, compItems, elem, sup.getTagAttributes(elem.getName(), tokenPart), token); } } // ATTRIBUTE VALUE if (id == JspTagTokenContext.ATTR_VALUE) { // inside or after an attribute String valuePart = tokenPart; item = item.getPrevious(); while ((item != null) && (item.getTokenID() == JspTagTokenContext.ATTR_VALUE)) { valuePart = item.getImage() + valuePart; item = item.getPrevious(); } // get rid of the first quote valuePart = valuePart.substring(1); removeLength = valuePart.length (); String attrName = findAttributeForValue(sup, item); if (attrName != null) { AttributeValueSupport attSup = AttributeValueSupport.getSupport(true, elem.getName(), attrName); if (attSup != null) { return attSup.getResult (component, offset, sup, elem, valuePart); } } } return result (component, offset, new CompletionData(compItems, removeLength)); } /** Gets a list of completion items for JSP tags. * @param offset position of caret * @param sup JSP syntax support * @param elem syntax element representing the current JSP tag * @return list of completion items */ protected CompletionData queryJspEndTag(int offset, JspSyntaxSupport sup, SyntaxElement.EndTag elem, BaseDocument doc) throws BadLocationException { // find the current item List compItems = new ArrayList(); int removeLength = 0; TokenItem item = sup.getItemAtOrBefore(offset); if (item == null) { return new CompletionData(compItems, 0); } TokenID id = item.getTokenID(); String tokenPart = item.getImage().substring(0, offset - item.getOffset()); removeLength = tokenPart.length(); return new CompletionData (sup.getPossibleEndTags (offset, tokenPart), removeLength); } /** Gets a list of completion items for JSP directives. * @param component editor component * @param offset position of caret * @param sup JSP syntax support * @param elem syntax element representing the current JSP tag * @return list of completion items */ protected CompletionQuery.Result queryJspDirective(JTextComponent component, int offset, JspSyntaxSupport sup, SyntaxElement.Directive elem, BaseDocument doc) throws BadLocationException { // find the current item List compItems = new ArrayList(); int removeLength = 0; TokenItem item = sup.getItemAtOrBefore(offset); if (item == null) { return result (component, offset, new CompletionData(compItems, 0)); } TokenID id = item.getTokenID(); String tokenPart = item.getImage().substring(0, offset - item.getOffset()); String token = item.getImage().trim(); // SYMBOL if (id == JspTagTokenContext.SYMBOL) { if (tokenPart.startsWith("<")) { // NOI18N //calculate a position of the potential replacement removeLength = tokenPart.length() - 1; addDirectiveItems(sup, compItems, sup.getDirectives("")); // NOI18N } if (tokenPart.endsWith("\"")) { // NOI18N // try an attribute value String attrName = findAttributeForValue(sup, item); if (attrName != null) { AttributeValueSupport attSup = AttributeValueSupport.getSupport(false, elem.getName(), attrName); if (attSup != null) { return attSup.getResult (component, offset, sup, elem, ""); // NOI18N } } } } // DIRECTIVE if (id == JspTagTokenContext.TAG) { // inside a JSP directive name if (isBlank(tokenPart.charAt(tokenPart.length() - 1))) { TokenItem prevItem = item.getPrevious (); TokenID prevId = prevItem.getTokenID (); String prevToken = prevItem.getImage().trim(); if (prevId == JspTagTokenContext.TAG || prevId == JspTagTokenContext.ATTR_VALUE) { // blank character - do attribute completion removeLength = 0; addAttributeItems(sup, compItems, elem, sup.getDirectiveAttributes(elem.getName(), ""), null); // NOI18N } else if (prevId == JspTagTokenContext.SYMBOL && prevToken.equals("<%@")) { // NOI18N // just after the beginning of the directive removeLength = tokenPart.length() + 2; addDirectiveItems(sup, compItems, sup.getDirectives("")); // NOI18N } } else { boolean add = true; //I need to get the whitespace token length before the tag name int whitespaceLength = 0; TokenItem prevItem = item.getPrevious (); TokenID prevId = prevItem.getTokenID (); //test whether there is a space before the currently completed tagname if(prevId == JspTagTokenContext.TAG && "".equals(prevItem.getImage().trim())) //try to trim the token image - just for sure since I am not absolutely sure if the TAG_ID is only for whitespaces in this case. whitespaceLength = prevItem.getImage().length(); List list = sup.getDirectives(tokenPart); if (list.size() == 1){ Object directive = list.get(0); //is the cc invoce just after the directive? if (directive instanceof TagInfo && ((TagInfo)directive).getTagName().equals(tokenPart)) add = false; } if (add){ removeLength = whitespaceLength + tokenPart.length() + 2; addDirectiveItems(sup, compItems, list); } } } // ATTRIBUTE if (id == JspTagTokenContext.ATTRIBUTE) { // inside or after an attribute if (isBlank(tokenPart.charAt(tokenPart.length() - 1))) { // blank character - do attribute completion removeLength = 0; addAttributeItems(sup, compItems, elem, sup.getDirectiveAttributes(elem.getName(), ""), null); // NOI18N } else { removeLength = tokenPart.length(); addAttributeItems(sup, compItems, elem, sup.getDirectiveAttributes(elem.getName(), tokenPart), token); } } // ATTRIBUTE VALUE if (id == JspTagTokenContext.ATTR_VALUE) { // inside or after an attribute String valuePart = tokenPart; item = item.getPrevious(); while ((item != null) && (item.getTokenID() == JspTagTokenContext.ATTR_VALUE)) { valuePart = item.getImage() + valuePart; item = item.getPrevious(); } // get rid of the first quote valuePart = valuePart.substring(1); removeLength = valuePart.length (); String attrName = findAttributeForValue(sup, item); if (attrName != null) { AttributeValueSupport attSup = AttributeValueSupport.getSupport(false, elem.getName(), attrName); if (attSup != null) { return attSup.getResult (component, offset, sup, elem, valuePart); // NOI18N } } } return new CompletionQuery.DefaultResult(component, NbBundle.getMessage (JspCompletionQuery.class, "CTL_JSP_Completion_Title"), compItems, offset - removeLength, removeLength); } protected CompletionData queryJspTagInContent(int offset, JspSyntaxSupport sup, SyntaxElement.ContentL elem, BaseDocument doc) throws BadLocationException { // find the current item List compItems = new ArrayList(); int removeLength = 0; TokenItem item = sup.getItemAtOrBefore(offset); if (item == null) { return new CompletionData(compItems, 0); } String tokenPart = item.getImage().substring(0, offset - item.getOffset()); int ltIndex = tokenPart.lastIndexOf('<'); if (ltIndex != -1) { tokenPart = tokenPart.substring(ltIndex + 1); } while (ltIndex == -1) { item = item.getPrevious(); if (item == null) { return new CompletionData(compItems, 0); } String newImage = item.getImage(); ltIndex = newImage.lastIndexOf('<'); if (ltIndex != -1) tokenPart = newImage.substring(ltIndex + 1) + tokenPart; else { tokenPart = newImage + tokenPart; } if (tokenPart.length() > 20) { return new CompletionData(compItems, 0); } } // we found ltIndex, tokenPart is either the part of the token we are looking for // or '/' + what we are looking for if (tokenPart.startsWith("/")) { // NOI18N tokenPart = tokenPart.substring(1); compItems = sup.getPossibleEndTags (offset, tokenPart); } else { addTagPrefixItems(sup, compItems, sup.getTagPrefixes(tokenPart)); } removeLength = tokenPart.length(); return new CompletionData(compItems, removeLength); } protected CompletionQuery.Result queryJspDirectiveInContent(JTextComponent component, int offset, JspSyntaxSupport sup, BaseDocument doc) throws BadLocationException { // find the current item List compItems = new ArrayList(); int removeLength = 0; TokenItem item = sup.getItemAtOrBefore(offset); if (item == null) { //return empty completion result return result (component, offset, new CompletionData(compItems, 0)); } String tokenPart = item.getImage().substring(0, offset - item.getOffset()); //if (tokenPart.lastIndexOf('<') == -1 || !tokenPart.equals("<")) -- the condition is strange - the some should be !tokenPart.equals("<") if(!tokenPart.equals("<") && !tokenPart.equals("<%")) // NOI18N //return empty completion result return result (component, offset, new CompletionData(compItems, 0)); //the removeLenght has to be set 0 if the CC is invoked right after <, 1 for <% if("<%".equals(tokenPart)) removeLength = 1; else removeLength = 0; // NOI18N addDirectiveItems(sup, compItems, sup.getDirectives("")); // NOI18N return new CompletionQuery.DefaultResult(component, NbBundle.getMessage (JspCompletionQuery.class, "CTL_JSP_Completion_Title"), compItems, offset - removeLength, removeLength); } private boolean isBlank(char c) { return c == ' '; } /** Finds an attribute name, assuming that the item is either * SYMBOL after the attribute name or ATTR_VALUE after this attribute name. * May return null if nothing found. */ protected String findAttributeForValue(JspSyntaxSupport sup, TokenItem item) { // get before any ATTR_VALUE while ((item != null) && (item.getTokenID() == JspTagTokenContext.ATTR_VALUE)) item = item.getPrevious(); // now collect the symbols String symbols = ""; // NOI18N while ((item != null) && (item.getTokenID() == JspTagTokenContext.SYMBOL)) { symbols = item.getImage() + symbols; item = item.getPrevious(); } // two quotes at the end are not allowed if (!sup.isValueBeginning(symbols)) return null; String attributeName = ""; // NOI18N while ((item != null) && (item.getTokenID() == JspTagTokenContext.ATTRIBUTE)) { attributeName = item.getImage() + attributeName; item = item.getPrevious(); } if (attributeName.trim().length() > 0) return attributeName.trim(); return null; } /** Adds to the list of items |
... 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.