1 11 12 package org.eclipse.ant.internal.ui.editor; 13 import org.eclipse.ant.internal.ui.editor.formatter.XmlDocumentFormatter; 14 import org.eclipse.ant.internal.ui.editor.model.AntElementNode; 15 import org.eclipse.ant.internal.ui.editor.outline.AntModel; 16 import org.eclipse.ant.internal.ui.model.AntUIPlugin; 17 import org.eclipse.jface.text.BadLocationException; 18 import org.eclipse.jface.text.DefaultAutoIndentStrategy; 19 import org.eclipse.jface.text.Document; 20 import org.eclipse.jface.text.DocumentCommand; 21 import org.eclipse.jface.text.IDocument; 22 import org.eclipse.jface.text.IRegion; 23 import org.eclipse.jface.text.TextUtilities; 24 import org.eclipse.ui.texteditor.AbstractDecoratedTextEditorPreferenceConstants; 25 26 29 public class AntAutoIndentStrategy extends DefaultAutoIndentStrategy { 30 31 private AntModel fModel; 32 private int fAccumulatedChange= 0; 33 34 public AntAutoIndentStrategy(AntModel model) { 35 fModel= model; 36 } 37 38 45 private synchronized void autoIndentAfterNewLine(IDocument d, DocumentCommand c) { 46 47 if (c.offset == -1 || d.getLength() == 0 || fModel.getProjectNode(false) == null) { 48 return; 49 } 50 51 int position= (c.offset == d.getLength() ? c.offset - 1 : c.offset); 52 AntElementNode node= fModel.getProjectNode(false).getNode(position - fAccumulatedChange); 53 if (node == null) { 54 return; 55 } 56 57 try { 58 StringBuffer correct= XmlDocumentFormatter.getLeadingWhitespace(node.getOffset(), d); 59 if (!nextNodeIsEndTag(c.offset, d)) { 60 correct.append(XmlDocumentFormatter.createIndent()); 61 } 62 StringBuffer buf= new StringBuffer (c.text); 63 buf.append(correct); 64 fAccumulatedChange+= buf.length(); 65 66 int line= d.getLineOfOffset(position); 67 IRegion reg= d.getLineInformation(line); 68 int lineEnd= reg.getOffset() + reg.getLength(); 69 int contentStart= findEndOfWhiteSpace(d, c.offset, lineEnd); 70 71 c.length= Math.max(contentStart - c.offset, 0); 72 c.caretOffset= c.offset + buf.length(); 73 c.shiftsCaret= false; 74 c.text= buf.toString(); 75 76 } catch (BadLocationException e) { 77 AntUIPlugin.log(e); 78 } 79 } 80 81 private boolean nextNodeIsEndTag(int offset, IDocument document) { 82 if (offset + 1 > document.getLength()) { 83 return false; 84 } 85 try { 86 IRegion lineRegion= document.getLineInformationOfOffset(offset); 87 offset= findEndOfWhiteSpace(document, offset, lineRegion.getOffset() + lineRegion.getLength()); 88 String nextChars= document.get(offset, 2).trim(); 89 if ("</".equals(nextChars) || "/>".equals(nextChars)) { return true; 91 } 92 } catch (BadLocationException e) { 93 } 94 return false; 95 } 96 97 100 public void customizeDocumentCommand(IDocument d, DocumentCommand c) { 101 102 if (c.length == 0 && c.text != null && isLineDelimiter(d, c.text)) { 103 autoIndentAfterNewLine(d, c); 104 } else if (c.text.length() > 1) { 105 smartPaste(d, c); 106 } 107 } 108 109 private boolean isLineDelimiter(IDocument document, String text) { 110 String [] delimiters= document.getLegalLineDelimiters(); 111 if (delimiters != null) 112 return TextUtilities.equals(delimiters, text) > -1; 113 return false; 114 } 115 116 public synchronized void reconciled() { 117 fAccumulatedChange= 0; 118 } 119 120 private void smartPaste(IDocument document, DocumentCommand command) { 121 try { 122 if (command.offset == -1 || document.getLength() == 0 || fModel.getProjectNode(false) == null) { 123 return; 124 } 125 String origChange= command.text; 126 int position= (command.offset == document.getLength() ? command.offset - 1 : command.offset); 127 AntElementNode node= fModel.getProjectNode(false).getNode(position - fAccumulatedChange); 128 if (node == null) { 129 return; 130 } 131 132 int firstLine= 1; IRegion line= document.getLineInformationOfOffset(command.offset); 135 String notSelected= document.get(line.getOffset(), command.offset - line.getOffset()); 136 if (notSelected.trim().length() == 0) { 137 command.length += notSelected.length(); 138 command.offset= line.getOffset(); 139 firstLine= 0; 140 } 141 142 Document temp= new Document(command.text); 144 145 boolean isIndentDetected= false; 150 StringBuffer addition= new StringBuffer (); 151 int insertLength= 0; 152 int lines= temp.getNumberOfLines(); 153 for (int l= firstLine; l < lines; l++) { 155 IRegion r= temp.getLineInformation(l); 156 int lineOffset= r.getOffset(); 157 int lineLength= r.getLength(); 158 159 if (lineLength == 0) { continue; 161 } 162 163 if (!isIndentDetected){ 164 165 StringBuffer current= XmlDocumentFormatter.getLeadingWhitespace(lineOffset, temp); 167 StringBuffer correct= XmlDocumentFormatter.getLeadingWhitespace(node.getOffset(), document); 168 correct.append(XmlDocumentFormatter.createIndent()); 169 170 insertLength= subtractIndent(correct, current, addition); 171 isIndentDetected= true; 172 } 173 174 if (insertLength > 0) { 176 addIndent(temp, l, addition); 177 } else if (insertLength < 0) { 178 cutIndent(temp, l, -insertLength); 179 } 180 } 181 182 if (!origChange.equals(temp.get())) { 184 fAccumulatedChange+= temp.getLength(); 185 command.text= temp.get(); 186 } 187 188 } catch (BadLocationException e) { 189 AntUIPlugin.log(e); 190 } 191 } 192 193 202 private void addIndent(Document document, int line, CharSequence indent) throws BadLocationException { 203 IRegion region= document.getLineInformation(line); 204 int insert= region.getOffset(); 205 206 document.replace(insert, 0, indent.toString()); 208 } 209 210 219 private void cutIndent(Document document, int line, int toDelete) throws BadLocationException { 220 IRegion region= document.getLineInformation(line); 221 int from= region.getOffset(); 222 int endOffset= region.getOffset() + region.getLength(); 223 224 int to= from; 225 while (toDelete > 0 && to < endOffset) { 226 char ch= document.getChar(to); 227 if (!Character.isWhitespace(ch)) 228 break; 229 toDelete -= computeVisualLength(ch); 230 if (toDelete >= 0) { 231 to++; 232 } else { 233 break; 234 } 235 } 236 237 document.replace(from, to - from, null); 238 } 239 240 247 private int computeVisualLength(char ch) { 248 if (ch == '\t') { 249 return getVisualTabLengthPreference(); 250 } 251 252 return 1; 253 } 254 255 262 private int computeVisualLength(CharSequence seq) { 263 int size= 0; 264 int tablen= getVisualTabLengthPreference(); 265 266 for (int i= 0; i < seq.length(); i++) { 267 char ch= seq.charAt(i); 268 if (ch == '\t') { 269 size += tablen - size % tablen; 270 } else { 271 size++; 272 } 273 } 274 return size; 275 } 276 277 287 private int subtractIndent(CharSequence correct, CharSequence current, StringBuffer difference) { 288 int c1= computeVisualLength(correct); 289 int c2= computeVisualLength(current); 290 int diff= c1 - c2; 291 if (diff <= 0) { 292 return diff; 293 } 294 295 difference.setLength(0); 296 int len= 0, i= 0; 297 while (len < diff) { 298 char c= correct.charAt(i++); 299 difference.append(c); 300 len += computeVisualLength(c); 301 } 302 303 return diff; 304 } 305 306 311 private int getVisualTabLengthPreference() { 312 return AntUIPlugin.getDefault().getPreferenceStore().getInt(AbstractDecoratedTextEditorPreferenceConstants.EDITOR_TAB_WIDTH); 313 } 314 } | Popular Tags |