[devkit] make `UElementAsPsiInspection` report on return values
[idea/community.git] / platform / diff-impl / src / com / intellij / diff / tools / fragmented / UnifiedEditorRangeHighlighter.java
1 /*
2  * Copyright 2000-2015 JetBrains s.r.o.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.intellij.diff.tools.fragmented;
17
18 import com.intellij.openapi.application.ApplicationManager;
19 import com.intellij.openapi.editor.Document;
20 import com.intellij.openapi.editor.ex.MarkupModelEx;
21 import com.intellij.openapi.editor.ex.RangeHighlighterEx;
22 import com.intellij.openapi.editor.impl.DocumentMarkupModel;
23 import com.intellij.openapi.editor.markup.MarkupModel;
24 import com.intellij.openapi.progress.ProgressManager;
25 import com.intellij.openapi.project.Project;
26 import com.intellij.openapi.util.TextRange;
27 import org.jetbrains.annotations.NotNull;
28 import org.jetbrains.annotations.Nullable;
29
30 import java.util.ArrayList;
31 import java.util.List;
32
33 class UnifiedEditorRangeHighlighter {
34   @NotNull private final List<Element> myPieces = new ArrayList<>();
35
36   UnifiedEditorRangeHighlighter(@Nullable Project project,
37                                 @NotNull Document document1,
38                                 @NotNull Document document2,
39                                 @NotNull List<HighlightRange> ranges) {
40     ApplicationManager.getApplication().assertReadAccessAllowed();
41
42     MarkupModelEx model1 = (MarkupModelEx)DocumentMarkupModel.forDocument(document1, project, false);
43     MarkupModelEx model2 = (MarkupModelEx)DocumentMarkupModel.forDocument(document2, project, false);
44     init(model1, model2, ranges);
45   }
46
47   private void init(@Nullable MarkupModelEx model1,
48                     @Nullable MarkupModelEx model2,
49                     @NotNull List<HighlightRange> ranges) {
50     for (HighlightRange range : ranges) {
51       if (range.getSide().isLeft()) {
52         if (model1 != null) processRange(model1, range);
53       }
54       else {
55         if (model2 != null) processRange(model2, range);
56       }
57     }
58   }
59
60   private void processRange(@NotNull MarkupModelEx model, @NotNull HighlightRange range) {
61     final TextRange base = range.getBase();
62     final TextRange changed = range.getChanged();
63     final int changedLength = changed.getEndOffset() - changed.getStartOffset();
64
65     model.processRangeHighlightersOverlappingWith(changed.getStartOffset(), changed.getEndOffset(), marker -> {
66       int relativeStart = Math.max(marker.getStartOffset() - changed.getStartOffset(), 0);
67       int relativeEnd = Math.min(marker.getEndOffset() - changed.getStartOffset(), changedLength);
68
69       int newStart = base.getStartOffset() + relativeStart;
70       int newEnd = base.getStartOffset() + relativeEnd;
71
72       if (newEnd - newStart <= 0) return true;
73
74       if (myPieces.size() % 1014 == 0) ProgressManager.checkCanceled();
75       myPieces.add(new Element(marker, newStart, newEnd));
76
77       return true;
78     });
79   }
80
81   public static void erase(@Nullable Project project, @NotNull Document document) {
82     MarkupModel model = DocumentMarkupModel.forDocument(document, project, true);
83     model.removeAllHighlighters();
84   }
85
86   public void apply(@Nullable Project project, @NotNull Document document) {
87     MarkupModelEx model = (MarkupModelEx)DocumentMarkupModel.forDocument(document, project, true);
88
89     for (Element piece : myPieces) {
90       RangeHighlighterEx delegate = piece.getDelegate();
91       if (!delegate.isValid()) continue;
92
93       model.addRangeHighlighterAndChangeAttributes(
94         delegate.getTextAttributesKey(), piece.getStart(), piece.getEnd(), delegate.getLayer(),
95         delegate.getTargetArea(), false, ex -> {
96           ex.copyFrom(delegate);
97         });
98     }
99   }
100
101   private static class Element {
102     @NotNull private final RangeHighlighterEx myDelegate;
103
104     private final int myStart;
105     private final int myEnd;
106
107     Element(@NotNull RangeHighlighterEx delegate, int start, int end) {
108       myDelegate = delegate;
109       myStart = start;
110       myEnd = end;
111     }
112
113     @NotNull
114     public RangeHighlighterEx getDelegate() {
115       return myDelegate;
116     }
117
118     public int getStart() {
119       return myStart;
120     }
121
122     public int getEnd() {
123       return myEnd;
124     }
125   }
126 }