1 19 20 package org.netbeans.modules.languages.features; 21 22 import java.util.ArrayList ; 23 import java.util.HashMap ; 24 import java.util.HashSet ; 25 import java.util.Iterator ; 26 import java.util.List ; 27 import java.util.List ; 28 import java.util.Map ; 29 import java.util.Set ; 30 import java.util.WeakHashMap ; 31 import java.util.regex.Pattern ; 32 import javax.swing.text.BadLocationException ; 33 import javax.swing.text.Caret ; 34 import javax.swing.text.Document ; 35 import javax.swing.text.JTextComponent ; 36 import javax.swing.text.StyledDocument ; 37 import org.netbeans.api.languages.Context; 38 import org.netbeans.api.languages.LanguagesManager; 39 import org.netbeans.api.lexer.Token; 40 import org.netbeans.api.lexer.TokenHierarchy; 41 import org.netbeans.api.lexer.TokenSequence; 42 import org.netbeans.editor.BaseDocument; 43 import org.netbeans.editor.BaseKit.InsertBreakAction; 44 import org.netbeans.modules.languages.Feature; 45 import org.netbeans.modules.languages.Feature.Type; 46 import org.netbeans.modules.languages.Language; 47 import org.netbeans.modules.languages.LanguagesManagerImpl; 48 import org.openide.ErrorManager; 49 import org.openide.text.NbDocument; 50 51 52 56 public class IndentAction extends InsertBreakAction { 57 58 protected void afterBreak ( 59 JTextComponent target, 60 BaseDocument doc, 61 Caret caret, 62 Object cookie 63 ) { 64 try { 65 TokenHierarchy th = TokenHierarchy.get (doc); 66 TokenSequence ts = th.tokenSequence (); 67 ts.move (caret.getDot ()); 68 if (ts.moveNext ()) 69 while (ts.embedded () != null) { 70 ts = ts.embedded (); 71 ts.move (caret.getDot ()); 72 if (!ts.moveNext ()) break; 73 } 74 Language l = ((LanguagesManagerImpl) LanguagesManager.getDefault ()).getLanguage (ts.language ().mimeType ()); 75 Token token = ts.token (); 76 Object indentValue = getIndentProperties (l); 77 78 if (indentValue == null) return; 79 if (indentValue instanceof Object []) { 80 Object [] params = (Object []) indentValue; 81 int ln = NbDocument.findLineNumber ((StyledDocument ) doc, caret.getDot () - 1); 82 int start = NbDocument.findLineOffset ((StyledDocument ) doc, ln); 83 int end = NbDocument.findLineOffset ((StyledDocument ) doc, ln + 1); 84 String line = doc.getText (start, end - start); 85 int indent = getIndent (line); 86 ts.move (start); 87 ts.moveNext (); 88 int ni = getIndent (line, ts, end, params); 89 if (ni > 0) 90 indent += 4; 91 else 92 if (ni == 0 && ln > 0) { 93 int start1 = NbDocument.findLineOffset ((StyledDocument ) doc, ln - 1); 94 line = doc.getText (start1, start - start1); 95 ts.move (start1); 96 ts.moveNext (); 97 ni = getIndent (line, ts, start, params); 98 if (ni == 2) 99 indent -= 4; 100 } 101 try { 102 start = NbDocument.findLineOffset ((StyledDocument ) doc, ln + 1); 103 end = NbDocument.findLineOffset ((StyledDocument ) doc, ln + 2); 104 line = doc.getText (start, end - start); 105 } catch (IndexOutOfBoundsException ex) { 106 line = null; 107 } 108 indent (doc, caret.getDot (), indent); 109 if ( line != null && 110 ((Set ) params [2]).contains (line.trim ()) 111 ) { 112 indent -= 4; 113 int offset = caret.getDot (); 114 doc.insertString (offset, "\n", null); 115 indent (doc, caret.getDot (), indent); 116 caret.setDot (offset); 117 } 118 } else 119 if (indentValue instanceof Feature) { 120 Feature m = (Feature) indentValue; 121 m.getValue (Context.create (doc, ts)); 122 } 123 } catch (Exception ex) { 124 ErrorManager.getDefault ().notify (ex); 125 } 126 } 127 128 private static int getIndent (String line) { 129 int i = 0, k = line.length () - 1; 130 while (i < k && Character.isWhitespace (line.charAt (i))) 131 i++; 132 return i; 133 } 134 135 private static int getIndent ( 136 String line, 137 TokenSequence ts, 138 int end, 139 Object [] params 140 ) { 141 Map p = new HashMap (); 142 do { 143 Token t = ts.token (); 144 String id = t.text ().toString (); 145 if (((Set ) params [1]).contains (id)) { 146 Integer i = (Integer ) p.get (id); 147 if (i == null) { 148 i = Integer.valueOf (1); 149 } else 150 i = Integer.valueOf (i.intValue () + 1); 151 p.put (id, i); 152 } 153 if (((Set ) params [2]).contains (t.text ().toString ())) { 154 id = (String ) ((Map ) params [3]).get (id); 155 Integer i = (Integer ) p.get (id); 156 if (i == null) { 157 i = Integer.valueOf (-1); 158 } else 159 i = Integer.valueOf (i.intValue () - 1); 160 p.put (id, i); 161 } 162 if (!ts.moveNext ()) break; 163 } while (ts.offset () < end); 164 Iterator it = p.values ().iterator (); 165 while (it.hasNext ()) { 166 int i = ((Integer ) it.next ()).intValue (); 167 if (i > 0) return 1; 168 if (i < 0) return -1; 169 } 170 it = ((List ) params [0]).iterator (); 171 while (it.hasNext ()) { 172 Pattern pattern = (Pattern ) it.next (); 173 if (pattern.matcher (line).matches ()) 174 return 2; 175 } 176 return 0; 177 } 178 179 private static void indent (Document doc, int offset, int i) { 180 StringBuilder sb = new StringBuilder (); 181 while (i > 0) { 182 sb.append (' ');i--; 183 } 184 try { 185 doc.insertString (offset, sb.toString (), null); 186 } catch (BadLocationException ex) { 187 ErrorManager.getDefault ().notify (ex); 188 } 189 } 190 191 private static Map indentProperties = new WeakHashMap (); 192 193 private static Object getIndentProperties (Language l) { 194 if (!indentProperties.containsKey (l)) { 195 List <Pattern > patterns = new ArrayList <Pattern > (); 196 Set <String > start = new HashSet <String > (); 197 Set <String > end = new HashSet <String > (); 198 Map <String ,String > endToStart = new HashMap <String ,String > (); 199 200 List <Feature> indents = l.getFeatures ("INDENT"); 201 Iterator <Feature> it = indents.iterator (); 202 while (it.hasNext ()) { 203 Feature indent = it.next (); 204 if (indent.getType () == Type.METHOD_CALL) { 205 return indent; 206 } 207 String s = (String ) indent.getValue (); 208 int i = s.indexOf (':'); 209 if (i < 1) { 210 patterns.add (Pattern.compile (c (s))); 211 continue; 212 } 213 start.add (s.substring (0, i)); 214 end.add (s.substring (i + 1)); 215 endToStart.put (s.substring (i + 1), s.substring (0, i)); 216 } 217 indentProperties.put ( 218 l, 219 new Object [] {patterns, start, end, endToStart} 220 ); 221 } 222 return indentProperties.get (l); 223 } 224 225 private static String c (String s) { 226 s = s.replace ("\\n", "\n"); 227 s = s.replace ("\\r", "\r"); 228 s = s.replace ("\\t", "\t"); 229 s = s.replace ("\\\"", "\""); 230 s = s.replace ("\\\'", "\'"); 231 s = s.replace ("\\\\", "\\"); 232 return s; 233 } 234 } 235 | Popular Tags |