1 11 package org.eclipse.ui.internal.console; 12 13 import java.io.IOException ; 14 import java.util.ArrayList ; 15 import java.util.Iterator ; 16 import java.util.List ; 17 18 import org.eclipse.core.runtime.IProgressMonitor; 19 import org.eclipse.core.runtime.IStatus; 20 import org.eclipse.core.runtime.OperationCanceledException; 21 import org.eclipse.core.runtime.Status; 22 import org.eclipse.core.runtime.jobs.IJobManager; 23 import org.eclipse.core.runtime.jobs.Job; 24 import org.eclipse.jface.text.BadLocationException; 25 import org.eclipse.jface.text.DocumentEvent; 26 import org.eclipse.jface.text.IDocument; 27 import org.eclipse.jface.text.IDocumentPartitionerExtension; 28 import org.eclipse.jface.text.IRegion; 29 import org.eclipse.jface.text.ITypedRegion; 30 import org.eclipse.jface.text.Region; 31 import org.eclipse.swt.custom.StyleRange; 32 import org.eclipse.ui.console.ConsolePlugin; 33 import org.eclipse.ui.console.IConsoleDocumentPartitioner; 34 import org.eclipse.ui.console.IOConsole; 35 import org.eclipse.ui.console.IOConsoleInputStream; 36 import org.eclipse.ui.console.IOConsoleOutputStream; 37 import org.eclipse.ui.progress.UIJob; 38 import org.eclipse.ui.progress.WorkbenchJob; 39 40 45 public class IOConsolePartitioner implements IConsoleDocumentPartitioner, IDocumentPartitionerExtension { 46 private PendingPartition consoleClosedPartition; 47 private IDocument document; 48 private ArrayList partitions; 49 52 private ArrayList pendingPartitions; 53 56 private ArrayList updatePartitions; 57 60 private IOConsolePartition lastPartition; 61 64 private QueueProcessingJob queueJob; 65 68 private IOConsoleInputStream inputStream; 69 72 private boolean updateInProgress; 73 77 private ArrayList inputPartitions; 78 81 private int firstOffset; 82 85 private String [] lld; 86 private int highWaterMark = -1; 87 private int lowWaterMark = -1; 88 private boolean connected = false; 89 90 private IOConsole console; 91 92 private TrimJob trimJob = new TrimJob(); 93 98 private Object overflowLock = new Object (); 99 100 101 private int fBuffer; 102 103 public IOConsolePartitioner(IOConsoleInputStream inputStream, IOConsole console) { 104 this.inputStream = inputStream; 105 this.console = console; 106 trimJob.setRule(console.getSchedulingRule()); 107 } 108 109 public IDocument getDocument() { 110 return document; 111 } 112 113 117 public void connect(IDocument doc) { 118 document = doc; 119 document.setDocumentPartitioner(this); 120 lld = document.getLegalLineDelimiters(); 121 partitions = new ArrayList (); 122 pendingPartitions = new ArrayList (); 123 inputPartitions = new ArrayList (); 124 queueJob = new QueueProcessingJob(); 125 queueJob.setSystem(true); 126 queueJob.setPriority(Job.INTERACTIVE); 127 queueJob.setRule(console.getSchedulingRule()); 128 connected = true; 129 } 130 131 public int getHighWaterMark() { 132 return highWaterMark; 133 } 134 135 public int getLowWaterMark() { 136 return lowWaterMark; 137 } 138 139 public void setWaterMarks(int low, int high) { 140 lowWaterMark = low; 141 highWaterMark = high; 142 ConsolePlugin.getStandardDisplay().asyncExec(new Runnable () { 143 public void run() { 144 checkBufferSize(); 145 } 146 }); 147 } 148 149 152 public void streamsClosed() { 153 consoleClosedPartition = new PendingPartition(null, null); 154 synchronized (pendingPartitions) { 155 pendingPartitions.add(consoleClosedPartition); 156 } 157 queueJob.schedule(); } 159 160 164 public void disconnect() { 165 synchronized (overflowLock) { 166 document = null; 167 partitions.clear(); 168 connected = false; 169 try { 170 inputStream.close(); 171 } catch (IOException e) { 172 } 173 } 174 } 175 176 180 public void documentAboutToBeChanged(DocumentEvent event) { 181 } 182 183 187 public boolean documentChanged(DocumentEvent event) { 188 return documentChanged2(event) != null; 189 } 190 191 195 public String [] getLegalContentTypes() { 196 return new String [] { IOConsolePartition.OUTPUT_PARTITION_TYPE, IOConsolePartition.INPUT_PARTITION_TYPE }; 197 } 198 199 203 public String getContentType(int offset) { 204 return getPartition(offset).getType(); 205 } 206 207 211 public ITypedRegion[] computePartitioning(int offset, int length) { 212 int rangeEnd = offset + length; 213 int left= 0; 214 int right= partitions.size() - 1; 215 int mid= 0; 216 IOConsolePartition position= null; 217 218 if (left == right) { 219 return new IOConsolePartition[]{(IOConsolePartition) partitions.get(0)}; 220 } 221 while (left < right) { 222 223 mid= (left + right) / 2; 224 225 position= (IOConsolePartition) partitions.get(mid); 226 if (rangeEnd < position.getOffset()) { 227 if (left == mid) 228 right= left; 229 else 230 right= mid -1; 231 } else if (offset > (position.getOffset() + position.getLength() - 1)) { 232 if (right == mid) 233 left= right; 234 else 235 left= mid +1; 236 } else { 237 left= right= mid; 238 } 239 } 240 241 242 List list = new ArrayList (); 243 int index = left - 1; 244 if (index >= 0) { 245 position= (IOConsolePartition) partitions.get(index); 246 while (index >= 0 && (position.getOffset() + position.getLength()) > offset) { 247 index--; 248 if (index >= 0) { 249 position= (IOConsolePartition) partitions.get(index); 250 } 251 } 252 } 253 index++; 254 position= (IOConsolePartition) partitions.get(index); 255 while (index < partitions.size() && (position.getOffset() < rangeEnd)) { 256 list.add(position); 257 index++; 258 if (index < partitions.size()) { 259 position= (IOConsolePartition) partitions.get(index); 260 } 261 } 262 263 return (ITypedRegion[]) list.toArray(new IOConsolePartition[list.size()]); 264 } 265 266 267 271 public ITypedRegion getPartition(int offset) { 272 for (int i = 0; i < partitions.size(); i++) { 273 ITypedRegion partition = (ITypedRegion) partitions.get(i); 274 int start = partition.getOffset(); 275 int end = start + partition.getLength(); 276 if (offset >= start && offset < end) { 277 return partition; 278 } 279 } 280 281 if (lastPartition == null) { 282 synchronized(partitions) { 283 lastPartition = new IOConsolePartition(inputStream, ""); lastPartition.setOffset(offset); 285 partitions.add(lastPartition); 286 inputPartitions.add(lastPartition); 287 } 288 } 289 return lastPartition; 290 } 291 292 298 private void checkBufferSize() { 299 if (document != null && highWaterMark > 0) { 300 int length = document.getLength(); 301 if (length > highWaterMark) { 302 if (trimJob.getState() == Job.NONE) { trimJob.setOffset(length - lowWaterMark); 304 trimJob.schedule(); 305 } 306 } 307 } 308 } 309 310 313 public void clearBuffer() { 314 synchronized (overflowLock) { 315 trimJob.setOffset(-1); 316 trimJob.schedule(); 317 } 318 } 319 320 325 public IRegion documentChanged2(DocumentEvent event) { 326 if (document == null) { 327 return null; } 329 if (document.getLength() == 0) { partitions.clear(); 331 inputPartitions.clear(); 332 pendingPartitions.clear(); 333 lastPartition = null; 334 return new Region(0, 0); 335 } 336 337 338 if (updateInProgress) { 339 synchronized(partitions) { 340 if (updatePartitions != null) { 341 for (Iterator i = updatePartitions.iterator(); i.hasNext(); ) { 342 PendingPartition pp = (PendingPartition) i.next(); 343 if (pp == consoleClosedPartition) { 344 continue; 345 } 346 347 int ppLen = pp.text.length(); 348 if (lastPartition != null && lastPartition.getStream() == pp.stream) { 349 int len = lastPartition.getLength(); 350 lastPartition.setLength(len + ppLen); 351 } else { 352 IOConsolePartition partition = new IOConsolePartition(pp.stream, ppLen); 353 partition.setOffset(firstOffset); 354 lastPartition = partition; 355 partitions.add(partition); 356 } 357 firstOffset += ppLen; 358 } 359 } 360 } 361 } else { int amountDeleted = event.getLength() ; 363 364 if (amountDeleted > 0) { 365 int offset = event.fOffset; 366 IOConsolePartition partition = (IOConsolePartition) getPartition(offset); 367 if(partition == lastPartition) { 368 partition.delete(event.fOffset-partition.getOffset(), amountDeleted); 369 } 370 } 371 372 synchronized(partitions) { 373 if (lastPartition == null || lastPartition.isReadOnly()) { 374 lastPartition = new IOConsolePartition(inputStream, event.fText); 375 lastPartition.setOffset(event.fOffset); 376 partitions.add(lastPartition); 377 inputPartitions.add(lastPartition); 378 } else { 379 lastPartition.insert(event.fText, (event.fOffset-lastPartition.getOffset())); 380 } 381 382 int lastLineDelimiter = -1; 383 String partitionText = lastPartition.getString(); 384 for (int i = 0; i < lld.length; i++) { 385 String ld = lld[i]; 386 int index = partitionText.lastIndexOf(ld); 387 if (index != -1) { 388 index += ld.length(); 389 } 390 if (index > lastLineDelimiter) { 391 lastLineDelimiter = index; 392 } 393 } 394 if (lastLineDelimiter != -1) { 395 StringBuffer input = new StringBuffer (); 396 Iterator it = inputPartitions.iterator(); 397 while (it.hasNext()) { 398 IOConsolePartition partition = (IOConsolePartition) it.next(); 399 if (partition.getOffset() + partition.getLength() <= event.fOffset + lastLineDelimiter) { 400 if (partition == lastPartition) { 401 lastPartition = null; 402 } 403 input.append(partition.getString()); 404 partition.clearBuffer(); 405 partition.setReadOnly(); 406 it.remove(); 407 } else { 408 String contentBefore = partitionText.substring(0, lastLineDelimiter); 411 IOConsolePartition newPartition = new IOConsolePartition(inputStream, contentBefore); 412 newPartition.setOffset(partition.getOffset()); 413 newPartition.setReadOnly(); 414 newPartition.clearBuffer(); 415 int index = partitions.indexOf(partition); 416 partitions.add(index, newPartition); 417 input.append(contentBefore); 418 partition.delete(0, lastLineDelimiter); 420 partition.setOffset(lastLineDelimiter + partition.getOffset()); 421 lastLineDelimiter = 0; 422 } 423 } 424 if (input.length() > 0) { 425 inputStream.appendData(input.toString()); 426 } 427 428 } 429 } 430 } 431 432 return new Region(event.fOffset, event.fText.length()); 433 } 434 435 private void setUpdateInProgress(boolean b) { 436 updateInProgress = b; 437 } 438 439 447 public void streamAppended(IOConsoleOutputStream stream, String s) throws IOException { 448 if (document == null) { 449 throw new IOException ("Document is closed"); } 451 synchronized(pendingPartitions) { 452 PendingPartition last = (PendingPartition) (pendingPartitions.size() > 0 ? pendingPartitions.get(pendingPartitions.size()-1) : null); 453 if (last != null && last.stream == stream) { 454 last.append(s); 455 } else { 456 pendingPartitions.add(new PendingPartition(stream, s)); 457 if (fBuffer > 1000) { 458 queueJob.schedule(); 459 } else { 460 queueJob.schedule(50); 461 } 462 } 463 464 if (fBuffer > 160000) { 465 try { 466 pendingPartitions.wait(); 467 } catch (InterruptedException e) { 468 } 469 } 470 } 471 } 472 473 476 private class PendingPartition { 477 StringBuffer text = new StringBuffer (8192); 478 IOConsoleOutputStream stream; 479 480 PendingPartition(IOConsoleOutputStream stream, String text) { 481 this.stream = stream; 482 if (text != null) { 483 append(text); 484 } 485 } 486 487 void append(String moreText) { 488 text.append(moreText); 489 fBuffer += moreText.length(); 490 } 491 } 492 493 497 private class QueueProcessingJob extends UIJob { 498 499 QueueProcessingJob() { 500 super("IOConsole Updater"); } 502 503 507 public IStatus runInUIThread(IProgressMonitor monitor) { 508 synchronized (overflowLock) { 509 ArrayList pendingCopy = new ArrayList (); 510 StringBuffer buffer = null; 511 boolean consoleClosed = false; 512 while (pendingPartitions.size() > 0) { 513 synchronized(pendingPartitions) { 514 pendingCopy.addAll(pendingPartitions); 515 pendingPartitions.clear(); 516 fBuffer = 0; 517 pendingPartitions.notifyAll(); 518 } 519 520 buffer = new StringBuffer (); 521 for (Iterator i = pendingCopy.iterator(); i.hasNext(); ) { 522 PendingPartition pp = (PendingPartition) i.next(); 523 if (pp != consoleClosedPartition) { 524 buffer.append(pp.text); 525 } else { 526 consoleClosed = true; 527 } 528 } 529 } 530 531 if (connected) { 532 setUpdateInProgress(true); 533 updatePartitions = pendingCopy; 534 firstOffset = document.getLength(); 535 try { 536 document.replace(firstOffset, 0, buffer.toString()); 537 } catch (BadLocationException e) { 538 } 539 updatePartitions = null; 540 setUpdateInProgress(false); 541 } 542 if (consoleClosed) { 543 console.partitionerFinished(); 544 } 545 checkBufferSize(); 546 547 } 548 549 return Status.OK_STATUS; 550 } 551 552 559 public boolean shouldRun() { 560 boolean shouldRun = connected && pendingPartitions != null && pendingPartitions.size() > 0; 561 return shouldRun; 562 } 563 } 564 565 566 567 568 569 570 571 574 private class TrimJob extends WorkbenchJob { 575 576 580 private int truncateOffset; 581 582 585 TrimJob() { 586 super("Trim Job"); setSystem(true); 588 } 589 590 595 public void setOffset(int offset) { 596 truncateOffset = offset; 597 } 598 599 602 public IStatus runInUIThread(IProgressMonitor monitor) { 603 IJobManager jobManager = Job.getJobManager(); 604 try { 605 jobManager.join(console, monitor); 606 } catch (OperationCanceledException e1) { 607 return Status.CANCEL_STATUS; 608 } catch (InterruptedException e1) { 609 return Status.CANCEL_STATUS; 610 } 611 if (document == null) { 612 return Status.OK_STATUS; 613 } 614 615 int length = document.getLength(); 616 if (truncateOffset < length) { 617 synchronized (overflowLock) { 618 try { 619 if (truncateOffset < 0) { 620 setUpdateInProgress(true); 622 document.set(""); setUpdateInProgress(false); 624 partitions.clear(); 625 } else { 626 int cutoffLine = document.getLineOfOffset(truncateOffset); 628 int cutOffset = document.getLineOffset(cutoffLine); 629 630 631 IOConsolePartition partition = (IOConsolePartition) getPartition(cutOffset); 633 partition.setLength(partition.getOffset() + partition.getLength() - cutOffset); 634 635 setUpdateInProgress(true); 636 document.replace(0, cutOffset, ""); setUpdateInProgress(false); 638 639 int index = partitions.indexOf(partition); 641 for (int i = 0; i < index; i++) { 642 partitions.remove(0); 643 } 644 645 int offset = 0; 646 for (Iterator i = partitions.iterator(); i.hasNext(); ) { 647 IOConsolePartition p = (IOConsolePartition) i.next(); 648 p.setOffset(offset); 649 offset += p.getLength(); 650 } 651 } 652 } catch (BadLocationException e) { 653 } 654 } 655 } 656 return Status.OK_STATUS; 657 } 658 } 659 660 661 662 663 664 665 666 669 public boolean isReadOnly(int offset) { 670 return ((IOConsolePartition)getPartition(offset)).isReadOnly(); 671 } 672 673 676 public StyleRange[] getStyleRanges(int offset, int length) { 677 if (!connected) { 678 return new StyleRange[0]; 679 } 680 IOConsolePartition[] computedPartitions = (IOConsolePartition[])computePartitioning(offset, length); 681 StyleRange[] styles = new StyleRange[computedPartitions.length]; 682 for (int i = 0; i < computedPartitions.length; i++) { 683 int rangeStart = Math.max(computedPartitions[i].getOffset(), offset); 684 int rangeLength = computedPartitions[i].getLength(); 685 styles[i] = computedPartitions[i].getStyleRange(rangeStart, rangeLength); 686 } 687 return styles; 688 } 689 690 691 } 692 | Popular Tags |