|
18 | 18 | import java.util.List; |
19 | 19 | import java.util.concurrent.CompletableFuture; |
20 | 20 | import java.util.concurrent.atomic.AtomicInteger; |
| 21 | +import java.util.concurrent.atomic.AtomicReference; |
| 22 | +import java.util.regex.Matcher; |
| 23 | +import java.util.regex.Pattern; |
21 | 24 |
|
22 | 25 | import org.junit.After; |
23 | 26 | import org.junit.Assert; |
|
55 | 58 | import org.eclipse.jface.text.codemining.DocumentFooterCodeMining; |
56 | 59 | import org.eclipse.jface.text.codemining.ICodeMining; |
57 | 60 | import org.eclipse.jface.text.codemining.ICodeMiningProvider; |
| 61 | +import org.eclipse.jface.text.codemining.LineContentCodeMining; |
58 | 62 | import org.eclipse.jface.text.codemining.LineHeaderCodeMining; |
59 | 63 | import org.eclipse.jface.text.reconciler.DirtyRegion; |
60 | 64 | import org.eclipse.jface.text.reconciler.IReconcilingStrategy; |
61 | 65 | import org.eclipse.jface.text.reconciler.MonoReconciler; |
62 | 66 | import org.eclipse.jface.text.source.AnnotationModel; |
63 | 67 | import org.eclipse.jface.text.source.AnnotationPainter; |
64 | 68 | import org.eclipse.jface.text.source.SourceViewer; |
| 69 | +import org.eclipse.jface.text.source.inlined.Positions; |
65 | 70 | import org.eclipse.jface.text.tests.TextViewerTest; |
66 | 71 |
|
67 | 72 | import org.eclipse.ui.tests.harness.util.DisplayHelper; |
@@ -491,6 +496,49 @@ protected boolean condition() { |
491 | 496 | }.waitForCondition(widget.getDisplay(), 1000)); |
492 | 497 | } |
493 | 498 |
|
| 499 | + @Test |
| 500 | + public void testCodeMiningSwitchingBetweenInLineAndLineHeader() { |
| 501 | + String ref= "REF-X"; |
| 502 | + String text= "Here " + ref + " is a reference."; |
| 503 | + fViewer.getDocument().set(text); |
| 504 | + int index= text.indexOf(ref); |
| 505 | + |
| 506 | + // in-line mode |
| 507 | + AtomicReference<Boolean> useInLineCodeMinings= new AtomicReference<>(true); |
| 508 | + fViewer.setCodeMiningProviders(new ICodeMiningProvider[] { new RefTestCodeMiningProvider(useInLineCodeMinings) }); |
| 509 | + |
| 510 | + StyledText widget= fViewer.getTextWidget(); |
| 511 | + Assert.assertTrue("Line header code minigs were used. Expected in-line code minings instead.", new DisplayHelper() { |
| 512 | + @Override |
| 513 | + protected boolean condition() { |
| 514 | + return widget.getStyleRangeAtOffset(index - 1) != null |
| 515 | + && widget.isVisible() && widget.getLineVerticalIndent(0) == 0; |
| 516 | + } |
| 517 | + }.waitForCondition(widget.getDisplay(), 1000)); |
| 518 | + |
| 519 | + // switch to line header mode |
| 520 | + useInLineCodeMinings.set(false); |
| 521 | + fViewer.updateCodeMinings(); |
| 522 | + |
| 523 | + Assert.assertTrue("In-line code minigs were used (or no code minings at all). Expected line header code minings.", new DisplayHelper() { |
| 524 | + @Override |
| 525 | + protected boolean condition() { |
| 526 | + return widget.getStyleRangeAtOffset(index - 1) == null && widget.getLineVerticalIndent(0) > 0; |
| 527 | + } |
| 528 | + }.waitForCondition(widget.getDisplay(), 1000)); |
| 529 | + |
| 530 | + // switch back to in-line mode |
| 531 | + useInLineCodeMinings.set(true); |
| 532 | + fViewer.updateCodeMinings(); |
| 533 | + |
| 534 | + Assert.assertTrue("Line header code minigs were used. Expected in-line code minings instead.", new DisplayHelper() { |
| 535 | + @Override |
| 536 | + protected boolean condition() { |
| 537 | + return widget.getStyleRangeAtOffset(index - 1) != null && widget.getLineVerticalIndent(0) == 0; |
| 538 | + } |
| 539 | + }.waitForCondition(widget.getDisplay(), 1000)); |
| 540 | + } |
| 541 | + |
494 | 542 | private static boolean hasCodeMiningPrintedBelowLine(ITextViewer viewer, int line) throws BadLocationException { |
495 | 543 | StyledText widget= viewer.getTextWidget(); |
496 | 544 | IDocument document= viewer.getDocument(); |
@@ -574,4 +622,88 @@ private static boolean hasCodeMiningPrintedAfterTextOnLine(ITextViewer viewer, i |
574 | 622 | image.dispose(); |
575 | 623 | return false; |
576 | 624 | } |
| 625 | + |
| 626 | + private static class RefTestCodeMiningProvider extends AbstractCodeMiningProvider { |
| 627 | + |
| 628 | + private static final String REGEX_REF= "REF-X"; |
| 629 | + |
| 630 | + private static final Pattern REGEX_PATTERN= Pattern.compile(REGEX_REF); |
| 631 | + |
| 632 | + private AtomicReference<Boolean> useInLineCodeMinings; |
| 633 | + |
| 634 | + public RefTestCodeMiningProvider(AtomicReference<Boolean> useInLineCodeMinings) { |
| 635 | + this.useInLineCodeMinings= useInLineCodeMinings; |
| 636 | + } |
| 637 | + |
| 638 | + @Override |
| 639 | + public CompletableFuture<List<? extends ICodeMining>> provideCodeMinings(ITextViewer viewer, |
| 640 | + IProgressMonitor monitor) { |
| 641 | + return CompletableFuture.supplyAsync(() -> { |
| 642 | + IDocument document= viewer.getDocument(); |
| 643 | + |
| 644 | + if (document == null) { |
| 645 | + return Collections.emptyList(); |
| 646 | + } |
| 647 | + |
| 648 | + return createCodeMiningsFor(document); |
| 649 | + }); |
| 650 | + } |
| 651 | + |
| 652 | + List<ICodeMining> createCodeMiningsFor(IDocument document) { |
| 653 | + String documentContent= document.get(); |
| 654 | + List<ICodeMining> minings= new ArrayList<>(); |
| 655 | + |
| 656 | + Matcher regexMatcher= REGEX_PATTERN.matcher(documentContent); |
| 657 | + while (regexMatcher.find()) { |
| 658 | + String matchedText= regexMatcher.group(); |
| 659 | + int startIndex= regexMatcher.start(); |
| 660 | + |
| 661 | + String title= "Building commercial quality plug-ins"; |
| 662 | + |
| 663 | + if (useInLineCodeMinings.get()) { |
| 664 | + minings.add(new ReferenceInLineCodeMining(title + ": ", startIndex, document, this)); |
| 665 | + } else { |
| 666 | + try { |
| 667 | + int offset= startIndex; |
| 668 | + int line= document.getLineOfOffset(offset); |
| 669 | + int lineOffset= document.getLineOffset(line); |
| 670 | + |
| 671 | + minings.add(new ReferenceLineHeaderCodeMining(title, line, offset - lineOffset, title.length(), |
| 672 | + document, this)); |
| 673 | + } catch (BadLocationException e) { |
| 674 | + e.printStackTrace(); |
| 675 | + } |
| 676 | + } |
| 677 | + } |
| 678 | + |
| 679 | + return minings; |
| 680 | + } |
| 681 | + } |
| 682 | + |
| 683 | + private static class ReferenceInLineCodeMining extends LineContentCodeMining { |
| 684 | + |
| 685 | + public ReferenceInLineCodeMining(String label, int positionOffset, IDocument document, |
| 686 | + ICodeMiningProvider provider) { |
| 687 | + super(new Position(positionOffset, 1), provider); |
| 688 | + this.setLabel(label); |
| 689 | + } |
| 690 | + |
| 691 | + } |
| 692 | + |
| 693 | + private static class ReferenceLineHeaderCodeMining extends LineHeaderCodeMining { |
| 694 | + |
| 695 | + public ReferenceLineHeaderCodeMining(String label, int beforeLineNumber, int columnInLine, int length, |
| 696 | + IDocument document, ICodeMiningProvider provider) throws BadLocationException { |
| 697 | + super(calculatePosition(beforeLineNumber, columnInLine, document), provider, null); |
| 698 | + this.setLabel(label); |
| 699 | + } |
| 700 | + |
| 701 | + private static Position calculatePosition(int beforeLineNumber, int columnInLine, IDocument document) |
| 702 | + throws BadLocationException { |
| 703 | + Position pos= Positions.of(beforeLineNumber, document, true); |
| 704 | + pos.setOffset(pos.offset + columnInLine); |
| 705 | + return pos; |
| 706 | + } |
| 707 | + |
| 708 | + } |
577 | 709 | } |
0 commit comments