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