/plugins/XML/tags/release-2-0-4/xml/parser/XmlParser.java

# · Java · 229 lines · 182 code · 15 blank · 32 comment · 14 complexity · 473f59daf78c1556c661f7fa0dc2f7f6 MD5 · raw file

  1. /*
  2. * XmlParser.java
  3. * :tabSize=8:indentSize=8:noTabs=false:
  4. * :folding=explicit:collapseFolds=1:
  5. *
  6. * Copyright (C) 2000, 2003 Slava Pestov
  7. * Portions copyright (C) 2001 David Walend
  8. *
  9. * The XML plugin is licensed under the GNU General Public License, with
  10. * the following exception:
  11. *
  12. * "Permission is granted to link this code with software released under
  13. * the Apache license version 1.1, for example used by the Xerces XML
  14. * parser package."
  15. */
  16. package xml.parser;
  17. import java.util.*;
  18. import org.gjt.sp.jedit.*;
  19. import sidekick.*;
  20. import xml.completion.*;
  21. import xml.completion.ElementDecl.AttributeDecl;
  22. import xml.parser.TagParser;
  23. import xml.*;
  24. /**
  25. * This is the common base class for both HTML and XML Parsers.
  26. * It contains auto completion for closing element tags.
  27. */
  28. public abstract class XmlParser extends SideKickParser
  29. {
  30. public static final String INSTANT_COMPLETION_TRIGGERS = "/";
  31. public static final int ELEMENT_COMPLETE = '<';
  32. public static final int ENTITY_COMPLETE = '&';
  33. public static final int ATTRIB_COMPLETE = ' ';
  34. //{{{ XmlParser constructor
  35. public XmlParser(String name)
  36. {
  37. super(name);
  38. highlight = new TagHighlight();
  39. } //}}}
  40. //{{{ stop() method
  41. /**
  42. * Stops the parse request currently in progress. It is up to the
  43. * parser to implement this.
  44. * @since SideKick 0.3
  45. */
  46. public void stop()
  47. {
  48. stopped = true;
  49. } //}}}
  50. //{{{ activate() method
  51. public void activate(EditPane editPane)
  52. {
  53. if(jEdit.getBooleanProperty("xml.tag-highlight"))
  54. editPane.getTextArea().addStructureMatcher(highlight);
  55. } //}}}
  56. //{{{ deactivate() method
  57. public void deactivate(EditPane editPane)
  58. {
  59. editPane.getTextArea().removeStructureMatcher(highlight);
  60. } //}}}
  61. //{{{ supportsCompletion() method
  62. public boolean supportsCompletion()
  63. {
  64. return true;
  65. } //}}}
  66. //{{{ getInstantCompletionTriggers() method
  67. public String getInstantCompletionTriggers()
  68. {
  69. return INSTANT_COMPLETION_TRIGGERS;
  70. } //}}}
  71. //{{{ complete() method
  72. public SideKickCompletion complete(EditPane editPane, int caret)
  73. {
  74. SideKickParsedData _data = SideKickParsedData
  75. .getParsedData(editPane.getView());
  76. if(!(_data instanceof XmlParsedData))
  77. return null;
  78. if(XmlPlugin.isDelegated(editPane.getTextArea()))
  79. return null;
  80. XmlParsedData data = (XmlParsedData)_data;
  81. Buffer buffer = editPane.getBuffer();
  82. // first, we get the word before the caret
  83. List allowedCompletions = new ArrayList(20);
  84. int caretLine = buffer.getLineOfOffset(caret);
  85. String text = buffer.getText(0,caret);
  86. int lineStart = buffer.getLineStartOffset(caretLine);
  87. int mode = -1;
  88. boolean insideQuote = false;
  89. int wordStart = -1;
  90. int attribStart = -1;
  91. for(int i = caret - 1; i >= lineStart; i--)
  92. {
  93. char ch = text.charAt(i);
  94. if(ch == '<' || ch == '&')
  95. {
  96. wordStart = i;
  97. if (mode == -1)
  98. mode = (ch == '<' ? ELEMENT_COMPLETE : ENTITY_COMPLETE);
  99. break;
  100. }
  101. else if (ch == '"')
  102. {
  103. insideQuote = !insideQuote;
  104. }
  105. else if (!insideQuote && attribStart == -1 && ch == ' ') {
  106. attribStart = i+1;
  107. mode = ATTRIB_COMPLETE;
  108. }
  109. else if(ch == '/' && (i == 0 || text.charAt(i - 1) != '<'))
  110. return null;
  111. }
  112. if (insideQuote) mode=-1;
  113. String closingTag = null;
  114. String word;
  115. if(wordStart != -1 && mode != -1)
  116. {
  117. int st = wordStart + 1;
  118. word = text.substring(st, caret);
  119. int firstSpace = word.indexOf(' ');
  120. if (firstSpace > 0)
  121. word = word.substring(0, firstSpace);
  122. List completions = new ArrayList();
  123. if(mode == ELEMENT_COMPLETE)
  124. {
  125. completions = data.getAllowedElements(buffer, caret);
  126. TagParser.Tag tag = TagParser.findLastOpenTag(text,caret - 2,data);
  127. if(tag != null)
  128. closingTag = tag.tag;
  129. if("!--".startsWith(word))
  130. allowedCompletions.add(new XmlListCellRenderer.Comment());
  131. if(!data.html && "![CDATA[".startsWith(word))
  132. allowedCompletions.add(new XmlListCellRenderer.CDATA());
  133. if(closingTag != null && ("/" + closingTag).startsWith(word))
  134. {
  135. if(word.length() == 0 || !jEdit.getBooleanProperty("xml.close-complete"))
  136. allowedCompletions.add(new XmlListCellRenderer.ClosingTag(closingTag));
  137. else
  138. {
  139. // just insert immediately
  140. XmlActions.completeClosingTag(
  141. editPane.getView(),
  142. false);
  143. return null;
  144. }
  145. }
  146. for(int i = 0; i < completions.size(); i++)
  147. {
  148. Object obj = completions.get(i);
  149. ElementDecl element = (ElementDecl)obj;
  150. if(element.name.startsWith(word)
  151. || (data.html && element.name.toLowerCase()
  152. .startsWith(word.toLowerCase())))
  153. {
  154. allowedCompletions.add(element);
  155. }
  156. }
  157. }
  158. else if (mode == ENTITY_COMPLETE)
  159. {
  160. completions = data.getNoNamespaceCompletionInfo().entities;
  161. for(int i = 0; i < completions.size(); i++)
  162. {
  163. Object obj = completions.get(i);
  164. EntityDecl entity = (EntityDecl)obj;
  165. if(entity.name.startsWith(word))
  166. allowedCompletions.add(entity);
  167. }
  168. }
  169. else if (mode == ATTRIB_COMPLETE)
  170. {
  171. int lastSpace = text.lastIndexOf(' ', caret);
  172. String prefix = text.substring(lastSpace+1, caret);
  173. ElementDecl decl = data.getElementDecl(word);
  174. if (decl != null) completions = decl.attributes;
  175. for (int i=0; i<completions.size(); ++i)
  176. {
  177. AttributeDecl attrDecl = (AttributeDecl)completions.get(i);
  178. if (attrDecl.name.startsWith(prefix))
  179. allowedCompletions.add(attrDecl);
  180. }
  181. word = prefix;
  182. }
  183. /* else if(mode == ID_COMPLETE)
  184. {
  185. else if(obj instanceof IDDecl)
  186. {
  187. IDDecl id = (IDDecl)obj;
  188. if(id.id.startsWith(word))
  189. allowedCompletions.add(id);
  190. }
  191. } */
  192. }
  193. else
  194. word = "";
  195. if(word.endsWith("/") && allowedCompletions.size() == 0)
  196. return null;
  197. else
  198. return new XmlCompletion(editPane.getView(),allowedCompletions,word,data,closingTag);
  199. } //}}}
  200. //{{{ Package-private members
  201. boolean stopped;
  202. //}}}
  203. //{{{ Private members
  204. private TagHighlight highlight;
  205. //}}}
  206. }