1 19 20 package org.netbeans.modules.languages.html; 21 22 import java.util.ArrayList ; 23 import java.util.Collections ; 24 import java.util.Collections ; 25 import java.util.Iterator ; 26 import java.util.List ; 27 import java.util.Stack ; 28 import javax.swing.text.BadLocationException ; 29 import javax.swing.text.Document ; 30 import javax.swing.text.StyledDocument ; 31 import org.netbeans.api.languages.ASTItem; 32 import org.netbeans.api.lexer.Token; 33 import org.netbeans.api.lexer.TokenSequence; 34 import org.netbeans.api.languages.Context; 35 import org.netbeans.api.languages.SyntaxContext; 36 import org.netbeans.api.languages.ASTNode; 37 import org.netbeans.api.languages.ASTToken; 38 import org.netbeans.api.languages.LibrarySupport; 39 import org.netbeans.api.languages.support.CompletionSupport; 40 import org.openide.ErrorManager; 41 import org.openide.text.NbDocument; 42 43 44 48 public class HTML { 49 50 private static final String HTML401 = "org/netbeans/modules/languages/html/HTML401.xml"; 52 53 54 56 public static String complete (Context context) { 57 TokenSequence ts = context.getTokenSequence (); 58 ts.moveNext (); 59 Token t = ts.token (); 60 if (t == null) return null; 61 String identifier = t.text ().toString (); 62 if (!identifier.equals (">")) return null; 63 do { 64 if (!ts.movePrevious ()) return null; 65 } while (!t.id ().name ().equals ("html_element_name")); 66 String et = getLibrary ().getProperty ("TAG", identifier, "endTag"); 67 if (!ts.movePrevious ()) return null; 68 if (!ts.token ().text ().toString ().equals ("<")) return null; 69 return "</" + identifier + ">"; 70 } 71 72 73 75 public static void indent (Context context) { 76 TokenSequence ts = context.getTokenSequence (); 77 Document doc = context.getDocument (); 78 int indent; 79 Token t; 80 do { 81 ts.movePrevious (); 82 t = ts.token (); 83 } while (t.text ().toString ().trim ().length () == 0); 84 String text = t.text ().toString (); 85 String type = t.id ().name (); 86 int ln = NbDocument.findLineNumber ((StyledDocument ) doc, ts.offset ()); 87 int start = NbDocument.findLineOffset ((StyledDocument ) doc, ln); 88 if (text.equals (">") || text.equals ("/>")) { 89 do { 90 if (!ts.movePrevious ()) break; 91 t = ts.token (); 92 } while (!t.text ().toString ().equals ("<")); 93 indent = getIndent (ts, doc); 94 } else 95 if (type.equals ("html_attribute_value") || 96 type.equals ("html_attribute_name") || 97 type.equals ("html_element_name") || 98 type.equals ("html_operator") 99 ) { 100 do { 101 if (!ts.movePrevious ()) break; 102 t = ts.token (); 103 } while ( 104 !t.text ().toString ().equals ("<") && 105 ts.offset () > start 106 ); 107 if (t.text ().toString ().equals ("<")) 108 indent = getIndent (ts, doc) + 4; 109 else { 110 ts.moveNext (); 111 indent = getIndent (ts, doc); 112 } 113 } else 114 if (text.equals ("<")) { 115 indent = getIndent (ts, doc) + 4; 116 } else 117 indent = getIndent (ts, doc); 118 indent (doc, context.getJTextComponent ().getCaret ().getDot (), indent); 119 } 120 121 private static int getIndent (TokenSequence ts, Document doc) { 122 int ln = NbDocument.findLineNumber ((StyledDocument ) doc, ts.offset ()); 123 int start = NbDocument.findLineOffset ((StyledDocument ) doc, ln); 124 ts.move (start); 125 ts.moveNext (); 126 if (ts.token ().text ().toString ().trim ().length () == 0) 127 ts.moveNext (); 128 return ts.offset () - start; 129 } 130 131 private static void indent (Document doc, int offset, int i) { 132 StringBuilder sb = new StringBuilder (); 133 while (i > 0) { 134 sb.append (' ');i--; 135 } 136 try { 137 doc.insertString (offset, sb.toString (), null); 138 } catch (BadLocationException ex) { 139 ErrorManager.getDefault ().notify (ex); 140 } 141 } 142 143 161 162 164 public static List tags (Context context) { 165 if (context instanceof SyntaxContext) return Collections.EMPTY_LIST; 166 List tags = getLibrary ().getItems ("TAG"); 167 List items = new ArrayList (tags.size ()); 168 Iterator it = tags.iterator (); 169 while (it.hasNext ()) { 170 String tag = (String ) it.next (); 171 String description = getLibrary ().getProperty 172 ("TAG", tag, "description"); 173 items.add (CompletionSupport.createCompletionItem ( 174 tag, 175 "<html><b><font color=blue>" + tag.toUpperCase () + 176 ": </font></b><font color=black> " + 177 description + "</font></html>" 178 )); 179 } 180 return items; 181 } 182 183 public static List attributes (Context context) { 184 if (context instanceof SyntaxContext) return Collections.EMPTY_LIST; 185 String tagName = tagName (context.getTokenSequence ()); 186 if (tagName == null) return Collections.EMPTY_LIST; 187 List r = getLibrary ().getItems (tagName); 188 if (r == null) return Collections.EMPTY_LIST; 189 List items = new ArrayList (r.size ()); 191 Iterator it = r.iterator (); 192 while (it.hasNext ()) { 193 String tag = (String ) it.next (); 194 String description = getLibrary ().getProperty 195 (tagName, tag, "description"); 196 items.add (CompletionSupport.createCompletionItem ( 197 tag, 198 "<html><b><font color=blue>" + tag.toUpperCase () + 199 ": </font></b><font color=black> " + 200 description + "</font></html>" 201 )); 202 } 203 return items; 205 } 206 207 208 210 public static boolean isDeprecatedAttribute (Context context) { 211 TokenSequence ts = context.getTokenSequence (); 212 String attribName = ts.token ().text ().toString ().toLowerCase (); 213 String tagName = tagName (context.getTokenSequence ()); 214 if (tagName == null) return false; 215 return "true".equals (getLibrary ().getProperty (tagName, attribName, "deprecated")); 216 } 217 218 public static boolean isDeprecatedTag (Context context) { 219 Token t = context.getTokenSequence ().token (); 220 String tagName = t.text ().toString ().toLowerCase (); 221 return "true".equals (getLibrary ().getProperty ("TAG", tagName, "deprecated")); 222 } 223 224 public static boolean isEndTagRequired (Context context) { 225 Token t = context.getTokenSequence ().token (); 226 return isEndTagRequired (t.id ().name ().toLowerCase ()); 227 } 228 229 static boolean isEndTagRequired (String tagName) { 230 String v = getLibrary ().getProperty ("TAG", tagName, "endTag"); 231 return !"O".equals (v) && !"F".equals (v); 232 } 233 234 public static ASTNode process (SyntaxContext context) { 235 ASTNode n = (ASTNode) context.getASTPath ().getRoot (); 236 List l = new ArrayList (); 237 resolve (n, new Stack (), l, true); 238 return ASTNode.create (n.getMimeType (), n.getNT (), l, n.getOffset ()); 239 } 240 241 242 244 private static String tagName (TokenSequence ts) { 245 while (!ts.token ().id ().name ().equals ("html_element_name")) 246 if (!ts.movePrevious ()) break; 247 if (!ts.token ().id ().name ().equals ("html_element_name")) 248 return null; 249 return ts.token ().text ().toString ().toLowerCase (); 250 } 251 252 private static LibrarySupport library; 253 254 private static LibrarySupport getLibrary () { 255 if (library == null) 256 library = LibrarySupport.create (HTML401); 257 return library; 258 } 259 260 private static ASTNode clone (String mimeType, String nt, int offset, List children) { 261 Iterator it = children.iterator (); 262 List l = new ArrayList (); 263 while (it.hasNext ()) { 264 Object o = it.next (); 265 if (o instanceof ASTToken) 266 l.add (clone ((ASTToken) o)); 267 else 268 l.add (clone ((ASTNode) o)); 269 } 270 return ASTNode.create (mimeType, nt, l, offset); 271 } 272 273 private static ASTNode clone (ASTNode n) { 274 return clone (n.getMimeType (), n.getNT (), n.getOffset (), n.getChildren ()); 275 } 276 277 private static ASTToken clone (ASTToken token) { 278 List <ASTItem> children = new ArrayList (); 279 Iterator <ASTItem> it = token.getChildren ().iterator (); 280 while (it.hasNext ()) { 281 ASTItem item = it.next (); 282 if (item instanceof ASTNode) 283 children.add (clone ((ASTNode) item)); 284 else 285 children.add (clone ((ASTToken) item)); 286 } 287 return ASTToken.create ( 288 token.getMimeType (), 289 token.getType (), 290 token.getIdentifier (), 291 token.getOffset (), 292 token.getLength (), 293 children 294 ); 295 } 296 297 private static ASTNode clone (ASTNode n, String nt) { 298 return clone (n.getMimeType (), nt, n.getOffset (), n.getChildren ()); 299 } 300 301 private static void resolve (ASTNode n, Stack s, List l, boolean findUnpairedTags) { 302 Iterator <ASTItem> it = n.getChildren ().iterator (); 303 while (it.hasNext ()) { 304 ASTItem item = it.next (); 305 if (item instanceof ASTToken) { 306 l.add (clone ((ASTToken) item)); 307 continue; 308 } 309 ASTNode node = (ASTNode) item; 310 if (node.getNT ().equals ("startTag")) { 311 if (node.getTokenType ("html_end_element_end") != null) { 312 l.add (clone (node, "simpleTag")); 313 } else { 314 String name = node.getTokenTypeIdentifier ("html_element_name"); 315 if (name == null) 316 name = ""; 317 else 318 name = name.toLowerCase (); 319 s.add (name); 320 s.add (new Integer (l.size ())); 321 if (findUnpairedTags && isEndTagRequired (name)) 322 l.add (clone (node, "unpairedStartTag")); 323 else 324 l.add (clone (node, "startTag")); 325 } 326 continue; 327 } else 328 if (node.getNT ().equals ("endTag")) { 329 String name = node.getTokenTypeIdentifier ("html_element_name"); 330 if (name == null) 331 name = ""; 332 else 333 name = name.toLowerCase (); 334 int indexS = s.lastIndexOf (name); 335 if (indexS >= 0) { 336 int indexL = ((Integer ) s.get (indexS + 1)).intValue (); 337 List ll = l.subList (indexL, l.size ()); 338 ll.set (0, clone ((ASTNode) ll.get (0), "startTag")); 339 List ll1 = new ArrayList (ll); 340 ll1.add (node); 341 ASTNode tag = clone ( 342 node.getMimeType (), 343 "tag", 344 ((ASTNode) ll1.get (0)).getOffset (), 345 ll1 346 ); 347 ll.clear (); 348 s.subList (indexS, s.size ()).clear (); 349 l.add (tag); 350 } else 351 l.add (clone (node, "unpairedEndTag")); 352 continue; 353 } else 354 if (node.getNT ().equals ("tags")) { 355 resolve (node, s, l, findUnpairedTags); 356 continue; 357 } 358 l.add (clone (node)); 359 } 360 } 361 } 362 363 | Popular Tags |