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