PageRenderTime 88ms CodeModel.GetById 75ms app.highlight 10ms RepoModel.GetById 1ms app.codeStats 0ms

/bundles/plugins-trunk/XML/xml/SideKickTagHighlight.java

#
Java | 154 lines | 100 code | 8 blank | 46 comment | 26 complexity | bff7b598537977b57331b71f2722c526 MD5 | raw file
  1/*
  2 * SideKickTagHighlight.java
  3 * :tabSize=8:indentSize=8:noTabs=false:
  4 * :folding=explicit:collapseFolds=1:
  5 *
  6 * Copyright (c) 2011 Eric Le Lay
  7 *
  8 * The XML plugin is licensed under the GNU General Public License, with
  9 * the following exception:
 10 *
 11 * "Permission is granted to link this code with software released under
 12 * the Apache license version 1.1, for example used by the Xerces XML
 13 * parser package."
 14 */
 15package xml;
 16
 17//{{{ Imports
 18import java.io.Reader;
 19import org.gjt.sp.jedit.GUIUtilities;
 20import org.gjt.sp.jedit.textarea.StructureMatcher;
 21import org.gjt.sp.jedit.textarea.TextArea;
 22import org.gjt.sp.jedit.textarea.JEditTextArea;
 23import org.gjt.sp.jedit.Buffer;
 24import org.gjt.sp.jedit.buffer.JEditBuffer;
 25import org.gjt.sp.util.Log;
 26import sidekick.SideKickActions;
 27import sidekick.SideKickParsedData;
 28import sidekick.IAsset;
 29import sidekick.util.ElementUtil;
 30import xml.parser.javacc.*;
 31import xml.parser.XmlTag;
 32//}}}
 33/**
 34 * StructureMatcher finding the matching tag (open/close).
 35 * It uses 
 36 *  - first the current SideKick tree to go to the open tag very fase
 37 *  - then xml.parser.javacc.TagParser, which will really parse this part of the buffer to get tag boundaries
 38 * */
 39public class SideKickTagHighlight implements StructureMatcher
 40{
 41	//{{{ getMatch() method
 42	public StructureMatcher.Match getMatch(TextArea textArea)
 43	{
 44		long startTime = System.currentTimeMillis();
 45		
 46		if(XmlPlugin.isDelegated(textArea)) {
 47			return null;
 48		}
 49
 50		int caret = textArea.getCaretPosition();
 51		SideKickParsedData parsedData = XmlParsedData.getParsedData(((JEditTextArea)textArea).getView(), false);
 52
 53		if(parsedData == null)
 54		{
 55			return null;
 56		}
 57		else
 58		{
 59			TagParser.Tag tag = null;
 60			IAsset asset = parsedData.getAssetAtOffset(caret);
 61			if(asset != null)
 62			{
 63				/* use the XML javacc parser to parse the start tag.
 64				 * If the caret is inside the start tag,
 65				 * then look for the '<' from the end of the region,
 66				 * to get easily the end tag (there is nothing to check for in the
 67				 * end tag : no quoted attributes and so on).
 68				 * On the contrary, when looking for '>' from the start of the region,
 69				 * one has to take care of '>' in attribute values, so it's better to simply
 70				 * use the javacc parser.
 71				 * */
 72				JEditBuffer b =  textArea.getBuffer();
 73				int max = b.getLength();
 74				if(Debug.DEBUG_TAG_HIGHLIGHT)System.err.println("asset is at "+asset.getStart().getOffset()+" - "+asset.getEnd().getOffset());
 75				int sA = asset.getStart().getOffset();
 76				int lA = asset.getEnd().getOffset()-sA;
 77				if(sA < 0 || sA > max){
 78					return null;
 79				}
 80				if(lA < 0 || sA+lA > max){
 81					return null;
 82				}
 83				CharSequence toParse = b.getSegment(sA,lA);
 84				int line = b.getLineOfOffset(sA);
 85				int col = b.getVirtualWidth(line, sA-b.getLineStartOffset(line))+1;
 86				if(Debug.DEBUG_TAG_HIGHLIGHT)System.err.println("line="+line+",col="+col);
 87				Reader r = new CharSequenceReader(toParse);
 88				XmlParser parser = new XmlParser(r,line+1,
 89					col);
 90				// set tab size so that ElementUtil.createStartPosition()
 91				// will compute a correct position, taking virtual columns
 92				// into account
 93				parser.setTabSize( b.getTabSize() );
 94				try{
 95					XmlDocument.XmlElement startTag = parser.Tag();
 96					// don't highlight self-closing tags : it flickers annoyingly when typing
 97					if(startTag instanceof XmlDocument.Tag && ((XmlDocument.Tag)startTag).emptyTag)return null;
 98					
 99					if(Debug.DEBUG_TAG_HIGHLIGHT)System.err.println("startL="+startTag.getStartLocation()+",endL="+startTag.getEndLocation());
100					// FIXME: switch back to ElementUtil when fixed
101					// int start = ElementUtil.createStartPosition((Buffer)textArea.getBuffer(),startTag).getOffset();
102					// int end= ElementUtil.createEndPosition((Buffer)textArea.getBuffer(),startTag).getOffset();
103					int start = xml.ElementUtil.createOffset((Buffer)textArea.getBuffer(),startTag.getStartLocation());
104					int end=  xml.ElementUtil.createOffset((Buffer)textArea.getBuffer(),startTag.getEndLocation());
105					tag = new TagParser.Tag(
106						start,
107						end);
108					if(Debug.DEBUG_TAG_HIGHLIGHT)System.err.println("start="+start+",end="+end);
109
110					int startEndTag = start;
111					for(int i=toParse.length()-2;i>0;i--){
112						if(toParse.charAt(i) == '<'){
113							startEndTag = start + i;
114							break;
115						}else if(toParse.charAt(i) == '>'){
116							return null;
117						}
118					}
119					if(caret > end && caret < startEndTag)
120					{
121						if(Debug.DEBUG_TAG_HIGHLIGHT)System.err.println("not in end ("+startEndTag+","+(start + toParse.length())+") nor start tag");
122						return null;
123					}
124					else if(caret <= end)
125					{
126						if(Debug.DEBUG_TAG_HIGHLIGHT)System.err.println("inside start tag");
127						/* if the caret is inside start tag */
128						tag.start = startEndTag;
129						tag.end = start + toParse.length();
130					}
131					tag.startLine = textArea.getLineOfOffset(tag.start);
132					tag.endLine = textArea.getLineOfOffset(tag.end);
133					tag.matcher = this;
134					
135				}catch(ParseException pe){
136					Log.log(Log.DEBUG, SideKickTagHighlight.class, "error parsing during matching tag highlight");
137				}
138			}
139			Log.log(Log.DEBUG, SideKickTagHighlight.class, "highlighting matching tag has taken "+(System.currentTimeMillis()-startTime)+"ms");
140			return tag;
141		}
142	} //}}}
143
144	//{{{ selectMatch() method
145	/**
146	 * Selects from the caret to the matching structure element (if there is
147	 * one, otherwise the behavior of this method is undefined).
148	 * @since jEdit 4.2pre3
149	 */
150	public void selectMatch(TextArea textArea)
151	{
152		SideKickActions.selectAsset(GUIUtilities.getView(textArea));
153	} //}}}
154}