Codebase list eclipse-platform-text / 0d2976e
New upstream version 4.12 Emmanuel Bourg 4 years ago
221 changed file(s) with 5965 addition(s) and 4889 deletion(s). Raw diff Collapse all Expand all
11 Bundle-ManifestVersion: 2
22 Bundle-Name: %pluginName
33 Bundle-SymbolicName: org.eclipse.core.filebuffers; singleton:=true
4 Bundle-Version: 3.6.500.qualifier
4 Bundle-Version: 3.6.600.qualifier
55 Bundle-Activator: org.eclipse.core.internal.filebuffers.FileBuffersPlugin
66 Bundle-ActivationPolicy: lazy
77 Bundle-Vendor: %providerName
1313 <parent>
1414 <artifactId>eclipse.platform.text</artifactId>
1515 <groupId>eclipse.platform.text</groupId>
16 <version>4.11.0-SNAPSHOT</version>
16 <version>4.12.0-SNAPSHOT</version>
1717 </parent>
1818 <groupId>org.eclipse.core</groupId>
1919 <artifactId>org.eclipse.core.filebuffers</artifactId>
20 <version>3.6.500-SNAPSHOT</version>
20 <version>3.6.600-SNAPSHOT</version>
2121 <packaging>eclipse-plugin</packaging>
2222 </project>
9595 ITextFileBuffer getFileStoreTextFileBuffer(IFileStore fileStore);
9696
9797 /**
98 * Returns the text file buffer managed for the given document
98 * Returns the text file buffer managed for the given document
9999 * or <code>null</code> if there is no such text file buffer.
100100 * <p>
101101 * <strong>Note:</strong> This method goes through the list
3131 * connected using a file store will not be found.
3232 * </p>
3333 *
34 * @see IFileBufferManager#connectFileStore(org.eclipse.core.filesystem.IFileStore, org.eclipse.core.runtime.IProgressMonitor)
34 * @see IFileBufferManager#connectFileStore(org.eclipse.core.filesystem.IFileStore, org.eclipse.core.runtime.IProgressMonitor)
3535 */
3636 public static final LocationKind LOCATION= new LocationKind("location"); //$NON-NLS-1$
3737
112112 /** Tells whether the file on disk has a BOM. */
113113 private boolean fHasBOM;
114114 /** The annotation model of this file buffer */
115 private IAnnotationModel fAnnotationModel;
115 private IAnnotationModel fAnnotationModel;
116116 /**
117117 * Lock for lazy creation of annotation model.
118118 * @since 3.2
257257 if (fAnnotationModel instanceof IPersistableAnnotationModel) {
258258 IPersistableAnnotationModel persistableModel= (IPersistableAnnotationModel) fAnnotationModel;
259259 try {
260 persistableModel.revert(fDocument);
260 persistableModel.revert(fDocument);
261261 } catch (CoreException x) {
262262 fStatus= x.getStatus();
263263 }
1313 <parent>
1414 <artifactId>tests-pom</artifactId>
1515 <groupId>eclipse.platform.text</groupId>
16 <version>4.11.0-SNAPSHOT</version>
16 <version>4.12.0-SNAPSHOT</version>
1717 <relativePath>../tests-pom/</relativePath>
1818 </parent>
1919 <groupId>org.eclipse.core</groupId>
11 Bundle-ManifestVersion: 2
22 Bundle-Name: %pluginName
33 Bundle-SymbolicName: org.eclipse.jface.text
4 Bundle-Version: 3.15.100.qualifier
4 Bundle-Version: 3.15.200.qualifier
55 Bundle-Vendor: %providerName
66 Bundle-Localization: plugin
77 Export-Package:
1313 <parent>
1414 <artifactId>eclipse.platform.text</artifactId>
1515 <groupId>eclipse.platform.text</groupId>
16 <version>4.11.0-SNAPSHOT</version>
16 <version>4.12.0-SNAPSHOT</version>
1717 </parent>
1818 <groupId>org.eclipse.jface</groupId>
1919 <artifactId>org.eclipse.jface.text</artifactId>
20 <version>3.15.100-SNAPSHOT</version>
20 <version>3.15.200-SNAPSHOT</version>
2121 <packaging>eclipse-plugin</packaging>
2222 </project>
0 /**
1 * Copyright (c) 2017 Angelo ZERR.
0 /**
1 * Copyright (c) 2017 Angelo ZERR.
22 *
3 * This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License 2.0
5 * which accompanies this distribution, and is available at
3 * This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License 2.0
5 * which accompanies this distribution, and is available at
66 * https://www.eclipse.org/legal/epl-2.0/
77 *
8 * SPDX-License-Identifier: EPL-2.0
9 *
10 * Contributors:
11 * Angelo Zerr <angelo.zerr@gmail.com> - [CodeMining] Provide CodeMining support with CodeMiningManager - Bug 527720
12 */
13 package org.eclipse.jface.internal.text.codemining;
14
15 import java.util.concurrent.CancellationException;
16
17 import org.eclipse.core.runtime.IProgressMonitor;
18 import org.eclipse.core.runtime.NullProgressMonitor;
19
20 /**
21 * {@link IProgressMonitor} which throws a {@link CancellationException} when
22 * {@link IProgressMonitor#isCanceled()} returns true.
23 *
24 * @since 3.13
25 */
26 class CancellationExceptionMonitor extends NullProgressMonitor {
27
28 @Override
29 public boolean isCanceled() {
30 boolean canceled= super.isCanceled();
31 if (canceled) {
32 throw new CancellationException();
33 }
34 return canceled;
35 }
36 }
8 * SPDX-License-Identifier: EPL-2.0
9 *
10 * Contributors:
11 * Angelo Zerr <angelo.zerr@gmail.com> - [CodeMining] Provide CodeMining support with CodeMiningManager - Bug 527720
12 */
13 package org.eclipse.jface.internal.text.codemining;
14
15 import java.util.concurrent.CancellationException;
16
17 import org.eclipse.core.runtime.IProgressMonitor;
18 import org.eclipse.core.runtime.NullProgressMonitor;
19
20 /**
21 * {@link IProgressMonitor} which throws a {@link CancellationException} when
22 * {@link IProgressMonitor#isCanceled()} returns true.
23 *
24 * @since 3.13
25 */
26 class CancellationExceptionMonitor extends NullProgressMonitor {
27
28 @Override
29 public boolean isCanceled() {
30 boolean canceled= super.isCanceled();
31 if (canceled) {
32 throw new CancellationException();
33 }
34 return canceled;
35 }
36 }
0 /**
1 * Copyright (c) 2017 Angelo ZERR.
2 *
3 * This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License 2.0
5 * which accompanies this distribution, and is available at
6 * https://www.eclipse.org/legal/epl-2.0/
7 *
8 * SPDX-License-Identifier: EPL-2.0
9 *
10 * Contributors:
11 * Angelo Zerr <angelo.zerr@gmail.com> - [CodeMining] Provide CodeMining support with CodeMiningManager - Bug 527720
12 */
13 package org.eclipse.jface.internal.text.codemining;
14
15 import java.util.Arrays;
16 import java.util.Collections;
17 import java.util.HashSet;
18 import java.util.LinkedHashMap;
19 import java.util.List;
20 import java.util.Map;
21 import java.util.Set;
22 import java.util.concurrent.CancellationException;
23 import java.util.concurrent.CompletableFuture;
24 import java.util.function.Function;
25 import java.util.stream.Collectors;
26
27 import org.osgi.framework.Bundle;
28
29 import org.eclipse.swt.graphics.Rectangle;
30
31 import org.eclipse.core.runtime.Assert;
32 import org.eclipse.core.runtime.ILog;
33 import org.eclipse.core.runtime.IProgressMonitor;
34 import org.eclipse.core.runtime.IStatus;
35 import org.eclipse.core.runtime.Platform;
36 import org.eclipse.core.runtime.Status;
37
38 import org.eclipse.jface.text.IDocument;
39 import org.eclipse.jface.text.ITextViewer;
40 import org.eclipse.jface.text.Position;
41 import org.eclipse.jface.text.codemining.ICodeMining;
42 import org.eclipse.jface.text.codemining.ICodeMiningProvider;
43 import org.eclipse.jface.text.codemining.LineHeaderCodeMining;
44 import org.eclipse.jface.text.source.ISourceViewer;
45 import org.eclipse.jface.text.source.inlined.AbstractInlinedAnnotation;
46 import org.eclipse.jface.text.source.inlined.InlinedAnnotationSupport;
47
48 /**
49 * Code Mining manager implementation.
50 *
51 * @since 3.13
52 */
53 public class CodeMiningManager implements Runnable {
54
55 /**
56 * The source viewer
57 */
58 private final ISourceViewer fViewer;
59
60 /**
61 * The inlined annotation support used to draw CodeMining in the line spacing.
62 */
63 private final InlinedAnnotationSupport fInlinedAnnotationSupport;
64
65 /**
66 * The list of codemining providers.
67 */
68 private List<ICodeMiningProvider> fCodeMiningProviders;
69
70 /**
71 * The current progress monitor.
72 */
73 private IProgressMonitor fMonitor;
74
75 /**
76 * Constructor of codemining manager with the given arguments.
77 *
78 * @param viewer the source viewer
79 * @param inlinedAnnotationSupport the inlined annotation support used to draw code minings
80 * @param codeMiningProviders the array of codemining providers, must not be empty
81 */
82 public CodeMiningManager(ISourceViewer viewer, InlinedAnnotationSupport inlinedAnnotationSupport,
83 ICodeMiningProvider[] codeMiningProviders) {
84 Assert.isNotNull(viewer);
85 Assert.isNotNull(inlinedAnnotationSupport);
86 Assert.isNotNull(codeMiningProviders);
87 fViewer= viewer;
88 fInlinedAnnotationSupport= inlinedAnnotationSupport;
89 setCodeMiningProviders(codeMiningProviders);
90 }
91
92 /**
93 * Set the codemining providers.
94 *
95 * @param codeMiningProviders the codemining providers.
96 */
97 public void setCodeMiningProviders(ICodeMiningProvider[] codeMiningProviders) {
98 cancel();
99 if (fCodeMiningProviders != null) {
100 fCodeMiningProviders.stream().forEach(ICodeMiningProvider::dispose);
101 }
102 fCodeMiningProviders= Arrays.asList(codeMiningProviders);
103 }
104
105 /**
106 * Uninstalls this codemining manager.
107 */
108 public void uninstall() {
109 cancel();
110 if (fInlinedAnnotationSupport != null) {
111 fInlinedAnnotationSupport.updateAnnotations(Collections.emptySet());
112 }
113 }
114
115 /**
116 * Collect, resolve and render the code minings of the viewer.
117 */
118 @Override
119 public void run() {
120 if (fViewer == null || fInlinedAnnotationSupport == null || fCodeMiningProviders == null
121 || fCodeMiningProviders.size() == 0 || fViewer.getAnnotationModel() == null) {
122 return;
123 }
124 // Cancel the last progress monitor to cancel last resolve and render of code
125 // minings
126 cancel();
127 // Update the code minings
128 updateCodeMinings();
129 }
130
131 /**
132 * Update the code minings.
133 */
134 private void updateCodeMinings() {
135 // Refresh the code minings by using the new progress monitor.
136 fMonitor= new CancellationExceptionMonitor();
137 IProgressMonitor monitor= fMonitor;
138 // Collect the code minings for the viewer
139 getCodeMinings(fViewer, fCodeMiningProviders, monitor).thenAccept(symbols -> {
140 // check if request was canceled.
141 monitor.isCanceled();
142 // then group code minings by lines position
143 Map<Position, List<ICodeMining>> groups= groupByLines(symbols, fCodeMiningProviders);
144 // resolve and render code minings
145 renderCodeMinings(groups, fViewer, monitor);
146 });
147 }
148
149 /**
150 * Cancel the codemining process.
151 */
152 private void cancel() {
153 // Cancel the last progress monitor.
154 if (fMonitor != null) {
155 fMonitor.setCanceled(true);
156 }
157 }
158
159 private static void logCodeMiningProviderException(Throwable e) {
160 if (e != null && (e instanceof CancellationException || (e.getCause() != null && e.getCause() instanceof CancellationException))) {
161 return;
162 }
163 String PLUGIN_ID= "org.eclipse.jface.text"; //$NON-NLS-1$
164 Bundle plugin= Platform.getBundle(PLUGIN_ID);
165 if (plugin != null) {
166 // In OSGi context, uses Platform Text log
167 ILog log= Platform.getLog(plugin);
168 log.log(new Status(IStatus.ERROR, PLUGIN_ID, IStatus.OK, e.getMessage(), e));
169 } else {
170 // In java main context, print stack trace
171 System.err.println("Error while code mining process: " + e.getMessage()); //$NON-NLS-1$
172 }
173 }
174
175 /**
176 * Return the list of {@link CompletableFuture} which provides the list of {@link ICodeMining}
177 * for the given <code>viewer</code> by using the given providers.
178 *
179 * @param viewer the text viewer.
180 * @param providers the CodeMining list providers.
181 * @param monitor the progress monitor.
182 * @return the list of {@link CompletableFuture} which provides the list of {@link ICodeMining}
183 * for the given <code>viewer</code> by using the given providers.
184 */
185 private static CompletableFuture<List<? extends ICodeMining>> getCodeMinings(ITextViewer viewer,
186 List<ICodeMiningProvider> providers, IProgressMonitor monitor) {
187 List<CompletableFuture<List<? extends ICodeMining>>> com= providers.stream()
188 .map(provider -> provider.provideCodeMinings(viewer, monitor))
189 .filter(c -> c != null)
190 .map(future -> future.exceptionally(e -> {
191 logCodeMiningProviderException(e);
192 return Collections.emptyList();
193 }))
194 .collect(Collectors.toList());
195 return CompletableFuture.allOf(com.toArray(new CompletableFuture[com.size()])).thenApply(
196 v -> com.stream().map(CompletableFuture::join).flatMap(l -> l.stream()).collect(Collectors.toList()));
197 }
198
199 /**
200 * Returns a sorted Map which groups the given code minings by same position line.
201 *
202 * @param codeMinings list of code minings to group.
203 * @param providers CodeMining providers used to retrieve code minings.
204 * @return a sorted Map which groups the given code minings by same position line.
205 */
206 private static Map<Position, List<ICodeMining>> groupByLines(List<? extends ICodeMining> codeMinings,
207 List<ICodeMiningProvider> providers) {
208 // sort code minings by lineNumber and provider-rank if
209 Collections.sort(codeMinings, (a, b) -> {
210 if (a.getPosition().offset < b.getPosition().offset) {
211 return -1;
212 } else if (a.getPosition().offset > b.getPosition().offset) {
213 return 1;
214 } else if (providers.indexOf(a.getProvider()) < providers.indexOf(b.getProvider())) {
215 return -1;
216 } else if (providers.indexOf(a.getProvider()) > providers.indexOf(b.getProvider())) {
217 return 1;
218 } else {
219 return 0;
220 }
221 });
222 return codeMinings.stream().collect(Collectors.groupingBy(ICodeMining::getPosition, LinkedHashMap::new,
223 Collectors.mapping(Function.identity(), Collectors.toList())));
224 }
225
226 /**
227 * Render the codemining grouped by line position.
228 *
229 * @param groups code minings grouped by lines position
230 * @param viewer the viewer
231 * @param monitor the progress monitor
232 */
233 private void renderCodeMinings(Map<Position, List<ICodeMining>> groups, ISourceViewer viewer,
234 IProgressMonitor monitor) {
235 // check if request was canceled.
236 monitor.isCanceled();
237 IDocument document= viewer != null ? viewer.getDocument() : null;
238 if (document == null) {
239 // this case comes from when editor is closed before codemining rendered is
240 // done.
241 return;
242 }
243 Set<ICodeMiningAnnotation> annotationsToRedraw= new HashSet<>();
244 Set<AbstractInlinedAnnotation> currentAnnotations= new HashSet<>();
245 // Loop for grouped code minings
246 groups.entrySet().stream().forEach(g -> {
247 // check if request was canceled.
248 monitor.isCanceled();
249
250 Position pos= new Position(g.getKey().offset, g.getKey().length);
251 List<ICodeMining> minings= g.getValue();
252 boolean inLineHeader= minings.size() > 0 ? (minings.get(0) instanceof LineHeaderCodeMining) : true;
253 // Try to find existing annotation
254 AbstractInlinedAnnotation ann= fInlinedAnnotationSupport.findExistingAnnotation(pos);
255 if (ann == null) {
256 // The annotation doesn't exists, create it.
257 ann= inLineHeader ? new CodeMiningLineHeaderAnnotation(pos, viewer) : new CodeMiningLineContentAnnotation(pos, viewer);
258 } else if (ann instanceof ICodeMiningAnnotation && ((ICodeMiningAnnotation) ann).isInVisibleLines()) {
259 // annotation is in visible lines
260 annotationsToRedraw.add((ICodeMiningAnnotation) ann);
261 }
262 ((ICodeMiningAnnotation) ann).update(minings, monitor);
263 currentAnnotations.add(ann);
264 });
265 // check if request was canceled.
266 monitor.isCanceled();
267 fInlinedAnnotationSupport.updateAnnotations(currentAnnotations);
268 // redraw the existing codemining annotations since their content can change
269 annotationsToRedraw.stream().forEach(ann -> ann.redraw());
270 }
271
272 /**
273 * Returns <code>true</code> if the given mining has a non empty label and <code>false</code>
274 * otherwise.
275 *
276 * @param mining the mining to check
277 * @return <code>true</code> if the given mining has a non empty label and <code>false</code>
278 * otherwise.
279 */
280 static boolean isValidMining(ICodeMining mining) {
281 return mining != null && mining.getLabel() != null && !mining.getLabel().isEmpty();
282 }
283
284 /**
285 * Returns the valid code mining at the given location by using the bounds of codemining
286 * annotations which stores only the valid code mining.
287 *
288 * @param minings the list of mining of the codemining annotation.
289 * @param bounds the bounds of the valid minings of the codemining annotation.
290 * @param x the x location
291 * @param y the y location
292 * @return the valid code mining at the given location by using the bounds of codemining
293 * annotations which stores only the valid code mining.
294 */
295 static ICodeMining getValidCodeMiningAtLocation(ICodeMining[] minings, List<Rectangle> bounds, int x, int y) {
296 for (int i= 0; i < bounds.size(); i++) {
297 Rectangle bound= bounds.get(i);
298 if (bound.contains(x, y)) {
299 return getCodeValidMiningAtIndex(minings, i);
300 }
301 }
302 return null;
303 }
304
305 /**
306 * Returns the valid code mining at the given index.
307 *
308 * @param minings the list of minings
309 * @param index the index
310 * @return the valid code mining at the given index.
311 */
312 private static ICodeMining getCodeValidMiningAtIndex(ICodeMining[] minings, int index) {
313 int validIndex= 0;
314 for (ICodeMining mining : minings) {
315 if (isValidMining(mining)) {
316 if (validIndex == index) {
317 return mining;
318 }
319 validIndex++;
320 }
321 }
322 return null;
323 }
324 }
0 /**
1 * Copyright (c) 2017 Angelo ZERR.
2 *
3 * This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License 2.0
5 * which accompanies this distribution, and is available at
6 * https://www.eclipse.org/legal/epl-2.0/
7 *
8 * SPDX-License-Identifier: EPL-2.0
9 *
10 * Contributors:
11 * Angelo Zerr <angelo.zerr@gmail.com> - [CodeMining] Provide CodeMining support with CodeMiningManager - Bug 527720
12 */
13 package org.eclipse.jface.internal.text.codemining;
14
15 import java.util.Arrays;
16 import java.util.Collections;
17 import java.util.HashSet;
18 import java.util.LinkedHashMap;
19 import java.util.List;
20 import java.util.Map;
21 import java.util.Set;
22 import java.util.concurrent.CancellationException;
23 import java.util.concurrent.CompletableFuture;
24 import java.util.function.Function;
25 import java.util.stream.Collectors;
26
27 import org.osgi.framework.Bundle;
28
29 import org.eclipse.swt.graphics.Rectangle;
30
31 import org.eclipse.core.runtime.Assert;
32 import org.eclipse.core.runtime.ILog;
33 import org.eclipse.core.runtime.IProgressMonitor;
34 import org.eclipse.core.runtime.IStatus;
35 import org.eclipse.core.runtime.Platform;
36 import org.eclipse.core.runtime.Status;
37
38 import org.eclipse.jface.text.IDocument;
39 import org.eclipse.jface.text.ITextViewer;
40 import org.eclipse.jface.text.Position;
41 import org.eclipse.jface.text.codemining.ICodeMining;
42 import org.eclipse.jface.text.codemining.ICodeMiningProvider;
43 import org.eclipse.jface.text.codemining.LineHeaderCodeMining;
44 import org.eclipse.jface.text.source.ISourceViewer;
45 import org.eclipse.jface.text.source.inlined.AbstractInlinedAnnotation;
46 import org.eclipse.jface.text.source.inlined.InlinedAnnotationSupport;
47
48 /**
49 * Code Mining manager implementation.
50 *
51 * @since 3.13
52 */
53 public class CodeMiningManager implements Runnable {
54
55 /**
56 * The source viewer
57 */
58 private final ISourceViewer fViewer;
59
60 /**
61 * The inlined annotation support used to draw CodeMining in the line spacing.
62 */
63 private final InlinedAnnotationSupport fInlinedAnnotationSupport;
64
65 /**
66 * The list of codemining providers.
67 */
68 private List<ICodeMiningProvider> fCodeMiningProviders;
69
70 /**
71 * The current progress monitor.
72 */
73 private IProgressMonitor fMonitor;
74
75 /**
76 * Constructor of codemining manager with the given arguments.
77 *
78 * @param viewer the source viewer
79 * @param inlinedAnnotationSupport the inlined annotation support used to draw code minings
80 * @param codeMiningProviders the array of codemining providers, must not be empty
81 */
82 public CodeMiningManager(ISourceViewer viewer, InlinedAnnotationSupport inlinedAnnotationSupport,
83 ICodeMiningProvider[] codeMiningProviders) {
84 Assert.isNotNull(viewer);
85 Assert.isNotNull(inlinedAnnotationSupport);
86 Assert.isNotNull(codeMiningProviders);
87 fViewer= viewer;
88 fInlinedAnnotationSupport= inlinedAnnotationSupport;
89 setCodeMiningProviders(codeMiningProviders);
90 }
91
92 /**
93 * Set the codemining providers.
94 *
95 * @param codeMiningProviders the codemining providers.
96 */
97 public void setCodeMiningProviders(ICodeMiningProvider[] codeMiningProviders) {
98 cancel();
99 if (fCodeMiningProviders != null) {
100 fCodeMiningProviders.stream().forEach(ICodeMiningProvider::dispose);
101 }
102 fCodeMiningProviders= Arrays.asList(codeMiningProviders);
103 }
104
105 /**
106 * Uninstalls this codemining manager.
107 */
108 public void uninstall() {
109 cancel();
110 if (fInlinedAnnotationSupport != null) {
111 fInlinedAnnotationSupport.updateAnnotations(Collections.emptySet());
112 }
113 }
114
115 /**
116 * Collect, resolve and render the code minings of the viewer.
117 */
118 @Override
119 public void run() {
120 if (fViewer == null || fInlinedAnnotationSupport == null || fCodeMiningProviders == null
121 || fCodeMiningProviders.size() == 0 || fViewer.getAnnotationModel() == null) {
122 return;
123 }
124 // Cancel the last progress monitor to cancel last resolve and render of code
125 // minings
126 cancel();
127 // Update the code minings
128 updateCodeMinings();
129 }
130
131 /**
132 * Update the code minings.
133 */
134 private void updateCodeMinings() {
135 // Refresh the code minings by using the new progress monitor.
136 fMonitor= new CancellationExceptionMonitor();
137 IProgressMonitor monitor= fMonitor;
138 // Collect the code minings for the viewer
139 getCodeMinings(fViewer, fCodeMiningProviders, monitor).thenAccept(symbols -> {
140 // check if request was canceled.
141 monitor.isCanceled();
142 // then group code minings by lines position
143 Map<Position, List<ICodeMining>> groups= groupByLines(symbols, fCodeMiningProviders);
144 // resolve and render code minings
145 renderCodeMinings(groups, fViewer, monitor);
146 });
147 }
148
149 /**
150 * Cancel the codemining process.
151 */
152 private void cancel() {
153 // Cancel the last progress monitor.
154 if (fMonitor != null) {
155 fMonitor.setCanceled(true);
156 }
157 }
158
159 private static void logCodeMiningProviderException(Throwable e) {
160 if (e != null && (e instanceof CancellationException || (e.getCause() != null && e.getCause() instanceof CancellationException))) {
161 return;
162 }
163 String PLUGIN_ID= "org.eclipse.jface.text"; //$NON-NLS-1$
164 Bundle plugin= Platform.getBundle(PLUGIN_ID);
165 if (plugin != null) {
166 // In OSGi context, uses Platform Text log
167 ILog log= Platform.getLog(plugin);
168 log.log(new Status(IStatus.ERROR, PLUGIN_ID, IStatus.OK, e.getMessage(), e));
169 } else {
170 // In java main context, print stack trace
171 System.err.println("Error while code mining process: " + e.getMessage()); //$NON-NLS-1$
172 }
173 }
174
175 /**
176 * Return the list of {@link CompletableFuture} which provides the list of {@link ICodeMining}
177 * for the given <code>viewer</code> by using the given providers.
178 *
179 * @param viewer the text viewer.
180 * @param providers the CodeMining list providers.
181 * @param monitor the progress monitor.
182 * @return the list of {@link CompletableFuture} which provides the list of {@link ICodeMining}
183 * for the given <code>viewer</code> by using the given providers.
184 */
185 private static CompletableFuture<List<? extends ICodeMining>> getCodeMinings(ITextViewer viewer,
186 List<ICodeMiningProvider> providers, IProgressMonitor monitor) {
187 List<CompletableFuture<List<? extends ICodeMining>>> com= providers.stream()
188 .map(provider -> provider.provideCodeMinings(viewer, monitor))
189 .filter(c -> c != null)
190 .map(future -> future.exceptionally(e -> {
191 logCodeMiningProviderException(e);
192 return Collections.emptyList();
193 }))
194 .collect(Collectors.toList());
195 return CompletableFuture.allOf(com.toArray(new CompletableFuture[com.size()])).thenApply(
196 v -> com.stream().map(CompletableFuture::join).flatMap(l -> l.stream()).collect(Collectors.toList()));
197 }
198
199 /**
200 * Returns a sorted Map which groups the given code minings by same position line.
201 *
202 * @param codeMinings list of code minings to group.
203 * @param providers CodeMining providers used to retrieve code minings.
204 * @return a sorted Map which groups the given code minings by same position line.
205 */
206 private static Map<Position, List<ICodeMining>> groupByLines(List<? extends ICodeMining> codeMinings,
207 List<ICodeMiningProvider> providers) {
208 // sort code minings by lineNumber and provider-rank if
209 Collections.sort(codeMinings, (a, b) -> {
210 if (a.getPosition().offset < b.getPosition().offset) {
211 return -1;
212 } else if (a.getPosition().offset > b.getPosition().offset) {
213 return 1;
214 } else if (providers.indexOf(a.getProvider()) < providers.indexOf(b.getProvider())) {
215 return -1;
216 } else if (providers.indexOf(a.getProvider()) > providers.indexOf(b.getProvider())) {
217 return 1;
218 } else {
219 return 0;
220 }
221 });
222 return codeMinings.stream().collect(Collectors.groupingBy(ICodeMining::getPosition, LinkedHashMap::new,
223 Collectors.mapping(Function.identity(), Collectors.toList())));
224 }
225
226 /**
227 * Render the codemining grouped by line position.
228 *
229 * @param groups code minings grouped by lines position
230 * @param viewer the viewer
231 * @param monitor the progress monitor
232 */
233 private void renderCodeMinings(Map<Position, List<ICodeMining>> groups, ISourceViewer viewer,
234 IProgressMonitor monitor) {
235 // check if request was canceled.
236 monitor.isCanceled();
237 IDocument document= viewer != null ? viewer.getDocument() : null;
238 if (document == null) {
239 // this case comes from when editor is closed before codemining rendered is
240 // done.
241 return;
242 }
243 Set<ICodeMiningAnnotation> annotationsToRedraw= new HashSet<>();
244 Set<AbstractInlinedAnnotation> currentAnnotations= new HashSet<>();
245 // Loop for grouped code minings
246 groups.entrySet().stream().forEach(g -> {
247 // check if request was canceled.
248 monitor.isCanceled();
249
250 Position pos= new Position(g.getKey().offset, g.getKey().length);
251 List<ICodeMining> minings= g.getValue();
252 boolean inLineHeader= minings.size() > 0 ? (minings.get(0) instanceof LineHeaderCodeMining) : true;
253 // Try to find existing annotation
254 AbstractInlinedAnnotation ann= fInlinedAnnotationSupport.findExistingAnnotation(pos);
255 if (ann == null) {
256 // The annotation doesn't exists, create it.
257 ann= inLineHeader ? new CodeMiningLineHeaderAnnotation(pos, viewer) : new CodeMiningLineContentAnnotation(pos, viewer);
258 } else if (ann instanceof ICodeMiningAnnotation && ((ICodeMiningAnnotation) ann).isInVisibleLines()) {
259 // annotation is in visible lines
260 annotationsToRedraw.add((ICodeMiningAnnotation) ann);
261 }
262 ((ICodeMiningAnnotation) ann).update(minings, monitor);
263 currentAnnotations.add(ann);
264 });
265 // check if request was canceled.
266 monitor.isCanceled();
267 fInlinedAnnotationSupport.updateAnnotations(currentAnnotations);
268 // redraw the existing codemining annotations since their content can change
269 annotationsToRedraw.stream().forEach(ann -> ann.redraw());
270 }
271
272 /**
273 * Returns <code>true</code> if the given mining has a non empty label and <code>false</code>
274 * otherwise.
275 *
276 * @param mining the mining to check
277 * @return <code>true</code> if the given mining has a non empty label and <code>false</code>
278 * otherwise.
279 */
280 static boolean isValidMining(ICodeMining mining) {
281 return mining != null && mining.getLabel() != null && !mining.getLabel().isEmpty();
282 }
283
284 /**
285 * Returns the valid code mining at the given location by using the bounds of codemining
286 * annotations which stores only the valid code mining.
287 *
288 * @param minings the list of mining of the codemining annotation.
289 * @param bounds the bounds of the valid minings of the codemining annotation.
290 * @param x the x location
291 * @param y the y location
292 * @return the valid code mining at the given location by using the bounds of codemining
293 * annotations which stores only the valid code mining.
294 */
295 static ICodeMining getValidCodeMiningAtLocation(ICodeMining[] minings, List<Rectangle> bounds, int x, int y) {
296 for (int i= 0; i < bounds.size(); i++) {
297 Rectangle bound= bounds.get(i);
298 if (bound.contains(x, y)) {
299 return getCodeValidMiningAtIndex(minings, i);
300 }
301 }
302 return null;
303 }
304
305 /**
306 * Returns the valid code mining at the given index.
307 *
308 * @param minings the list of minings
309 * @param index the index
310 * @return the valid code mining at the given index.
311 */
312 private static ICodeMining getCodeValidMiningAtIndex(ICodeMining[] minings, int index) {
313 int validIndex= 0;
314 for (ICodeMining mining : minings) {
315 if (isValidMining(mining)) {
316 if (validIndex == index) {
317 return mining;
318 }
319 validIndex++;
320 }
321 }
322 return null;
323 }
324 }
4949 /**
5050 * @see Reader#ready()
5151 */
52 @Override
52 @Override
5353 public boolean ready() throws IOException {
5454 return true;
5555 }
130130 /**
131131 * @see Reader#ready()
132132 */
133 @Override
133 @Override
134134 public boolean ready() throws IOException {
135135 return fReader.ready();
136136 }
15401540 * @since 3.4
15411541 */
15421542 boolean isColoredLabelsSupportEnabled() {
1543 return fIsColoredLabelsSupportEnabled;
1543 return fIsColoredLabelsSupportEnabled;
15441544 }
15451545
15461546 /**
563563
564564 } else if (key == SWT.ESC) {
565565 e.doit= false;
566 hideContextInfoPopup();
566 hideContextInfoPopup();
567567 } else {
568568 validateContextInformation();
569569 }
2929 super();
3030 }
3131
32 /**
32 /**
3333 * Constructs an <code>LineIndexOutOfBoundsException</code> with the specified detail message.
3434 *
3535 * @param s the detail message.
284284 updateFocusRevision(null); // kill any focus as the ctx menu is going to show
285285 if (e.button == 1) {
286286 fMouseDownRegion= fFocusRange;
287 postRedraw();
287 postRedraw();
288288 }
289289 }
290290
350350 @Override
351351 protected IInformationControl doCreateInformationControl(Shell parent) {
352352 if (BrowserInformationControl.isAvailable(parent)) {
353 return new BrowserInformationControl(parent, JFaceResources.DIALOG_FONT, fIsFocusable) {
354 /**
353 return new BrowserInformationControl(parent, JFaceResources.DIALOG_FONT, fIsFocusable) {
354 /**
355355 * {@inheritDoc}
356356 *
357357 * @deprecated use {@link #setInput(Object)}
358358 */
359 @Deprecated
359 @Deprecated
360360 @Override
361361 public void setInformation(String content) {
362 content= addCSSToHTMLFragment(content);
363 super.setInformation(content);
364 }
365
366 /**
367 * Adds a HTML header and CSS info if <code>html</code> is only an HTML fragment (has no
368 * &lt;html&gt; section).
369 *
370 * @param html the html / text produced by a revision
371 * @return modified html
372 */
373 private String addCSSToHTMLFragment(String html) {
374 int max= Math.min(100, html.length());
375 if (html.substring(0, max).indexOf("<html>") != -1) //$NON-NLS-1$
376 // there is already a header
377 return html;
378
379 StringBuilder info= new StringBuilder(512 + html.length());
380 HTMLPrinter.insertPageProlog(info, 0, fgStyleSheet);
381 info.append(html);
382 HTMLPrinter.addPageEpilog(info);
383 return info.toString();
384 }
385
386 };
387 }
362 content= addCSSToHTMLFragment(content);
363 super.setInformation(content);
364 }
365
366 /**
367 * Adds a HTML header and CSS info if <code>html</code> is only an HTML fragment (has no
368 * &lt;html&gt; section).
369 *
370 * @param html the html / text produced by a revision
371 * @return modified html
372 */
373 private String addCSSToHTMLFragment(String html) {
374 int max= Math.min(100, html.length());
375 if (html.substring(0, max).indexOf("<html>") != -1) //$NON-NLS-1$
376 // there is already a header
377 return html;
378
379 StringBuilder info= new StringBuilder(512 + html.length());
380 HTMLPrinter.insertPageProlog(info, 0, fgStyleSheet);
381 info.append(html);
382 HTMLPrinter.addPageEpilog(info);
383 return info.toString();
384 }
385
386 };
387 }
388388 return new DefaultInformationControl(parent, fIsFocusable);
389389 }
390390
472472 return range == null ? null : new LineRange(lineNumber, 1);
473473 }
474474
475 @Override
475 @Override
476476 public IInformationControlCreator getInformationPresenterControlCreator() {
477477 RevisionInformation revisionInfo= fRevisionInfo;
478478 if (revisionInfo != null) {
481481 return creator;
482482 }
483483 return new HoverInformationControlCreator(true);
484 }
484 }
485485 }
486486
487487 /* Listeners and helpers. */
11551155 /**
11561156 * Handles the selection of a revision id and informs listeners
11571157 *
1158 * @param id the selected revision id
1159 */
1158 * @param id the selected revision id
1159 */
11601160 void handleRevisionSelected(String id) {
11611161 Assert.isLegal(id != null);
11621162 if (fRevisionInfo == null)
11731173 handleRevisionSelected((Revision) null);
11741174 }
11751175
1176 /**
1177 * Returns the selection provider.
1178 *
1179 * @return the selection provider
1180 */
1181 public RevisionSelectionProvider getRevisionSelectionProvider() {
1176 /**
1177 * Returns the selection provider.
1178 *
1179 * @return the selection provider
1180 */
1181 public RevisionSelectionProvider getRevisionSelectionProvider() {
11821182 return fRevisionSelectionProvider;
1183 }
1183 }
11841184
11851185 /**
11861186 * Updates the focus line with a new line.
12311231 }
12321232
12331233 private void updateFocusRevision(Revision revision) {
1234 if (fFocusRevision != revision)
1234 if (fFocusRevision != revision)
12351235 onFocusRevisionChanged(fFocusRevision, revision);
1236 }
1236 }
12371237
12381238 /**
12391239 * Handles a changing focus revision.
14221422 * @param offset the document offset
14231423 * @return the revision at offset, or <code>null</code> for none
14241424 */
1425 Revision getRevision(int offset) {
1426 IDocument document= fViewer.getDocument();
1427 int line;
1428 try {
1429 line= document.getLineOfOffset(offset);
1430 } catch (BadLocationException x) {
1431 return null;
1432 }
1433 if (line != -1) {
1434 RevisionRange range= getRange(line);
1435 if (range != null)
1436 return range.getRevision();
1437 }
1438 return null;
1439 }
1425 Revision getRevision(int offset) {
1426 IDocument document= fViewer.getDocument();
1427 int line;
1428 try {
1429 line= document.getLineOfOffset(offset);
1430 } catch (BadLocationException x) {
1431 return null;
1432 }
1433 if (line != -1) {
1434 RevisionRange range= getRange(line);
1435 if (range != null)
1436 return range.getRevision();
1437 }
1438 return null;
1439 }
14401440
14411441 /**
14421442 * Returns <code>true</code> if a revision model has been set, <code>false</code> otherwise.
14431443 *
1444 * @return <code>true</code> if a revision model has been set, <code>false</code> otherwise
1445 */
1446 public boolean hasInformation() {
1447 return fRevisionInfo != null;
1448 }
1444 * @return <code>true</code> if a revision model has been set, <code>false</code> otherwise
1445 */
1446 public boolean hasInformation() {
1447 return fRevisionInfo != null;
1448 }
14491449
14501450 /**
14511451 * Returns the width in chars required to display information.
4545 * Post selection listener on the viewer that remembers the selection provider it is registered
4646 * with.
4747 */
48 private final class PostSelectionListener implements ISelectionChangedListener {
49 private final IPostSelectionProvider fPostProvider;
48 private final class PostSelectionListener implements ISelectionChangedListener {
49 private final IPostSelectionProvider fPostProvider;
5050
5151 public PostSelectionListener(IPostSelectionProvider postProvider) {
5252 postProvider.addPostSelectionChangedListener(this);
5353 fPostProvider= postProvider;
54 }
54 }
5555
5656 @Override
5757 public void selectionChanged(SelectionChangedEvent event) {
58 ISelection selection= event.getSelection();
59 if (selection instanceof ITextSelection) {
60 ITextSelection ts= (ITextSelection) selection;
61 int offset= ts.getOffset();
62 setSelectedRevision(fPainter.getRevision(offset));
63 }
58 ISelection selection= event.getSelection();
59 if (selection instanceof ITextSelection) {
60 ITextSelection ts= (ITextSelection) selection;
61 int offset= ts.getOffset();
62 setSelectedRevision(fPainter.getRevision(offset));
63 }
6464
65 }
65 }
6666
6767 public void dispose() {
6868 fPostProvider.removePostSelectionChangedListener(this);
6969 }
70 }
70 }
7171
7272 private final RevisionPainter fPainter;
7373
9797 *
9898 * @param painter the painter that the created provider interacts with
9999 */
100 RevisionSelectionProvider(RevisionPainter painter) {
100 RevisionSelectionProvider(RevisionPainter painter) {
101101 fPainter= painter;
102 }
102 }
103103
104 @Override
104 @Override
105105 public void addSelectionChangedListener(ISelectionChangedListener listener) {
106 fListeners.add(listener);
107 }
106 fListeners.add(listener);
107 }
108108
109 @Override
109 @Override
110110 public void removeSelectionChangedListener(ISelectionChangedListener listener) {
111 fListeners.remove(listener);
112 }
111 fListeners.remove(listener);
112 }
113113
114 @Override
114 @Override
115115 public ISelection getSelection() {
116 if (fSelection == null)
117 return StructuredSelection.EMPTY;
118 return new StructuredSelection(fSelection);
119 }
116 if (fSelection == null)
117 return StructuredSelection.EMPTY;
118 return new StructuredSelection(fSelection);
119 }
120120
121 @Override
121 @Override
122122 public void setSelection(ISelection selection) {
123 if (fIgnoreEvents)
124 return;
125 if (selection instanceof IStructuredSelection) {
126 Object first= ((IStructuredSelection) selection).getFirstElement();
127 if (first instanceof Revision)
123 if (fIgnoreEvents)
124 return;
125 if (selection instanceof IStructuredSelection) {
126 Object first= ((IStructuredSelection) selection).getFirstElement();
127 if (first instanceof Revision)
128128 fPainter.handleRevisionSelected((Revision) first);
129129 else if (first instanceof String)
130130 fPainter.handleRevisionSelected((String) first);
131131 else if (selection.isEmpty())
132132 fPainter.handleRevisionSelected((Revision) null);
133 }
134 }
133 }
134 }
135135
136 /**
136 /**
137137 * Installs the selection provider on the viewer.
138138 *
139139 * @param viewer the viewer on which we listen to for post selection events
140140 */
141 void install(ITextViewer viewer) {
142 uninstall();
141 void install(ITextViewer viewer) {
142 uninstall();
143143 fViewer= viewer;
144144 if (fViewer != null) {
145145 ISelectionProvider provider= fViewer.getSelectionProvider();
146146 if (provider instanceof IPostSelectionProvider) {
147 IPostSelectionProvider postProvider= (IPostSelectionProvider) provider;
148 fSelectionListener= new PostSelectionListener(postProvider);
149 }
147 IPostSelectionProvider postProvider= (IPostSelectionProvider) provider;
148 fSelectionListener= new PostSelectionListener(postProvider);
149 }
150150 }
151 }
151 }
152152
153 /**
154 * Uninstalls the selection provider.
155 */
156 void uninstall() {
157 fViewer= null;
158 if (fSelectionListener != null) {
159 fSelectionListener.dispose();
160 fSelectionListener= null;
161 }
162 }
153 /**
154 * Uninstalls the selection provider.
155 */
156 void uninstall() {
157 fViewer= null;
158 if (fSelectionListener != null) {
159 fSelectionListener.dispose();
160 fSelectionListener= null;
161 }
162 }
163163
164 /**
164 /**
165165 * Private protocol used by {@link RevisionPainter} to signal selection of a revision.
166166 *
167167 * @param revision the selected revision, or <code>null</code> for none
168168 */
169 void revisionSelected(Revision revision) {
170 setSelectedRevision(revision);
171 }
169 void revisionSelected(Revision revision) {
170 setSelectedRevision(revision);
171 }
172172
173173 /**
174174 * Updates the currently selected revision and sends out an event if it changed.
180180 fSelection= revision;
181181 fireSelectionEvent();
182182 }
183 }
183 }
184184
185 private void fireSelectionEvent() {
186 fIgnoreEvents= true;
187 try {
188 ISelection selection= getSelection();
189 SelectionChangedEvent event= new SelectionChangedEvent(this, selection);
185 private void fireSelectionEvent() {
186 fIgnoreEvents= true;
187 try {
188 ISelection selection= getSelection();
189 SelectionChangedEvent event= new SelectionChangedEvent(this, selection);
190190
191191 for (ISelectionChangedListener listener : fListeners) {
192192 listener.selectionChanged(event);
193193 }
194 } finally {
195 fIgnoreEvents= false;
196 }
197 }
194 } finally {
195 fIgnoreEvents= false;
196 }
197 }
198198 }
525525 /**
526526 * Returns <code>true</code> if diff information is being displayed, <code>false</code> otherwise.
527527 *
528 * @return <code>true</code> if diff information is being displayed, <code>false</code> otherwise
529 * @since 3.3
530 */
528 * @return <code>true</code> if diff information is being displayed, <code>false</code> otherwise
529 * @since 3.3
530 */
531531 public boolean hasInformation() {
532532 if (fLineDiffer instanceof ILineDifferExtension2)
533533 return !((ILineDifferExtension2) fLineDiffer).isSuspended();
608608 private MouseTracker fMouseTracker= new MouseTracker();
609609 /**
610610 * The remembered hover event.
611 * @since 3.0
611 * @since 3.0
612612 */
613613 private MouseEvent fHoverEvent= null;
614614 /** The remembered hover event state mask of the keyboard modifiers */
844844 fReplacingDelayJob= new Job("AbstractHoverInformationControlManager Replace Delayer") { //$NON-NLS-1$
845845 @Override
846846 public IStatus run(final IProgressMonitor monitor) {
847 if (monitor.isCanceled() || display.isDisposed()) {
847 if (monitor.isCanceled() || display.isDisposed()) {
848848 return Status.CANCEL_STATUS;
849849 }
850850 display.syncExec(() -> {
938938 return fHoverEvent;
939939 }
940940
941 /**
941 /**
942942 * Returns the SWT event state of the most recent mouse hover event.
943943 *
944944 * @return the SWT event state of the most recent mouse hover event
945945 */
946946 protected int getHoverEventStateMask() {
947947 return fHoverEventStateMask;
948 }
948 }
949949
950950 /**
951951 * Returns an adapter that gives access to internal methods.
351351 return;
352352
353353 try {
354 IDocument document= fEvent.getDocument();
355 if (document == null)
356 return;
354 IDocument document= fEvent.getDocument();
355 if (document == null)
356 return;
357357
358358 TextChangingEvent event= new TextChangingEvent(this);
359359 event.start= fEvent.fOffset;
120120 /**
121121 * Additional styles to use for the text control.
122122 * @since 3.4, previously called <code>fTextStyle</code>
123 */
123 */
124124 private final int fAdditionalTextStyles;
125125
126126 /**
7474
7575 @Override
7676 public char last() {
77 fIndex= fOffset < fEndOffset ? fEndOffset -1 : fEndOffset;
78 return current();
77 fIndex= fOffset < fEndOffset ? fEndOffset -1 : fEndOffset;
78 return current();
7979 }
8080
8181 @Override
103103 * @since 3.1
104104 */
105105 TextCommand(IUndoContext context) {
106 super(JFaceTextMessages.getString("DefaultUndoManager.operationLabel")); //$NON-NLS-1$
107 addContext(context);
106 super(JFaceTextMessages.getString("DefaultUndoManager.operationLabel")); //$NON-NLS-1$
107 addContext(context);
108108 }
109109
110110 /**
132132
133133 @Override
134134 public void dispose() {
135 reinitialize();
135 reinitialize();
136136 }
137137
138138 /**
222222
223223 @Override
224224 public boolean canExecute() {
225 return isConnected();
225 return isConnected();
226226 }
227227
228228 @Override
229229 public IStatus execute(IProgressMonitor monitor, IAdaptable uiInfo) {
230230 // Text commands execute as they are typed, so executing one has no effect.
231 return Status.OK_STATUS;
231 return Status.OK_STATUS;
232232 }
233233
234234 /*
323323 } else {
324324 reinitialize();
325325 }
326 } else {
326 } else {
327327 updateCommand();
328328 fCurrent= createCurrent();
329329 }
367367 * @since 3.1
368368 */
369369 protected boolean isValid() {
370 return fStart > -1 &&
371 fEnd > -1 &&
372 fText != null;
370 return fStart > -1 &&
371 fEnd > -1 &&
372 fText != null;
373373 }
374374
375375 @Override
376376 public String toString() {
377377 String delimiter= ", "; //$NON-NLS-1$
378 StringBuilder text= new StringBuilder(super.toString());
378 StringBuilder text= new StringBuilder(super.toString());
379379 text.append("\n"); //$NON-NLS-1$
380380 text.append(this.getClass().getName());
381381 text.append(" undo modification stamp: "); //$NON-NLS-1$
385385 text.append(" start: "); //$NON-NLS-1$
386386 text.append(fStart);
387387 text.append(delimiter);
388 text.append("end: "); //$NON-NLS-1$
389 text.append(fEnd);
388 text.append("end: "); //$NON-NLS-1$
389 text.append(fEnd);
390390 text.append(delimiter);
391 text.append("text: '"); //$NON-NLS-1$
391 text.append("text: '"); //$NON-NLS-1$
392392 text.append(fText);
393 text.append('\'');
393 text.append('\'');
394394 text.append(delimiter);
395 text.append("preservedText: '"); //$NON-NLS-1$
395 text.append("preservedText: '"); //$NON-NLS-1$
396396 text.append(fPreservedText);
397 text.append('\'');
398 return text.toString();
397 text.append('\'');
398 return text.toString();
399399 }
400400
401401 /**
435435 * @since 3.1
436436 */
437437 CompoundTextCommand(IUndoContext context) {
438 super(context);
438 super(context);
439439 }
440440
441441 /**
544544 protected boolean isValid() {
545545 if (isConnected())
546546 return (fStart > -1 || fCommands.size() > 0);
547 return false;
547 return false;
548548 }
549549
550550 /**
826826 * @param undoLevel the length of this manager's history
827827 */
828828 public DefaultUndoManager(int undoLevel) {
829 fHistory= OperationHistoryFactory.getOperationHistory();
829 fHistory= OperationHistoryFactory.getOperationHistory();
830830 setMaximalUndoLevel(undoLevel);
831831 }
832832
908908 */
909909 private void addToCommandStack(TextCommand command){
910910 if (!fFoldingIntoCompoundChange || command instanceof CompoundTextCommand) {
911 fHistory.add(command);
912 fLastAddedCommand= command;
911 fHistory.add(command);
912 fLastAddedCommand= command;
913913 }
914914 }
915915
919919 * @since 3.1
920920 */
921921 private void disposeCommandStack() {
922 fHistory.dispose(fUndoContext, true, true, true);
922 fHistory.dispose(fUndoContext, true, true, true);
923923 }
924924
925925 /**
928928 * @since 3.1
929929 */
930930 private void initializeCommandStack() {
931 if (fHistory != null && fUndoContext != null)
931 if (fHistory != null && fUndoContext != null)
932932 fHistory.dispose(fUndoContext, true, true, false);
933933
934934 }
11921192 fTextViewer= textViewer;
11931193 fTextBuffer= new StringBuilder();
11941194 fPreservedTextBuffer= new StringBuilder();
1195 if (fUndoContext == null)
1196 fUndoContext= new ObjectUndoContext(this);
1197
1198 fHistory.setLimit(fUndoContext, fUndoLevel);
1195 if (fUndoContext == null)
1196 fUndoContext= new ObjectUndoContext(this);
1197
1198 fHistory.setLimit(fUndoContext, fUndoLevel);
11991199
12001200 initializeCommandStack();
12011201
12391239
12401240 @Override
12411241 public boolean redoable() {
1242 return fHistory.canRedo(fUndoContext);
1242 return fHistory.canRedo(fUndoContext);
12431243 }
12441244
12451245 @Override
12461246 public boolean undoable() {
1247 return fHistory.canUndo(fUndoContext);
1247 return fHistory.canUndo(fUndoContext);
12481248 }
12491249
12501250 @Override
7070 public DocumentClone(String content, String[] lineDelimiters) {
7171 super();
7272 setTextStore(new StringTextStore(content));
73 ConfigurableLineTracker tracker= new ConfigurableLineTracker(lineDelimiters);
73
74 boolean hasDefaultDelims= lineDelimiters == null;
75 if (!hasDefaultDelims && DefaultLineTracker.DELIMITERS.length == lineDelimiters.length) {
76 hasDefaultDelims= true;
77 for (int i= 0; i < lineDelimiters.length; i++) {
78 if (DefaultLineTracker.DELIMITERS[i] != lineDelimiters[i]) {
79 hasDefaultDelims= false;
80 break;
81 }
82 }
83 }
84
85 ILineTracker tracker= hasDefaultDelims ? new DefaultLineTracker() : new ConfigurableLineTracker(lineDelimiters);
7486 setLineTracker(tracker);
7587 getTracker().set(content);
7688 completeInitialization();
5454 */
5555 boolean canPerformFind();
5656
57 /**
58 * Searches for a string starting at the given widget offset and using the specified search
59 * directives. If a string has been found it is selected and its start offset is
60 * returned.
61 * <p>
62 * Replaced by {@link IFindReplaceTargetExtension3#findAndSelect(int, String, boolean, boolean, boolean, boolean)}.
63 *
64 * @param widgetOffset the widget offset at which searching starts
65 * @param findString the string which should be found
66 * @param searchForward <code>true</code> searches forward, <code>false</code> backwards
67 * @param caseSensitive <code>true</code> performs a case sensitive search, <code>false</code> an insensitive search
68 * @param wholeWord if <code>true</code> only occurrences are reported in which the findString stands as a word by itself
69 * @return the position of the specified string, or -1 if the string has not been found
57 /**
58 * Searches for a string starting at the given widget offset and using the specified search
59 * directives. If a string has been found it is selected and its start offset is
60 * returned.
61 * <p>
62 * Replaced by {@link IFindReplaceTargetExtension3#findAndSelect(int, String, boolean, boolean, boolean, boolean)}.
63 *
64 * @param widgetOffset the widget offset at which searching starts
65 * @param findString the string which should be found
66 * @param searchForward <code>true</code> searches forward, <code>false</code> backwards
67 * @param caseSensitive <code>true</code> performs a case sensitive search, <code>false</code> an insensitive search
68 * @param wholeWord if <code>true</code> only occurrences are reported in which the findString stands as a word by itself
69 * @return the position of the specified string, or -1 if the string has not been found
7070 */
7171 int findAndSelect(int widgetOffset, String findString, boolean searchForward, boolean caseSensitive, boolean wholeWord);
7272
193193 * behavior over the course of time, this method causes them to be set
194194 * back to their initial state and behavior. E.g., if an {@link IUndoManager}
195195 * has been installed on this text viewer, the manager's list of remembered
196 * text editing operations is removed.
196 * text editing operations is removed.
197197 */
198198 void resetPlugins();
199199
4646 */
4747 public interface ITextViewerExtension2 {
4848
49 /**
50 * The state mask of the default hover (value <code>0xff</code>).
51 */
49 /**
50 * The state mask of the default hover (value <code>0xff</code>).
51 */
5252 final int DEFAULT_HOVER_STATE_MASK= 0xff;
5353
5454 /**
22152215 return true;
22162216 }
22172217
2218 } else {
2219 fWidgetTokenKeeper= requester;
2220 return true;
2221 }
2222 }
2223 return false;
2224 }
2218 } else {
2219 fWidgetTokenKeeper= requester;
2220 return true;
2221 }
2222 }
2223 return false;
2224 }
22252225
22262226 @Override
22272227 public void releaseWidgetToken(IWidgetTokenKeeper tokenKeeper) {
28422842 * @return <code>true</code> if the slave has been adapted successfully
28432843 * @throws BadLocationException in case the specified range is not valid in the master document
28442844 * @since 2.1
2845 * @deprecated use <code>updateSlaveDocument</code> instead
2845 * @deprecated use <code>updateSlaveDocument</code> instead
28462846 */
28472847 @Deprecated
28482848 protected boolean updateVisibleDocument(IDocument visibleDocument, int visibleRegionOffset, int visibleRegionLength) throws BadLocationException {
44114411 options.printTextFontStyle= true;
44124412 options.printTextForeground= true;
44134413 print(options);
4414 }
4414 }
44154415
44164416 //------ find support
44174417
0 /**
1 * Copyright (c) 2017 Angelo ZERR.
0 /**
1 * Copyright (c) 2017 Angelo ZERR.
22 *
3 * This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License 2.0
5 * which accompanies this distribution, and is available at
3 * This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License 2.0
5 * which accompanies this distribution, and is available at
66 * https://www.eclipse.org/legal/epl-2.0/
77 *
8 * SPDX-License-Identifier: EPL-2.0
9 *
10 * Contributors:
11 * Angelo Zerr <angelo.zerr@gmail.com> - [CodeMining] Provide CodeMining support with CodeMiningManager - Bug 527720
12 */
13 package org.eclipse.jface.text.codemining;
14
15 import java.util.concurrent.CompletableFuture;
16 import java.util.function.Consumer;
17
18 import org.eclipse.swt.custom.StyledText;
19 import org.eclipse.swt.events.MouseEvent;
20 import org.eclipse.swt.graphics.Color;
21 import org.eclipse.swt.graphics.GC;
22 import org.eclipse.swt.graphics.Point;
23
24 import org.eclipse.core.runtime.IProgressMonitor;
25
26 import org.eclipse.jface.text.ITextViewer;
27 import org.eclipse.jface.text.Position;
28
29 /**
30 * Abstract class for {@link ICodeMining}.
31 *
32 * @since 3.13
33 */
34 public abstract class AbstractCodeMining implements ICodeMining {
35
36 /**
37 * The position where codemining must be drawn
38 */
39 private final Position position;
40
41 /**
42 * The owner codemining provider which creates this mining.
43 */
44 private final ICodeMiningProvider provider;
45
46 /**
47 * The future used to resolve mining.
48 */
49 private CompletableFuture<Void> resolveFuture;
50
51 /**
52 * The label of the resolved codemining.
53 */
54 private String label;
55
56 /**
57 * The action to execute when mining is clicked and null otherwise.
58 */
59 private final Consumer<MouseEvent> action;
60
61 /**
62 * CodeMining constructor to locate the code mining in a given position.
63 *
64 * @param position the position where the mining must be drawn.
65 * @param provider the owner codemining provider which creates this mining.
66 * @param action the action to execute when mining is clicked and null otherwise.
67 */
68 protected AbstractCodeMining(Position position, ICodeMiningProvider provider, Consumer<MouseEvent> action) {
69 this.position= position;
70 this.provider= provider;
71 this.action= action;
72 }
73
74 @Override
75 public Position getPosition() {
76 return position;
77 }
78
79 @Override
80 public ICodeMiningProvider getProvider() {
81 return provider;
82 }
83
84 @Override
85 public String getLabel() {
86 return label;
87 }
88
89 /**
90 * Set the label mining.
91 *
92 * @param label the label mining.
93 */
94 public void setLabel(String label) {
95 this.label= label;
96 }
97
98 @Override
99 public final CompletableFuture<Void> resolve(ITextViewer viewer, IProgressMonitor monitor) {
100 if (resolveFuture == null) {
101 resolveFuture= doResolve(viewer, monitor);
102 }
103 return resolveFuture;
104 }
105
106 /**
107 * Returns the future which resolved the content of mining and null otherwise. By default, the
108 * resolve do nothing.
109 *
110 * @param viewer the viewer
111 * @param monitor the monitor
112 * @return the future which resolved the content of mining and null otherwise.
113 */
114 protected CompletableFuture<Void> doResolve(ITextViewer viewer, IProgressMonitor monitor) {
115 return CompletableFuture.completedFuture(null);
116 }
117
118 @Override
119 public boolean isResolved() {
120 return (resolveFuture != null && resolveFuture.isDone());
121 }
122
123 @Override
124 public void dispose() {
125 if (resolveFuture != null) {
126 resolveFuture.cancel(true);
127 resolveFuture= null;
128 }
129 }
130
131 /**
132 * Draw the {@link #getLabel()} of mining with gray color. User can override this method to draw
133 * anything.
134 *
135 * @param gc the graphics context
136 * @param textWidget the text widget to draw on
137 * @param color the color of the line
138 * @param x the x position of the annotation
139 * @param y the y position of the annotation
140 * @return the size of the draw of mining.
141 */
142 @Override
143 public Point draw(GC gc, StyledText textWidget, Color color, int x, int y) {
144 String title= getLabel() != null ? getLabel() : "no command"; //$NON-NLS-1$
145 gc.drawString(title, x, y, true);
146 return gc.stringExtent(title);
147 }
148
149 @Override
150 public Consumer<MouseEvent> getAction() {
151 return action;
152 }
153 }
8 * SPDX-License-Identifier: EPL-2.0
9 *
10 * Contributors:
11 * Angelo Zerr <angelo.zerr@gmail.com> - [CodeMining] Provide CodeMining support with CodeMiningManager - Bug 527720
12 */
13 package org.eclipse.jface.text.codemining;
14
15 import java.util.concurrent.CompletableFuture;
16 import java.util.function.Consumer;
17
18 import org.eclipse.swt.custom.StyledText;
19 import org.eclipse.swt.events.MouseEvent;
20 import org.eclipse.swt.graphics.Color;
21 import org.eclipse.swt.graphics.GC;
22 import org.eclipse.swt.graphics.Point;
23
24 import org.eclipse.core.runtime.IProgressMonitor;
25
26 import org.eclipse.jface.text.ITextViewer;
27 import org.eclipse.jface.text.Position;
28
29 /**
30 * Abstract class for {@link ICodeMining}.
31 *
32 * @since 3.13
33 */
34 public abstract class AbstractCodeMining implements ICodeMining {
35
36 /**
37 * The position where codemining must be drawn
38 */
39 private final Position position;
40
41 /**
42 * The owner codemining provider which creates this mining.
43 */
44 private final ICodeMiningProvider provider;
45
46 /**
47 * The future used to resolve mining.
48 */
49 private CompletableFuture<Void> resolveFuture;
50
51 /**
52 * The label of the resolved codemining.
53 */
54 private String label;
55
56 /**
57 * The action to execute when mining is clicked and null otherwise.
58 */
59 private final Consumer<MouseEvent> action;
60
61 /**
62 * CodeMining constructor to locate the code mining in a given position.
63 *
64 * @param position the position where the mining must be drawn.
65 * @param provider the owner codemining provider which creates this mining.
66 * @param action the action to execute when mining is clicked and null otherwise.
67 */
68 protected AbstractCodeMining(Position position, ICodeMiningProvider provider, Consumer<MouseEvent> action) {
69 this.position= position;
70 this.provider= provider;
71 this.action= action;
72 }
73
74 @Override
75 public Position getPosition() {
76 return position;
77 }
78
79 @Override
80 public ICodeMiningProvider getProvider() {
81 return provider;
82 }
83
84 @Override
85 public String getLabel() {
86 return label;
87 }
88
89 /**
90 * Set the label mining.
91 *
92 * @param label the label mining.
93 */
94 public void setLabel(String label) {
95 this.label= label;
96 }
97
98 @Override
99 public final CompletableFuture<Void> resolve(ITextViewer viewer, IProgressMonitor monitor) {
100 if (resolveFuture == null) {
101 resolveFuture= doResolve(viewer, monitor);
102 }
103 return resolveFuture;
104 }
105
106 /**
107 * Returns the future which resolved the content of mining and null otherwise. By default, the
108 * resolve do nothing.
109 *
110 * @param viewer the viewer
111 * @param monitor the monitor
112 * @return the future which resolved the content of mining and null otherwise.
113 */
114 protected CompletableFuture<Void> doResolve(ITextViewer viewer, IProgressMonitor monitor) {
115 return CompletableFuture.completedFuture(null);
116 }
117
118 @Override
119 public boolean isResolved() {
120 return (resolveFuture != null && resolveFuture.isDone());
121 }
122
123 @Override
124 public void dispose() {
125 if (resolveFuture != null) {
126 resolveFuture.cancel(true);
127 resolveFuture= null;
128 }
129 }
130
131 /**
132 * Draw the {@link #getLabel()} of mining with gray color. User can override this method to draw
133 * anything.
134 *
135 * @param gc the graphics context
136 * @param textWidget the text widget to draw on
137 * @param color the color of the line
138 * @param x the x position of the annotation
139 * @param y the y position of the annotation
140 * @return the size of the draw of mining.
141 */
142 @Override
143 public Point draw(GC gc, StyledText textWidget, Color color, int x, int y) {
144 String title= getLabel() != null ? getLabel() : "no command"; //$NON-NLS-1$
145 gc.drawString(title, x, y, true);
146 return gc.stringExtent(title);
147 }
148
149 @Override
150 public Consumer<MouseEvent> getAction() {
151 return action;
152 }
153 }
0 /**
1 * Copyright (c) 2017 Angelo ZERR.
0 /**
1 * Copyright (c) 2017 Angelo ZERR.
22 *
3 * This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License 2.0
5 * which accompanies this distribution, and is available at
3 * This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License 2.0
5 * which accompanies this distribution, and is available at
66 * https://www.eclipse.org/legal/epl-2.0/
77 *
8 * SPDX-License-Identifier: EPL-2.0
9 *
10 * Contributors:
11 * Angelo Zerr <angelo.zerr@gmail.com> - [CodeMining] Provide CodeMining support with CodeMiningManager - Bug 527720
12 */
13 package org.eclipse.jface.text.codemining;
14
15 import org.eclipse.core.runtime.Assert;
16 import org.eclipse.core.runtime.IAdaptable;
17
18 /**
19 * A codemining provider that can provide adapters through a context that can be set by the creator
20 * of this codemining provider.
21 * <p>
22 * Clients may subclass.
23 * </p>
24 *
25 * @since 3.13
26 */
27 public abstract class AbstractCodeMiningProvider implements ICodeMiningProvider {
28
29 /**
30 * The context of this codemining provider.
31 */
32 private IAdaptable context;
33
34 /**
35 * Sets this codemining provider's context which is responsible to provide the adapters.
36 *
37 * @param context the context for this codemining provider
38 * @throws IllegalArgumentException if the context is <code>null</code>
39 * @throws IllegalStateException if this method is called more than once
40 */
41 public final void setContext(IAdaptable context) throws IllegalStateException, IllegalArgumentException {
42 Assert.isLegal(context != null);
43 if (this.context != null)
44 throw new IllegalStateException();
45 this.context= context;
46 }
47
48 @Override
49 public void dispose() {
50 context= null;
51 }
52
53 /**
54 * Returns an object which is an instance of the given class and provides additional context for
55 * this codemining provider.
56 *
57 * @param adapterClass the adapter class to look up
58 * @return an instance that can be cast to the given class, or <code>null</code> if this object
59 * does not have an adapter for the given class
60 */
61 protected final <T> T getAdapter(Class<T> adapterClass) {
62 Assert.isLegal(adapterClass != null);
63 if (context != null)
64 return context.getAdapter(adapterClass);
65 return null;
66 }
67 }
8 * SPDX-License-Identifier: EPL-2.0
9 *
10 * Contributors:
11 * Angelo Zerr <angelo.zerr@gmail.com> - [CodeMining] Provide CodeMining support with CodeMiningManager - Bug 527720
12 */
13 package org.eclipse.jface.text.codemining;
14
15 import org.eclipse.core.runtime.Assert;
16 import org.eclipse.core.runtime.IAdaptable;
17
18 /**
19 * A codemining provider that can provide adapters through a context that can be set by the creator
20 * of this codemining provider.
21 * <p>
22 * Clients may subclass.
23 * </p>
24 *
25 * @since 3.13
26 */
27 public abstract class AbstractCodeMiningProvider implements ICodeMiningProvider {
28
29 /**
30 * The context of this codemining provider.
31 */
32 private IAdaptable context;
33
34 /**
35 * Sets this codemining provider's context which is responsible to provide the adapters.
36 *
37 * @param context the context for this codemining provider
38 * @throws IllegalArgumentException if the context is <code>null</code>
39 * @throws IllegalStateException if this method is called more than once
40 */
41 public final void setContext(IAdaptable context) throws IllegalStateException, IllegalArgumentException {
42 Assert.isLegal(context != null);
43 if (this.context != null)
44 throw new IllegalStateException();
45 this.context= context;
46 }
47
48 @Override
49 public void dispose() {
50 context= null;
51 }
52
53 /**
54 * Returns an object which is an instance of the given class and provides additional context for
55 * this codemining provider.
56 *
57 * @param adapterClass the adapter class to look up
58 * @return an instance that can be cast to the given class, or <code>null</code> if this object
59 * does not have an adapter for the given class
60 */
61 protected final <T> T getAdapter(Class<T> adapterClass) {
62 Assert.isLegal(adapterClass != null);
63 if (context != null)
64 return context.getAdapter(adapterClass);
65 return null;
66 }
67 }
0 /**
1 * Copyright (c) 2017 Angelo ZERR.
0 /**
1 * Copyright (c) 2017 Angelo ZERR.
22 *
3 * This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License 2.0
5 * which accompanies this distribution, and is available at
3 * This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License 2.0
5 * which accompanies this distribution, and is available at
66 * https://www.eclipse.org/legal/epl-2.0/
77 *
8 * SPDX-License-Identifier: EPL-2.0
9 *
10 * Contributors:
11 * Angelo Zerr <angelo.zerr@gmail.com> - [CodeMining] Provide extension point for CodeMining - Bug 528419
12 */
13 package org.eclipse.jface.text.codemining;
14
15 import org.eclipse.jface.text.IDocument;
16 import org.eclipse.jface.text.ITextViewer;
17 import org.eclipse.jface.text.reconciler.Reconciler;
18
19 /**
20 * A reconciler which update code minings.
21 *
22 * @since 3.13
23 */
24 public class CodeMiningReconciler extends Reconciler {
25
26 private CodeMiningStrategy fStrategy;
27
28 public CodeMiningReconciler() {
29 super.setIsIncrementalReconciler(false);
30 fStrategy= new CodeMiningStrategy();
31 this.setReconcilingStrategy(fStrategy, IDocument.DEFAULT_CONTENT_TYPE);
32 }
33
34 @Override
35 public void install(ITextViewer textViewer) {
36 super.install(textViewer);
37 fStrategy.install(textViewer);
38 }
39
40 @Override
41 public void uninstall() {
42 super.uninstall();
43 fStrategy.uninstall();
44 }
45
46 }
8 * SPDX-License-Identifier: EPL-2.0
9 *
10 * Contributors:
11 * Angelo Zerr <angelo.zerr@gmail.com> - [CodeMining] Provide extension point for CodeMining - Bug 528419
12 */
13 package org.eclipse.jface.text.codemining;
14
15 import org.eclipse.jface.text.IDocument;
16 import org.eclipse.jface.text.ITextViewer;
17 import org.eclipse.jface.text.reconciler.Reconciler;
18
19 /**
20 * A reconciler which update code minings.
21 *
22 * @since 3.13
23 */
24 public class CodeMiningReconciler extends Reconciler {
25
26 private CodeMiningStrategy fStrategy;
27
28 public CodeMiningReconciler() {
29 super.setIsIncrementalReconciler(false);
30 fStrategy= new CodeMiningStrategy();
31 this.setReconcilingStrategy(fStrategy, IDocument.DEFAULT_CONTENT_TYPE);
32 }
33
34 @Override
35 public void install(ITextViewer textViewer) {
36 super.install(textViewer);
37 fStrategy.install(textViewer);
38 }
39
40 @Override
41 public void uninstall() {
42 super.uninstall();
43 fStrategy.uninstall();
44 }
45
46 }
0 /**
1 * Copyright (c) 2017 Angelo ZERR.
0 /**
1 * Copyright (c) 2017 Angelo ZERR.
22 *
3 * This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License 2.0
5 * which accompanies this distribution, and is available at
3 * This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License 2.0
5 * which accompanies this distribution, and is available at
66 * https://www.eclipse.org/legal/epl-2.0/
77 *
8 * SPDX-License-Identifier: EPL-2.0
9 *
10 * Contributors:
11 * Angelo Zerr <angelo.zerr@gmail.com> - [CodeMining] Provide extension point for CodeMining - Bug 528419
12 */
13 package org.eclipse.jface.text.codemining;
14
15 import org.eclipse.core.runtime.IProgressMonitor;
16
17 import org.eclipse.jface.text.IDocument;
18 import org.eclipse.jface.text.IRegion;
19 import org.eclipse.jface.text.ITextViewer;
20 import org.eclipse.jface.text.reconciler.DirtyRegion;
21 import org.eclipse.jface.text.reconciler.IReconcilingStrategy;
22 import org.eclipse.jface.text.reconciler.IReconcilingStrategyExtension;
23 import org.eclipse.jface.text.source.ISourceViewerExtension5;
24
25 /**
26 * A reconciling strategy which updates code minings.
27 *
28 * @since 3.13
29 */
30 class CodeMiningStrategy implements IReconcilingStrategy, IReconcilingStrategyExtension {
31
32 private ISourceViewerExtension5 fViewer;
33
34 public void install(ITextViewer viewer) {
35 if (viewer instanceof ISourceViewerExtension5) {
36 fViewer= (ISourceViewerExtension5) viewer;
37 }
38 }
39
40 @Override
41 public void initialReconcile() {
42 // Do nothing
43 // Initial reconcilation will happen when the SourceViewer
44 // has initialized the code mining provider
45 // see SourceViewer#ensureCodeMiningManagerInstalled
46 }
47
48 @Override
49 public void reconcile(IRegion partition) {
50 if (fViewer != null) {
51 fViewer.updateCodeMinings();
52 }
53 }
54
55 public void uninstall() {
56 fViewer= null;
57 }
58
59 @Override
60 public void setProgressMonitor(IProgressMonitor monitor) {
61 // Do nothing
62 }
63
64 @Override
65 public void setDocument(IDocument document) {
66 // Do nothing
67 }
68
69 @Override
70 public void reconcile(DirtyRegion dirtyRegion, IRegion subRegion) {
71 // Do nothing
72 }
73
74 }
8 * SPDX-License-Identifier: EPL-2.0
9 *
10 * Contributors:
11 * Angelo Zerr <angelo.zerr@gmail.com> - [CodeMining] Provide extension point for CodeMining - Bug 528419
12 */
13 package org.eclipse.jface.text.codemining;
14
15 import org.eclipse.core.runtime.IProgressMonitor;
16
17 import org.eclipse.jface.text.IDocument;
18 import org.eclipse.jface.text.IRegion;
19 import org.eclipse.jface.text.ITextViewer;
20 import org.eclipse.jface.text.reconciler.DirtyRegion;
21 import org.eclipse.jface.text.reconciler.IReconcilingStrategy;
22 import org.eclipse.jface.text.reconciler.IReconcilingStrategyExtension;
23 import org.eclipse.jface.text.source.ISourceViewerExtension5;
24
25 /**
26 * A reconciling strategy which updates code minings.
27 *
28 * @since 3.13
29 */
30 class CodeMiningStrategy implements IReconcilingStrategy, IReconcilingStrategyExtension {
31
32 private ISourceViewerExtension5 fViewer;
33
34 public void install(ITextViewer viewer) {
35 if (viewer instanceof ISourceViewerExtension5) {
36 fViewer= (ISourceViewerExtension5) viewer;
37 }
38 }
39
40 @Override
41 public void initialReconcile() {
42 // Do nothing
43 // Initial reconcilation will happen when the SourceViewer
44 // has initialized the code mining provider
45 // see SourceViewer#ensureCodeMiningManagerInstalled
46 }
47
48 @Override
49 public void reconcile(IRegion partition) {
50 if (fViewer != null) {
51 fViewer.updateCodeMinings();
52 }
53 }
54
55 public void uninstall() {
56 fViewer= null;
57 }
58
59 @Override
60 public void setProgressMonitor(IProgressMonitor monitor) {
61 // Do nothing
62 }
63
64 @Override
65 public void setDocument(IDocument document) {
66 // Do nothing
67 }
68
69 @Override
70 public void reconcile(DirtyRegion dirtyRegion, IRegion subRegion) {
71 // Do nothing
72 }
73
74 }
0 /**
1 * Copyright (c) 2017 Angelo ZERR.
0 /**
1 * Copyright (c) 2017 Angelo ZERR.
22 *
3 * This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License 2.0
5 * which accompanies this distribution, and is available at
3 * This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License 2.0
5 * which accompanies this distribution, and is available at
66 * https://www.eclipse.org/legal/epl-2.0/
77 *
8 * SPDX-License-Identifier: EPL-2.0
9 *
10 * Contributors:
11 * Angelo Zerr <angelo.zerr@gmail.com> - [CodeMining] Provide CodeMining support with CodeMiningManager - Bug 527720
12 */
13 package org.eclipse.jface.text.codemining;
14
15 import java.util.concurrent.CompletableFuture;
16 import java.util.function.Consumer;
17
18 import org.eclipse.swt.custom.StyledText;
19 import org.eclipse.swt.events.MouseEvent;
20 import org.eclipse.swt.graphics.Color;
21 import org.eclipse.swt.graphics.GC;
22 import org.eclipse.swt.graphics.Point;
23
24 import org.eclipse.core.runtime.IProgressMonitor;
25
26 import org.eclipse.jface.text.ITextViewer;
27 import org.eclipse.jface.text.Position;
28
29 /**
30 * A code mining represents a content (ex: label, icons) that should be shown along with source
31 * text, like the number of references, a way to run tests (with run/debug icons), etc.
32 *
33 * A code mining is unresolved when no content (ex: label, icons) is associated to it. For
34 * performance reasons the creation of a code mining and resolving should be done to two stages.
35 *
36 * @since 3.13
37 */
38 public interface ICodeMining {
39
40 /**
41 * Returns the line position where code mining must be displayed in the line spacing area.
42 *
43 * @return the line position where code mining must be displayed in the line spacing area.
44 */
45 Position getPosition();
46
47 /**
48 * Returns the owner provider which has created this mining.
49 *
50 * @return the owner provider which has created this mining.
51 */
52 ICodeMiningProvider getProvider();
53
54 /**
55 * Returns the label may be set early in the class lifecycle, or upon completion of the future
56 * provided by {@link #resolve(ITextViewer, IProgressMonitor)} operation.
57 *
58 * <p>
59 * The returned label can have several values:
60 * <ul>
61 * <li><code>null</code> when mining is not resolved</li>
62 * <li><code>null</code> when mining is resolved means that mining was resolved with an error and it will not
63 * be displayed.</li>
64 * <li>empty when mining is resolved means that mining will not be displayed</li>
65 * <li>non empty when mining must be displayed</li>
66 * </ul>
67 * </p>
68 *
69 * @return the label may be set early in the class lifecycle, or upon completion of the future
70 * provided by {@link #resolve(ITextViewer, IProgressMonitor)} operation.
71 */
72 String getLabel();
73
74 /**
75 * Returns the future to resolve the content of mining, or
76 * {@link CompletableFuture#completedFuture(Object)} if no such resolution is necessary (in
77 * which case {#isResolved()} is expected to return <code>true</code>).
78 *
79 * @param viewer the viewer.
80 * @param monitor the monitor.
81 * @return the future to resolve the content of mining, or
82 * {@link CompletableFuture#completedFuture(Object)} if no such resolution is necessary
83 * (in which case {#isResolved()} is expected to return <code>true</code>).
84 */
85 CompletableFuture<Void> resolve(ITextViewer viewer, IProgressMonitor monitor);
86
87 /**
88 * Returns whether the content mining is resolved. If it is not resolved,
89 * {{@link #resolve(ITextViewer, IProgressMonitor)}} will be invoked later, triggering the
90 * future to resolve content.
91 *
92 * @return whether the content mining is resolved. If it is not resolved,
93 * {{@link #resolve(ITextViewer, IProgressMonitor)}} will be invoked later, triggering
94 * the future to resolve content.
95 */
96 boolean isResolved();
97
98 /**
99 * Draw the code mining.
100 *
101 * @param gc the graphics context
102 * @param textWidget the text widget to draw on
103 * @param color the color of the line
104 * @param x the x position of the annotation
105 * @param y the y position of the annotation
106 * @return the size of the draw of mining.
107 */
108 Point draw(GC gc, StyledText textWidget, Color color, int x, int y);
109
110 /**
111 * Returns the action to execute when mining is clicked and null otherwise.
112 *
113 * @return the action to execute when mining is clicked and null otherwise.
114 */
115 Consumer<MouseEvent> getAction();
116
117 /**
118 * Dispose the mining. Typically shuts down or cancels all related asynchronous operations.
119 */
120 void dispose();
121 }
8 * SPDX-License-Identifier: EPL-2.0
9 *
10 * Contributors:
11 * Angelo Zerr <angelo.zerr@gmail.com> - [CodeMining] Provide CodeMining support with CodeMiningManager - Bug 527720
12 */
13 package org.eclipse.jface.text.codemining;
14
15 import java.util.concurrent.CompletableFuture;
16 import java.util.function.Consumer;
17
18 import org.eclipse.swt.custom.StyledText;
19 import org.eclipse.swt.events.MouseEvent;
20 import org.eclipse.swt.graphics.Color;
21 import org.eclipse.swt.graphics.GC;
22 import org.eclipse.swt.graphics.Point;
23
24 import org.eclipse.core.runtime.IProgressMonitor;
25
26 import org.eclipse.jface.text.ITextViewer;
27 import org.eclipse.jface.text.Position;
28
29 /**
30 * A code mining represents a content (ex: label, icons) that should be shown along with source
31 * text, like the number of references, a way to run tests (with run/debug icons), etc.
32 *
33 * A code mining is unresolved when no content (ex: label, icons) is associated to it. For
34 * performance reasons the creation of a code mining and resolving should be done to two stages.
35 *
36 * @since 3.13
37 */
38 public interface ICodeMining {
39
40 /**
41 * Returns the line position where code mining must be displayed in the line spacing area.
42 *
43 * @return the line position where code mining must be displayed in the line spacing area.
44 */
45 Position getPosition();
46
47 /**
48 * Returns the owner provider which has created this mining.
49 *
50 * @return the owner provider which has created this mining.
51 */
52 ICodeMiningProvider getProvider();
53
54 /**
55 * Returns the label may be set early in the class lifecycle, or upon completion of the future
56 * provided by {@link #resolve(ITextViewer, IProgressMonitor)} operation.
57 *
58 * <p>
59 * The returned label can have several values:
60 * <ul>
61 * <li><code>null</code> when mining is not resolved</li>
62 * <li><code>null</code> when mining is resolved means that mining was resolved with an error and it will not
63 * be displayed.</li>
64 * <li>empty when mining is resolved means that mining will not be displayed</li>
65 * <li>non empty when mining must be displayed</li>
66 * </ul>
67 * </p>
68 *
69 * @return the label may be set early in the class lifecycle, or upon completion of the future
70 * provided by {@link #resolve(ITextViewer, IProgressMonitor)} operation.
71 */
72 String getLabel();
73
74 /**
75 * Returns the future to resolve the content of mining, or
76 * {@link CompletableFuture#completedFuture(Object)} if no such resolution is necessary (in
77 * which case {#isResolved()} is expected to return <code>true</code>).
78 *
79 * @param viewer the viewer.
80 * @param monitor the monitor.
81 * @return the future to resolve the content of mining, or
82 * {@link CompletableFuture#completedFuture(Object)} if no such resolution is necessary
83 * (in which case {#isResolved()} is expected to return <code>true</code>).
84 */
85 CompletableFuture<Void> resolve(ITextViewer viewer, IProgressMonitor monitor);
86
87 /**
88 * Returns whether the content mining is resolved. If it is not resolved,
89 * {{@link #resolve(ITextViewer, IProgressMonitor)}} will be invoked later, triggering the
90 * future to resolve content.
91 *
92 * @return whether the content mining is resolved. If it is not resolved,
93 * {{@link #resolve(ITextViewer, IProgressMonitor)}} will be invoked later, triggering
94 * the future to resolve content.
95 */
96 boolean isResolved();
97
98 /**
99 * Draw the code mining.
100 *
101 * @param gc the graphics context
102 * @param textWidget the text widget to draw on
103 * @param color the color of the line
104 * @param x the x position of the annotation
105 * @param y the y position of the annotation
106 * @return the size of the draw of mining.
107 */
108 Point draw(GC gc, StyledText textWidget, Color color, int x, int y);
109
110 /**
111 * Returns the action to execute when mining is clicked and null otherwise.
112 *
113 * @return the action to execute when mining is clicked and null otherwise.
114 */
115 Consumer<MouseEvent> getAction();
116
117 /**
118 * Dispose the mining. Typically shuts down or cancels all related asynchronous operations.
119 */
120 void dispose();
121 }
0 /**
1 * Copyright (c) 2017 Angelo ZERR.
0 /**
1 * Copyright (c) 2017 Angelo ZERR.
22 *
3 * This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License 2.0
5 * which accompanies this distribution, and is available at
3 * This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License 2.0
5 * which accompanies this distribution, and is available at
66 * https://www.eclipse.org/legal/epl-2.0/
77 *
8 * SPDX-License-Identifier: EPL-2.0
9 *
10 * Contributors:
11 * Angelo Zerr <angelo.zerr@gmail.com> - [CodeMining] Provide CodeMining support with CodeMiningManager - Bug 527720
12 */
13 package org.eclipse.jface.text.codemining;
14
15 import java.util.List;
16 import java.util.concurrent.CompletableFuture;
17
18 import org.eclipse.core.runtime.IProgressMonitor;
19
20 import org.eclipse.jface.text.ITextViewer;
21
22 /**
23 * A code mining provider adds minings {@link ICodeMining} to source text. The mining will be shown
24 * as dedicated horizontal lines in between the source text.
25 *
26 * @since 3.13
27 */
28 public interface ICodeMiningProvider {
29
30 /**
31 * Compute a list of code minings {@link ICodeMining}. This call should return as fast as
32 * possible and if computing the content of {@link ICodeMining} is expensive implementors should
33 * only return code mining objects with the position and implement resolve
34 * {@link ICodeMining#resolve(ITextViewer, IProgressMonitor)}.
35 *
36 * @param viewer the viewer in which the command was invoked.
37 * @param monitor A progress monitor.
38 * @return An array of future of code minings that resolves to such. The lack of a result can be
39 * signaled by returning null, or an empty array.
40 */
41 CompletableFuture<List<? extends ICodeMining>> provideCodeMinings(ITextViewer viewer, IProgressMonitor monitor);
42
43 /**
44 * Dispose code mining provider.
45 */
46 void dispose();
47 }
8 * SPDX-License-Identifier: EPL-2.0
9 *
10 * Contributors:
11 * Angelo Zerr <angelo.zerr@gmail.com> - [CodeMining] Provide CodeMining support with CodeMiningManager - Bug 527720
12 */
13 package org.eclipse.jface.text.codemining;
14
15 import java.util.List;
16 import java.util.concurrent.CompletableFuture;
17
18 import org.eclipse.core.runtime.IProgressMonitor;
19
20 import org.eclipse.jface.text.ITextViewer;
21
22 /**
23 * A code mining provider adds minings {@link ICodeMining} to source text. The mining will be shown
24 * as dedicated horizontal lines in between the source text.
25 *
26 * @since 3.13
27 */
28 public interface ICodeMiningProvider {
29
30 /**
31 * Compute a list of code minings {@link ICodeMining}. This call should return as fast as
32 * possible and if computing the content of {@link ICodeMining} is expensive implementors should
33 * only return code mining objects with the position and implement resolve
34 * {@link ICodeMining#resolve(ITextViewer, IProgressMonitor)}.
35 *
36 * @param viewer the viewer in which the command was invoked.
37 * @param monitor A progress monitor.
38 * @return An array of future of code minings that resolves to such. The lack of a result can be
39 * signaled by returning null, or an empty array.
40 */
41 CompletableFuture<List<? extends ICodeMining>> provideCodeMinings(ITextViewer viewer, IProgressMonitor monitor);
42
43 /**
44 * Dispose code mining provider.
45 */
46 void dispose();
47 }
6262 /**
6363 * @return the delay in milliseconds before this task should be run
6464 */
65 public abstract long delay();
66 /**
67 * Runs this task.
68 */
69 @Override
65 public abstract long delay();
66 /**
67 * Runs this task.
68 */
69 @Override
7070 public abstract void run();
71 /**
72 * @return the task to be scheduled after this task has been run
73 */
74 public abstract Task nextTask();
71 /**
72 * @return the task to be scheduled after this task has been run
73 */
74 public abstract Task nextTask();
7575 }
7676
7777 /**
8787 @Override
8888 public Task nextTask() {
8989 Assert.isTrue(false);
90 return null;
90 return null;
9191 }
9292
9393 @Override
111111 @Override
112112 protected IStatus run(IProgressMonitor monitor) {
113113 Object info;
114 try {
115 info= proposal.getAdditionalProposalInfo(monitor);
116 } catch (RuntimeException x) {
117 /*
114 try {
115 info= proposal.getAdditionalProposalInfo(monitor);
116 } catch (RuntimeException x) {
117 /*
118118 * XXX: This is the safest fix at this point so close to end of 3.2.
119119 * Will be revisited when fixing https://bugs.eclipse.org/bugs/show_bug.cgi?id=101033
120 */
121 return new Status(IStatus.WARNING, "org.eclipse.jface.text", IStatus.OK, "", x); //$NON-NLS-1$ //$NON-NLS-2$
122 }
120 */
121 return new Status(IStatus.WARNING, "org.eclipse.jface.text", IStatus.OK, "", x); //$NON-NLS-1$ //$NON-NLS-2$
122 }
123123 setInfo((ICompletionProposal) proposal, info);
124124 return Status.OK_STATUS;
125125 }
199199
200200 @Override
201201 public String toString() {
202 return "LEGACY_WAIT"; //$NON-NLS-1$
202 return "LEGACY_WAIT"; //$NON-NLS-1$
203203 }
204204 };
205205 /**
208208 private final Task EXIT= new Task() {
209209 @Override
210210 public long delay() {
211 return 1;
212 }
211 return 1;
212 }
213213
214214 @Override
215215 public Task nextTask() {
216216 Assert.isTrue(false);
217 return EXIT;
218 }
217 return EXIT;
218 }
219219
220220 @Override
221221 public void run() {
222222 Assert.isTrue(false);
223 }
223 }
224224
225225 @Override
226226 public String toString() {
250250 * @param delay the delay until to show additional info
251251 */
252252 public Timer(Display display, int delay) {
253 fDisplay= display;
253 fDisplay= display;
254254 fDelay= delay;
255255 long current= System.currentTimeMillis();
256 schedule(IDLE, current);
256 schedule(IDLE, current);
257257
258258 fThread= new Thread((Runnable) () -> {
259259 try {
291291 }
292292 }
293293
294 private Task taskOnReset(ICompletionProposal p) {
294 private Task taskOnReset(ICompletionProposal p) {
295295 if (p == null)
296296 return IDLE;
297297 if (isExt5(p))
298298 return FIRST_WAIT;
299299 return LEGACY_WAIT;
300 }
301
302 private synchronized void loop() throws InterruptedException {
303 long current= System.currentTimeMillis();
304 Task task= currentTask();
305
306 while (task != EXIT) {
307 long delay= fNextWakeup - current;
308 if (delay <= 0) {
309 task.run();
310 task= task.nextTask();
311 schedule(task, current);
312 } else {
313 wait(delay);
314 current= System.currentTimeMillis();
315 task= currentTask();
316 }
317 }
318 }
319
320 private Task currentTask() {
321 return fTask;
322 }
323
324 private void schedule(Task task, long current) {
325 fTask= task;
326 long nextWakeup= current + task.delay();
327 if (nextWakeup <= current)
328 fNextWakeup= Long.MAX_VALUE;
329 else
330 fNextWakeup= nextWakeup;
331 }
300 }
301
302 private synchronized void loop() throws InterruptedException {
303 long current= System.currentTimeMillis();
304 Task task= currentTask();
305
306 while (task != EXIT) {
307 long delay= fNextWakeup - current;
308 if (delay <= 0) {
309 task.run();
310 task= task.nextTask();
311 schedule(task, current);
312 } else {
313 wait(delay);
314 current= System.currentTimeMillis();
315 task= currentTask();
316 }
317 }
318 }
319
320 private Task currentTask() {
321 return fTask;
322 }
323
324 private void schedule(Task task, long current) {
325 fTask= task;
326 long nextWakeup= current + task.delay();
327 if (nextWakeup <= current)
328 fNextWakeup= Long.MAX_VALUE;
329 else
330 fNextWakeup= nextWakeup;
331 }
332332
333333 private boolean isExt5(ICompletionProposal p) {
334334 return p instanceof ICompletionProposalExtension5;
335335 }
336336
337 ICompletionProposal getCurrentProposal() {
338 return fCurrentProposal;
339 }
340
341 ICompletionProposalExtension5 getCurrentProposalEx() {
342 Assert.isTrue(fCurrentProposal instanceof ICompletionProposalExtension5);
343 return (ICompletionProposalExtension5) fCurrentProposal;
344 }
345
346 synchronized void setInfo(ICompletionProposal proposal, Object info) {
347 if (proposal == fCurrentProposal) {
348 fCurrentInfo= info;
349 if (fAllowShowing) {
350 triggerShowing();
351 }
352 }
353 }
354
355 private void triggerShowing() {
337 ICompletionProposal getCurrentProposal() {
338 return fCurrentProposal;
339 }
340
341 ICompletionProposalExtension5 getCurrentProposalEx() {
342 Assert.isTrue(fCurrentProposal instanceof ICompletionProposalExtension5);
343 return (ICompletionProposalExtension5) fCurrentProposal;
344 }
345
346 synchronized void setInfo(ICompletionProposal proposal, Object info) {
347 if (proposal == fCurrentProposal) {
348 fCurrentInfo= info;
349 if (fAllowShowing) {
350 triggerShowing();
351 }
352 }
353 }
354
355 private void triggerShowing() {
356356 final Object info= fCurrentInfo;
357357 if (!fDisplay.isDisposed()) {
358358 fDisplay.asyncExec(() -> {
363363 }
364364 });
365365 }
366 }
367
368 /**
369 * Called in the display thread to show additional info.
370 *
371 * @param proposal the proposal to show information about
372 * @param info the information about <code>proposal</code>
373 */
374 protected abstract void showInformation(ICompletionProposal proposal, Object info);
375
376 void allowShowing() {
377 fAllowShowing= true;
378 triggerShowing();
379 }
366 }
367
368 /**
369 * Called in the display thread to show additional info.
370 *
371 * @param proposal the proposal to show information about
372 * @param info the information about <code>proposal</code>
373 */
374 protected abstract void showInformation(ICompletionProposal proposal, Object info);
375
376 void allowShowing() {
377 fAllowShowing= true;
378 triggerShowing();
379 }
380380 }
381381 /**
382382 * Internal table selection listener.
440440 setAnchor(ANCHOR_RIGHT);
441441 setFallbackAnchors(new Anchor[] { ANCHOR_RIGHT, ANCHOR_LEFT, ANCHOR_BOTTOM });
442442
443 /*
443 /*
444444 * Adjust the location by one pixel towards the proposal popup, so that the single pixel
445445 * border of the additional info popup overlays with the border of the popup. This avoids
446446 * having a double black line.
447447 */
448 int spacing= -1;
448 int spacing= -1;
449449 setMargins(spacing, spacing); // see also adjustment in #computeLocation
450450
451451 InformationControlReplacer replacer= new InformationControlReplacer(new DefaultPresenterControlCreator());
524524 if (fProposal == proposal && ((info == null && fInformation == null) || (info != null && info.equals(fInformation))))
525525 return;
526526
527 fInformation= info;
528 fProposal= proposal;
529 showInformation();
530 }
527 fInformation= info;
528 fProposal= proposal;
529 showInformation();
530 }
531531
532532 @Override
533533 protected void computeInformation() {
545545
546546 @Override
547547 protected Point computeLocation(Rectangle subjectArea, Point controlSize, Anchor anchor) {
548 Point location= super.computeLocation(subjectArea, controlSize, anchor);
549
550 /*
548 Point location= super.computeLocation(subjectArea, controlSize, anchor);
549
550 /*
551551 * The location is computed using subjectControl.toDisplay(), which does not include the
552552 * trim of the subject control. As we want the additional info popup aligned with the outer
553553 * coordinates of the proposal popup, adjust this here
554554 */
555 Rectangle trim= fProposalTable.getShell().computeTrim(0, 0, 0, 0);
556 location.x += trim.x;
557 location.y += trim.y;
555 Rectangle trim= fProposalTable.getShell().computeTrim(0, 0, 0, 0);
556 location.x += trim.x;
557 location.y += trim.y;
558558
559559 return location;
560560 }
565565 Point sizeConstraint= super.computeSizeConstraints(subjectControl, informationControl);
566566 Point size= subjectControl.getShell().getSize();
567567
568 // AbstractInformationControlManager#internalShowInformationControl(Rectangle, Object) adds trims
568 // AbstractInformationControlManager#internalShowInformationControl(Rectangle, Object) adds trims
569569 // to the computed constraints. Need to remove them here, to make the outer bounds of the additional
570570 // info shell fit the bounds of the proposal shell:
571 if (fInformationControl instanceof IInformationControlExtension3) {
572 Rectangle shellTrim= ((IInformationControlExtension3) fInformationControl).computeTrim();
573 size.x -= shellTrim.width;
574 size.y -= shellTrim.height;
575 }
571 if (fInformationControl instanceof IInformationControlExtension3) {
572 Rectangle shellTrim= ((IInformationControlExtension3) fInformationControl).computeTrim();
573 size.x -= shellTrim.width;
574 size.y -= shellTrim.height;
575 }
576576
577577 if (sizeConstraint.x < size.x)
578578 sizeConstraint.x= size.x;
739739 * @param control the control to watch for focus
740740 * @since 3.2
741741 */
742 private void addCommandSupport(final Control control) {
743 final KeySequence commandSequence= fContentAssistant.getRepeatedInvocationKeySequence();
744 if (commandSequence != null && !commandSequence.isEmpty() && fContentAssistant.isRepeatedInvocationMode()) {
745 control.addFocusListener(new FocusListener() {
746 private CommandKeyListener fCommandKeyListener;
747 @Override
742 private void addCommandSupport(final Control control) {
743 final KeySequence commandSequence= fContentAssistant.getRepeatedInvocationKeySequence();
744 if (commandSequence != null && !commandSequence.isEmpty() && fContentAssistant.isRepeatedInvocationMode()) {
745 control.addFocusListener(new FocusListener() {
746 private CommandKeyListener fCommandKeyListener;
747 @Override
748748 public void focusGained(FocusEvent e) {
749 if (Helper.okToUse(control)) {
750 if (fCommandKeyListener == null) {
751 fCommandKeyListener= new CommandKeyListener(commandSequence);
752 fProposalTable.addKeyListener(fCommandKeyListener);
753 }
754 }
755 }
756 @Override
749 if (Helper.okToUse(control)) {
750 if (fCommandKeyListener == null) {
751 fCommandKeyListener= new CommandKeyListener(commandSequence);
752 fProposalTable.addKeyListener(fCommandKeyListener);
753 }
754 }
755 }
756 @Override
757757 public void focusLost(FocusEvent e) {
758 if (fCommandKeyListener != null) {
759 control.removeKeyListener(fCommandKeyListener);
760 fCommandKeyListener= null;
761 }
762 }
763 });
764 }
765 if (fAdditionalInfoController != null) {
766 control.addFocusListener(new FocusListener() {
767 private TraverseListener fTraverseListener;
768 @Override
758 if (fCommandKeyListener != null) {
759 control.removeKeyListener(fCommandKeyListener);
760 fCommandKeyListener= null;
761 }
762 }
763 });
764 }
765 if (fAdditionalInfoController != null) {
766 control.addFocusListener(new FocusListener() {
767 private TraverseListener fTraverseListener;
768 @Override
769769 public void focusGained(FocusEvent e) {
770 if (Helper.okToUse(control)) {
771 if (fTraverseListener == null) {
770 if (Helper.okToUse(control)) {
771 if (fTraverseListener == null) {
772772 fTraverseListener= new TraverseListener() {
773773 @Override
774774 public void keyTraversed(TraverseEvent event) {
781781 }
782782 }
783783 };
784 fProposalTable.addTraverseListener(fTraverseListener);
785 }
786 }
787 }
788 @Override
784 fProposalTable.addTraverseListener(fTraverseListener);
785 }
786 }
787 }
788 @Override
789789 public void focusLost(FocusEvent e) {
790 if (fTraverseListener != null) {
791 control.removeTraverseListener(fTraverseListener);
792 fTraverseListener= null;
793 }
794 }
795 });
796 }
797 }
790 if (fTraverseListener != null) {
791 control.removeTraverseListener(fTraverseListener);
792 fTraverseListener= null;
793 }
794 }
795 });
796 }
797 }
798798
799799 /**
800800 * Returns the background color to use.
24632463 /**
24642464 * Returns the prefix completion state.
24652465 *
2466 * @return <code>true</code> if prefix completion is enabled, <code>false</code> otherwise
2467 * @since 3.2
2468 */
2469 boolean isPrefixCompletionEnabled() {
2470 return fIsPrefixCompletionEnabled;
2471 }
2466 * @return <code>true</code> if prefix completion is enabled, <code>false</code> otherwise
2467 * @since 3.2
2468 */
2469 boolean isPrefixCompletionEnabled() {
2470 return fIsPrefixCompletionEnabled;
2471 }
24722472
24732473 /**
24742474 * Returns whether the content assistant proposal popup has the focus.
27312731 * @since 3.4
27322732 */
27332733 boolean isColoredLabelsSupportEnabled() {
2734 return fIsColoredLabelsSupportEnabled;
2734 return fIsColoredLabelsSupportEnabled;
27352735 }
27362736
27372737 /**
822822
823823 } else if (key == SWT.ESC) {
824824 e.doit= false;
825 hideContextInfoPopup();
825 hideContextInfoPopup();
826826 } else {
827827 validateContextInformation();
828828 }
149149 }
150150 }
151151
152 reconcilerReset();
152 reconcilerReset();
153153 }
154154
155155 /**
481481 }
482482 fListener= null;
483483
484 synchronized (this) {
485 // http://dev.eclipse.org/bugs/show_bug.cgi?id=19135
486 BackgroundThread bt= fThread;
487 fThread= null;
488 bt.cancel();
489 }
484 synchronized (this) {
485 // http://dev.eclipse.org/bugs/show_bug.cgi?id=19135
486 BackgroundThread bt= fThread;
487 fThread= null;
488 bt.cancel();
489 }
490490 }
491491 }
492492
577577 }
578578 }
579579
580 /**
581 * Hook that is called after the reconciler thread has been reset.
582 */
583 protected void reconcilerReset() {
584 }
585
586 /**
580 /**
581 * Hook that is called after the reconciler thread has been reset.
582 */
583 protected void reconcilerReset() {
584 }
585
586 /**
587587 * Tells whether the code is running in this reconciler's
588588 * background thread.
589589 *
513513 return null;
514514 }
515515
516 /* zero-length partition support */
516 /* zero-length partition support */
517517
518518 @Override
519519 public String getContentType(int offset, boolean preferOpenPartitions) {
533533 return new TypedRegion(offset, 0, IDocument.DEFAULT_CONTENT_TYPE);
534534 }
535535 }
536 return region;
536 return region;
537537 }
538538
539539 @Override
573573 return null;
574574 }
575575
576 /* zero-length partition support */
576 /* zero-length partition support */
577577
578578 /**
579579 * {@inheritDoc}
605605 return new TypedRegion(offset, 0, IDocument.DEFAULT_CONTENT_TYPE);
606606 }
607607 }
608 return region;
608 return region;
609609 }
610610
611611 /**
505505 return null;
506506 }
507507
508 /* zero-length partition support */
508 /* zero-length partition support */
509509
510510 @Override
511511 public String getContentType(int offset, boolean preferOpenPartitions) {
525525 return new TypedRegion(offset, 0, IDocument.DEFAULT_CONTENT_TYPE);
526526 }
527527 }
528 return region;
528 return region;
529529 }
530530
531531 @Override
194194
195195 @Override
196196 public void unread() {
197 --fOffset;
197 --fOffset;
198198 fColumn= UNDEFINED;
199199 }
200200 }
349349
350350 @Override
351351 protected void showInformationControl(Rectangle subjectArea) {
352 super.showInformationControl(subjectArea);
353 fCurrentHover= getHover(getHoverEvent());
352 super.showInformationControl(subjectArea);
353 fCurrentHover= getHover(getHoverEvent());
354354 }
355355
356356 @Override
357357 protected void hideInformationControl() {
358358 fCurrentHover= null;
359 super.hideInformationControl();
359 super.hideInformationControl();
360360 }
361361
362362 /**
706706 * @return the currently shown annotation hover or <code>null</code>
707707 * @since 3.2
708708 */
709 public IAnnotationHover getCurrentAnnotationHover() {
710 return fCurrentHover;
711 }
709 public IAnnotationHover getCurrentAnnotationHover() {
710 return fCurrentHover;
711 }
712712
713713 /**
714714 * Returns an adapter that gives access to internal methods.
721721 * @noreference This method is not intended to be referenced by clients.
722722 * @nooverride This method is not intended to be re-implemented or extended by clients.
723723 */
724 @Override
724 @Override
725725 public InternalAccessor getInternalAccessor() {
726 return new InternalAccessor() {
726 return new InternalAccessor() {
727727 @Override
728728 public IInformationControl getCurrentInformationControl() {
729729 return AnnotationBarHoverManager.super.getInternalAccessor().getCurrentInformationControl();
769769 return fAllowMouseExit;
770770 }
771771 };
772 }
772 }
773773 }
774774
956956 private void invalidateTextPresentation() {
957957 IRegion r= null;
958958 synchronized (fHighlightedDecorationsMapLock) {
959 if (fCurrentHighlightAnnotationRange != null)
960 r= new Region(fCurrentHighlightAnnotationRange.getOffset(), fCurrentHighlightAnnotationRange.getLength());
959 if (fCurrentHighlightAnnotationRange != null)
960 r= new Region(fCurrentHighlightAnnotationRange.getOffset(), fCurrentHighlightAnnotationRange.getLength());
961961 }
962962 if (r == null)
963963 return;
16091609 }
16101610
16111611 /**
1612 * Retrieves the annotation model from the given source viewer.
1613 *
1614 * @param sourceViewer the source viewer
1615 * @return the source viewer's annotation model or <code>null</code> if none can be found
1612 * Retrieves the annotation model from the given source viewer.
1613 *
1614 * @param sourceViewer the source viewer
1615 * @return the source viewer's annotation model or <code>null</code> if none can be found
16161616 * @since 3.0
16171617 */
16181618 protected IAnnotationModel findAnnotationModel(ISourceViewer sourceViewer) {
493493 }
494494
495495 /**
496 * Returns the revision selection provider.
497 *
498 * @return the revision selection provider
499 * @since 3.2
500 */
501 public ISelectionProvider getRevisionSelectionProvider() {
502 return fRevisionPainter.getRevisionSelectionProvider();
503 }
496 * Returns the revision selection provider.
497 *
498 * @return the revision selection provider
499 * @since 3.2
500 */
501 public ISelectionProvider getRevisionSelectionProvider() {
502 return fRevisionPainter.getRevisionSelectionProvider();
503 }
504504 }
123123 * top of the text widget and the top of this overview ruler.
124124 *
125125 * @return the header control of this overview ruler.
126 */
126 */
127127 Control getHeaderControl();
128128 }
228228 postRedraw();
229229 }
230230
231 @Override
231 @Override
232232 public ISelectionProvider getRevisionSelectionProvider() {
233 return fRevisionPainter.getRevisionSelectionProvider();
234 }
235
236 /*
237 * @see org.eclipse.jface.text.revisions.IRevisionRulerColumnExtension#setRenderingMode(org.eclipse.jface.text.revisions.IRevisionRulerColumnExtension.RenderingMode)
238 * @since 3.3
239 */
240 @Override
233 return fRevisionPainter.getRevisionSelectionProvider();
234 }
235
236 /*
237 * @see org.eclipse.jface.text.revisions.IRevisionRulerColumnExtension#setRenderingMode(org.eclipse.jface.text.revisions.IRevisionRulerColumnExtension.RenderingMode)
238 * @since 3.3
239 */
240 @Override
241241 public void setRevisionRenderingMode(RenderingMode renderingMode) {
242242 fRevisionPainter.setRenderingMode(renderingMode);
243243 }
249249 * diff / revision info.
250250 * @since 3.3
251251 */
252 public void showLineNumbers(boolean showNumbers) {
253 if (fShowNumbers != showNumbers) {
254 fShowNumbers= showNumbers;
252 public void showLineNumbers(boolean showNumbers) {
253 if (fShowNumbers != showNumbers) {
254 fShowNumbers= showNumbers;
255255 updateNumberOfDigits();
256256 computeIndentations();
257257 layout(true);
258 }
259 }
260
261 @Override
258 }
259 }
260
261 @Override
262262 public int getWidth() {
263 int width= super.getWidth();
263 int width= super.getWidth();
264264 return width > 0 ? width : 8; // minimal width to display quick diff / revisions if no textual info is shown
265 }
266
267 /**
265 }
266
267 /**
268268 * Returns <code>true</code> if the ruler is showing line numbers, <code>false</code>
269269 * otherwise
270270 *
611611 VisibleLinesTracker.track(fCachedTextViewer, lineHeightChangeHandler);
612612
613613 fCanvas= new Canvas(parentControl, SWT.NO_FOCUS ) {
614 @Override
614 @Override
615615 public void addMouseListener(MouseListener listener) {
616616 // see bug 40889, bug 230073 and AnnotationRulerColumn#isPropagatingMouseListener()
617617 if (listener == fMouseHandler)
363363 thumbHeight= verticalBar != null ? Math.max(Math.min(bounds.height, verticalBar.getThumbBounds().height), 0) : 0;
364364 }
365365
366 int partialTopIndex= JFaceTextUtil.getPartialTopIndex(textWidget);
367 int topLineHeight= textWidget.getLineHeight(textWidget.getOffsetAtLine(partialTopIndex));
368 int topLinePixel= textWidget.getLinePixel(partialTopIndex);
369 double topIndex= partialTopIndex - (double) topLinePixel / topLineHeight;
370
371 int partialBottomIndex= JFaceTextUtil.getPartialBottomIndex(textWidget);
372 int bottomLineHeight= textWidget.getLineHeight(textWidget.getOffsetAtLine(partialBottomIndex));
373 int bottomLinePixel= textWidget.getLinePixel(partialBottomIndex);
374 double bottomIndex= partialBottomIndex - ((double) bottomLinePixel - textWidget.getClientArea().height) / bottomLineHeight;
375
376 visibleLines= bottomIndex - topIndex;
377 invisibleLines= maxLines - visibleLines;
366 int partialTopIndex= JFaceTextUtil.getPartialTopIndex(textWidget);
367 int topLineHeight= textWidget.getLineHeight(textWidget.getOffsetAtLine(partialTopIndex));
368 int topLinePixel= textWidget.getLinePixel(partialTopIndex);
369 double topIndex= partialTopIndex - (double) topLinePixel / topLineHeight;
370
371 int partialBottomIndex= JFaceTextUtil.getPartialBottomIndex(textWidget);
372 int bottomLineHeight= textWidget.getLineHeight(textWidget.getOffsetAtLine(partialBottomIndex));
373 int bottomLinePixel= textWidget.getLinePixel(partialBottomIndex);
374 double bottomIndex= partialBottomIndex - ((double) bottomLinePixel - textWidget.getClientArea().height) / bottomLineHeight;
375
376 visibleLines= bottomIndex - topIndex;
377 invisibleLines= maxLines - visibleLines;
378378 }
379379 }
380380
12571257 }
12581258 }
12591259
1260 @Override
1260 @Override
12611261 public IAnnotationHover getCurrentAnnotationHover() {
1262 if (fVerticalRulerHoveringController == null)
1263 return null;
1264 return fVerticalRulerHoveringController.getCurrentAnnotationHover();
1265 }
1266
1267 @Override
1262 if (fVerticalRulerHoveringController == null)
1263 return null;
1264 return fVerticalRulerHoveringController.getCurrentAnnotationHover();
1265 }
1266
1267 @Override
12681268 public void setCodeMiningProviders(ICodeMiningProvider[] codeMiningProviders) {
12691269 boolean enable= codeMiningProviders != null && codeMiningProviders.length > 0;
12701270 fCodeMiningProviders= codeMiningProviders;
2121 import org.eclipse.swt.graphics.Font;
2222 import org.eclipse.swt.graphics.GC;
2323
24 import org.eclipse.jface.text.IRegion;
2425 import org.eclipse.jface.text.ITextViewerExtension5;
2526 import org.eclipse.jface.text.Position;
27 import org.eclipse.jface.text.Region;
2628 import org.eclipse.jface.text.source.Annotation;
2729 import org.eclipse.jface.text.source.ISourceViewer;
30 import org.eclipse.jface.text.source.projection.ProjectionViewer;
2831
2932 /**
3033 * Abstract class for inlined annotation.
7174 }
7275
7376 /**
74 * Returns the position where the annotation must be drawn.
75 *
76 * @return the position where the annotation must be drawn.
77 * Returns the position where the annotation must be drawn. For {@link ITextViewerExtension5}
78 * (enabling folding with widget/model projection), this position is the <strong>model</strong>
79 * position.
80 *
81 * @return the model position where the annotation must be drawn.
7782 */
7883 public Position getPosition() {
84 return position;
85 }
86
87 final Position computeWidgetPosition() {
88 if (fViewer instanceof ITextViewerExtension5) {
89 IRegion region= ((ITextViewerExtension5) fViewer).modelRange2WidgetRange(new Region(position.getOffset(), position.getLength()));
90 return new Position(region.getOffset(), region.getLength());
91 }
7992 return position;
8093 }
8194
118131 * Draw the inlined annotation. By default it draw the text of the annotation with gray color.
119132 * User can override this method to draw anything.
120133 *
121 * @param gc the graphics context
134 * @param gc the graphics context
122135 * @param textWidget the text widget to draw on
123 * @param offset the offset of the line
124 * @param length the length of the line
125 * @param color the color of the line
126 * @param x the x position of the annotation
127 * @param y the y position of the annotation
128 */
129 public void draw(GC gc, StyledText textWidget, int offset, int length, Color color, int x, int y) {
136 * @param widgetOffset the offset
137 * @param length the length of the line
138 * @param color the color of the line
139 * @param x the x position of the annotation
140 * @param y the y position of the annotation
141 */
142 public void draw(GC gc, StyledText textWidget, int widgetOffset, int length, Color color, int x, int y) {
130143 gc.setForeground(color);
131144 gc.setBackground(textWidget.getBackground());
132145 gc.drawString(getText(), x, y, true);
173186 */
174187 protected boolean isInVisibleLines() {
175188 return support.isInVisibleLines(getPosition().getOffset());
189 }
190
191 boolean isFirstVisibleOffset(int widgetOffset) {
192 if (fViewer instanceof ProjectionViewer) {
193 IRegion widgetRange= ((ProjectionViewer) fViewer).modelRange2WidgetRange(new Region(position.getOffset(), position.getLength()));
194 return widgetOffset == widgetRange.getOffset();
195 } else {
196 return position.getOffset() == widgetOffset;
197 }
176198 }
177199
178200 /**
2020 import org.eclipse.swt.graphics.Point;
2121 import org.eclipse.swt.graphics.Rectangle;
2222
23 import org.eclipse.jface.text.Position;
2423 import org.eclipse.jface.text.source.Annotation;
2524 import org.eclipse.jface.text.source.AnnotationPainter.IDrawingStrategy;
2625
3231 class InlinedAnnotationDrawingStrategy implements IDrawingStrategy {
3332
3433 @Override
35 public void draw(Annotation annotation, GC gc, StyledText textWidget, int offset, int length, Color color) {
34 public void draw(Annotation annotation, GC gc, StyledText textWidget, int widgetOffset, int length, Color color) {
3635 if (!(annotation instanceof AbstractInlinedAnnotation)) {
3736 return;
3837 }
39 if (!((AbstractInlinedAnnotation) annotation).isInVisibleLines()) {
40 // The annotation is not in visible lines, don't draw it.
41 return;
42 }
43 InlinedAnnotationDrawingStrategy.draw((AbstractInlinedAnnotation) annotation, gc, textWidget, offset, length,
44 color);
38 AbstractInlinedAnnotation inlinedAnnotation= (AbstractInlinedAnnotation) annotation;
39 if (inlinedAnnotation.isInVisibleLines() && inlinedAnnotation.isFirstVisibleOffset(widgetOffset)) {
40 draw((AbstractInlinedAnnotation) annotation, gc, textWidget, widgetOffset, length,
41 color);
42 }
4543 }
4644
4745 /**
5048 * @param annotation the annotation to be drawn
5149 * @param gc the graphics context, <code>null</code> when in clearing mode
5250 * @param textWidget the text widget to draw on
53 * @param offset the offset of the line
51 * @param widgetOffset the offset of the line
5452 * @param length the length of the line
5553 * @param color the color of the line
5654 */
57 public static void draw(AbstractInlinedAnnotation annotation, GC gc, StyledText textWidget, int offset, int length,
55 public static void draw(AbstractInlinedAnnotation annotation, GC gc, StyledText textWidget, int widgetOffset, int length,
5856 Color color) {
5957 if (annotation instanceof LineHeaderAnnotation) {
60 draw((LineHeaderAnnotation) annotation, gc, textWidget, offset, length, color);
61 } else {
62 draw((LineContentAnnotation) annotation, gc, textWidget, offset, length, color);
58 draw((LineHeaderAnnotation) annotation, gc, textWidget, widgetOffset, length, color);
59 } else {
60 draw((LineContentAnnotation) annotation, gc, textWidget, widgetOffset, length, color);
6361 }
6462 }
6563
125123 * @param annotation the annotation to be drawn
126124 * @param gc the graphics context, <code>null</code> when in clearing mode
127125 * @param textWidget the text widget to draw on
128 * @param offset the offset of the line
126 * @param widgetOffset the offset of the line in the widget (not model)
129127 * @param length the length of the line
130128 * @param color the color of the line
131129 */
132 private static void draw(LineContentAnnotation annotation, GC gc, StyledText textWidget, int offset, int length,
130 private static void draw(LineContentAnnotation annotation, GC gc, StyledText textWidget, int widgetOffset, int length,
133131 Color color) {
132 if (annotation.drawRightToPreviousChar(widgetOffset)) {
133 drawAsRightOfPreviousCharacter(annotation, gc, textWidget, widgetOffset, length, color);
134 } else {
135 drawAsLeftOf1stCharacter(annotation, gc, textWidget, widgetOffset, length, color);
136 }
137 }
138
139 protected static void drawAsLeftOf1stCharacter(LineContentAnnotation annotation, GC gc, StyledText textWidget, int widgetOffset, int length, Color color) {
134140 StyleRange style= null;
135141 try {
136 style= textWidget.getStyleRangeAtOffset(offset);
142 style= textWidget.getStyleRangeAtOffset(widgetOffset);
137143 } catch (Exception e) {
138144 return;
139145 }
146152 return;
147153 }
148154 if (gc != null) {
149 String s= textWidget.getText(offset, offset);
150 boolean isEndOfLine= ("\r".equals(s) || "\n".equals(s)); //$NON-NLS-1$ //$NON-NLS-2$
155 String hostCharacter= textWidget.getText(widgetOffset, widgetOffset);
156 boolean isEndOfLine= ("\r".equals(hostCharacter) || "\n".equals(hostCharacter)); //$NON-NLS-1$ //$NON-NLS-2$
151157
152158 // Compute the location of the annotation
153 Rectangle bounds= textWidget.getTextBounds(offset, offset);
159 Rectangle bounds= textWidget.getTextBounds(widgetOffset, widgetOffset);
154160 int x= bounds.x + (isEndOfLine ? bounds.width * 2 : 0);
155161 int y= bounds.y;
156162
159165
160166 // Draw the line content annotation
161167 annotation.setLocation(x, y);
162 annotation.draw(gc, textWidget, offset, length, color, x, y);
168 annotation.draw(gc, textWidget, widgetOffset, length, color, x, y);
163169 int width= annotation.getWidth();
164170 if (width != 0) {
165171 if (isEndOfLine) {
170176 }
171177 } else {
172178 // Get size of the character where GlyphMetrics width is added
173 Point charBounds= gc.stringExtent(s);
179 Point charBounds= gc.stringExtent(hostCharacter);
174180 int charWidth= charBounds.x;
175181
176182 // FIXME: remove this code when we need not redraw the character (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=531769)
179185 // END TO REMOVE
180186
181187 // Annotation takes place, add GlyphMetrics width to the style
182 StyleRange newStyle= updateStyle(annotation, style);
188 StyleRange newStyle= annotation.updateStyle(style);
183189 if (newStyle != null) {
184190 textWidget.setStyleRange(newStyle);
185191 return;
191197 // GlyphMetrics
192198 // Here we need to redraw this first character because GlyphMetrics clip this
193199 // character.
194 int charX= x + bounds.width - charWidth;
195 int charY= y;
200 int redrawnHostCharX= x + bounds.width - charWidth;
201 int redrawnHostCharY= y;
202 gc.setForeground(textWidget.getForeground());
203 gc.setBackground(textWidget.getBackground());
204 gc.setFont(textWidget.getFont());
196205 if (style != null) {
197206 if (style.background != null) {
198207 gc.setBackground(style.background);
199 gc.fillRectangle(charX, charY, charWidth + 1, bounds.height);
208 gc.fillRectangle(redrawnHostCharX, redrawnHostCharY, charWidth + 1, bounds.height);
200209 }
201210 if (style.foreground != null) {
202211 gc.setForeground(style.foreground);
203 } else {
204 gc.setForeground(textWidget.getForeground());
205212 }
206 gc.setFont(annotation.getFont(style.fontStyle));
207 }
208 gc.drawString(s, charX, charY, true);
213 if (style.font != null) {
214 gc.setFont(style.font);
215 }
216 }
217 if (textWidget.getSelection().x <= widgetOffset && textWidget.getSelection().y > widgetOffset) {
218 gc.setForeground(textWidget.getSelectionForeground());
219 gc.setBackground(textWidget.getSelectionBackground());
220 }
221 gc.drawString(hostCharacter, redrawnHostCharX, redrawnHostCharY, true);
209222 }
210223 // END TO REMOVE
211224 } else if (style != null && style.metrics != null && style.metrics.width != 0) {
214227 textWidget.setStyleRange(style);
215228 }
216229 } else {
217 textWidget.redrawRange(offset, length, true);
218 }
219 }
220
221 /**
222 * Returns the style to apply with GlyphMetrics width only if needed.
223 *
224 * @param annotation the line content annotation
225 * @param style the current style and null otherwise.
226 * @return the style to apply with GlyphMetrics width only if needed.
227 */
228 static StyleRange updateStyle(LineContentAnnotation annotation, StyleRange style) {
229 int width= annotation.getWidth();
230 if (width == 0 || annotation.getRedrawnCharacterWidth() == 0) {
231 return null;
232 }
233 int fullWidth= width + annotation.getRedrawnCharacterWidth();
234 if (style == null) {
235 style= new StyleRange();
236 Position position= annotation.getPosition();
237 style.start= position.getOffset();
238 style.length= 1;
239 }
240 GlyphMetrics metrics= style.metrics;
241 if (!annotation.isMarkedDeleted()) {
242 if (metrics == null) {
243 metrics= new GlyphMetrics(0, 0, fullWidth);
244 } else {
245 if (metrics.width == fullWidth) {
246 return null;
247 }
248 /**
249 * We must create a new GlyphMetrics instance because comparison with similarTo used
250 * later in StyledText#setStyleRange will compare the same (modified) and won't
251 * realize an update happened.
252 */
253 metrics= new GlyphMetrics(0, 0, fullWidth);
254 }
255 } else {
256 metrics= null;
257 }
258 style.metrics= metrics;
259 return style;
230 textWidget.redrawRange(widgetOffset, length, true);
231 }
232 }
233
234 protected static void drawAsRightOfPreviousCharacter(LineContentAnnotation annotation, GC gc, StyledText textWidget, int widgetOffset, int length, Color color) {
235 StyleRange style= null;
236 try {
237 style= textWidget.getStyleRangeAtOffset(widgetOffset - 1);
238 } catch (Exception e) {
239 return;
240 }
241 if (isDeleted(annotation)) {
242 // When annotation is deleted, update metrics to null to remove extra spaces of the line content annotation.
243 if (style != null && style.metrics != null) {
244 style.metrics= null;
245 textWidget.setStyleRange(style);
246 }
247 return;
248 }
249 if (gc != null) {
250 String hostCharacter= textWidget.getText(widgetOffset - 1, widgetOffset - 1);
251 int redrawnCharacterWidth= gc.stringExtent(hostCharacter).x;
252 Rectangle charBounds= textWidget.getTextBounds(widgetOffset - 1, widgetOffset - 1);
253 Rectangle annotationBounds= new Rectangle(charBounds.x + redrawnCharacterWidth, charBounds.y, annotation.getWidth(), charBounds.height);
254
255 // When line text has line header annotation, there is a space on the top, adjust the y by using char height
256 annotationBounds.y+= charBounds.height - textWidget.getLineHeight();
257
258 // Draw the line content annotation
259 annotation.setLocation(annotationBounds.x, annotationBounds.y);
260 annotation.draw(gc, textWidget, widgetOffset, length, color, annotationBounds.x, annotationBounds.y);
261 int width= annotation.getWidth();
262 if (width != 0) {
263 // FIXME: remove this code when we need not redraw the character (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=531769)
264 // START TO REMOVE
265 annotation.setRedrawnCharacterWidth(redrawnCharacterWidth);
266 // END TO REMOVE
267
268 // Annotation takes place, add GlyphMetrics width to the style
269 StyleRange newStyle= annotation.updateStyle(style);
270 if (newStyle != null) {
271 textWidget.setStyleRange(newStyle);
272 return;
273 }
274
275 // FIXME: remove this code when we need not redraw the character (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=531769)
276 // START TO REMOVE
277 // The inline annotation replaces one character by taking a place width
278 // GlyphMetrics
279 // Here we need to redraw this first character because GlyphMetrics clip this
280 // character.
281 gc.setForeground(textWidget.getForeground());
282 gc.setBackground(textWidget.getBackground());
283 gc.setFont(textWidget.getFont());
284 if (style != null) {
285 if (style.background != null) {
286 gc.setBackground(style.background);
287 gc.fillRectangle(charBounds.x, annotationBounds.y, redrawnCharacterWidth, charBounds.height);
288 }
289 if (style.foreground != null) {
290 gc.setForeground(style.foreground);
291 }
292 if (style.font != null) {
293 gc.setFont(style.font);
294 }
295 }
296 int toRedrawCharOffset= widgetOffset - 1;
297 if (textWidget.getSelection().x <= toRedrawCharOffset && textWidget.getSelection().y > toRedrawCharOffset) {
298 gc.setForeground(textWidget.getSelectionForeground());
299 gc.setBackground(textWidget.getSelectionBackground());
300 }
301 gc.drawString(hostCharacter, charBounds.x, charBounds.y, true);
302 // END TO REMOVE
303 } else if (style != null && style.metrics != null && style.metrics.width != 0) {
304 // line content annotation had an , reset it
305 style.metrics= null;
306 textWidget.setStyleRange(style);
307 }
308 } else {
309 textWidget.redrawRange(widgetOffset, length, true);
310 }
260311 }
261312
262313 /**
4747 import org.eclipse.jface.text.ISynchronizable;
4848 import org.eclipse.jface.text.ITextPresentationListener;
4949 import org.eclipse.jface.text.ITextViewerExtension4;
50 import org.eclipse.jface.text.ITextViewerExtension5;
5051 import org.eclipse.jface.text.IViewportListener;
5152 import org.eclipse.jface.text.JFaceTextUtil;
5253 import org.eclipse.jface.text.Position;
54 import org.eclipse.jface.text.Region;
5355 import org.eclipse.jface.text.TextPresentation;
5456 import org.eclipse.jface.text.source.Annotation;
5557 import org.eclipse.jface.text.source.AnnotationPainter;
106108 .forEachRemaining(annotation -> {
107109 if (annotation instanceof LineContentAnnotation) {
108110 LineContentAnnotation ann= (LineContentAnnotation) annotation;
109 StyleRange style= InlinedAnnotationDrawingStrategy.updateStyle(ann, null);
111 StyleRange style= ann.updateStyle(null);
110112 if (style != null) {
113 if (fViewer instanceof ITextViewerExtension5) {
114 ITextViewerExtension5 projectionViewer= (ITextViewerExtension5) fViewer;
115 IRegion annotationRegion= projectionViewer.widgetRange2ModelRange(new Region(style.start, style.length));
116 style.start= annotationRegion.getOffset();
117 style.length= annotationRegion.getLength();
118 }
111119 textPresentation.mergeStyleRange(style);
112120 }
113121 }
0 /**
1 * Copyright (c) 2017, 2018 Angelo ZERR.
0 /**
1 * Copyright (c) 2017, 2018 Angelo ZERR.
22 *
3 * This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License 2.0
5 * which accompanies this distribution, and is available at
3 * This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License 2.0
5 * which accompanies this distribution, and is available at
66 * https://www.eclipse.org/legal/epl-2.0/
77 *
8 * SPDX-License-Identifier: EPL-2.0
9 *
10 * Contributors:
11 * Angelo Zerr <angelo.zerr@gmail.com> - [CodeMining] Provide inline annotations support - Bug 527675
12 */
13 package org.eclipse.jface.text.source.inlined;
14
15 import org.eclipse.swt.custom.StyledText;
16 import org.eclipse.swt.graphics.Color;
17 import org.eclipse.swt.graphics.GC;
18
19 import org.eclipse.jface.text.Position;
20 import org.eclipse.jface.text.source.ISourceViewer;
21
22 /**
23 * Inlined annotation which is drawn in the line content and which takes some place with a given
24 * width.
25 *
26 * @since 3.13
27 */
28 public class LineContentAnnotation extends AbstractInlinedAnnotation {
29
30 /**
31 * The annotation width
32 */
33 private int width;
34
35 private int redrawnCharacterWidth;
36
37 /**
38 * Line content annotation constructor.
39 *
40 * @param position the position where the annotation must be drawn.
41 * @param viewer the {@link ISourceViewer} where the annotation must be drawn.
42 */
43 public LineContentAnnotation(Position position, ISourceViewer viewer) {
44 super(position, viewer);
45 }
46
47 /**
48 * Returns the annotation width. By default it computes the well width for the text annotation.
49 *
50 * @return the annotation width.
51 */
52 public final int getWidth() {
53 return width;
54 }
55
56 /**
57 * {@inheritDoc}
58 * <p>
59 * After drawn, compute the text width and update it.
60 * </p>
61 */
62 @Override
63 public final void draw(GC gc, StyledText textWidget, int offset, int length, Color color, int x, int y) {
64 width= drawAndComputeWidth(gc, textWidget, offset, length, color, x, y);
65 }
66
67 /**
68 * Draw the inlined annotation. By default it draws the text of the annotation with gray color.
69 * User can override this method to draw anything.
70 *
71 * @param gc the graphics context
72 * @param textWidget the text widget to draw on
73 * @param offset the offset of the line
74 * @param length the length of the line
75 * @param color the color of the line
76 * @param x the x position of the annotation
77 * @param y the y position of the annotation
78 * @return the text width.
79 */
80 protected int drawAndComputeWidth(GC gc, StyledText textWidget, int offset, int length, Color color, int x, int y) {
81 // Draw the text annotation and returns the width
82 super.draw(gc, textWidget, offset, length, color, x, y);
83 return (int) (gc.stringExtent(getText()).x + 2 * gc.getFontMetrics().getAverageCharacterWidth());
84 }
85
86 int getRedrawnCharacterWidth() {
87 return redrawnCharacterWidth;
88 }
89
90 void setRedrawnCharacterWidth(int redrawnCharacterWidth) {
91 this.redrawnCharacterWidth= redrawnCharacterWidth;
92 }
93
94 @Override
95 boolean contains(int x, int y) {
96 return (x >= this.fX && x <= this.fX + width && y >= this.fY && y <= this.fY + getTextWidget().getLineHeight());
97 }
98
99 }
8 * SPDX-License-Identifier: EPL-2.0
9 *
10 * Contributors:
11 * Angelo Zerr <angelo.zerr@gmail.com> - [CodeMining] Provide inline annotations support - Bug 527675
12 */
13 package org.eclipse.jface.text.source.inlined;
14
15 import org.eclipse.swt.custom.StyleRange;
16 import org.eclipse.swt.custom.StyledText;
17 import org.eclipse.swt.graphics.Color;
18 import org.eclipse.swt.graphics.GC;
19 import org.eclipse.swt.graphics.GlyphMetrics;
20
21 import org.eclipse.jface.text.ITextViewerExtension5;
22 import org.eclipse.jface.text.Position;
23 import org.eclipse.jface.text.TextPresentation;
24 import org.eclipse.jface.text.source.ISourceViewer;
25
26 /**
27 * Inlined annotation which is drawn in the line content and which takes some place with a given
28 * width.
29 *
30 * @since 3.13
31 */
32 public class LineContentAnnotation extends AbstractInlinedAnnotation {
33
34 /**
35 * The annotation width
36 */
37 private int width;
38
39 private int redrawnCharacterWidth;
40
41 /**
42 * Line content annotation constructor.
43 *
44 * @param position the position where the annotation must be drawn.
45 * @param viewer the {@link ISourceViewer} where the annotation must be drawn.
46 */
47 public LineContentAnnotation(Position position, ISourceViewer viewer) {
48 super(position, viewer);
49 }
50
51 /**
52 * Returns the annotation width. By default it computes the well width for the text annotation.
53 *
54 * @return the annotation width.
55 */
56 public final int getWidth() {
57 return width;
58 }
59
60 /**
61 * {@inheritDoc}
62 * <p>
63 * After drawn, compute the text width and update it.
64 * </p>
65 */
66 @Override
67 public final void draw(GC gc, StyledText textWidget, int offset, int length, Color color, int x, int y) {
68 width= drawAndComputeWidth(gc, textWidget, offset, length, color, x, y);
69 }
70
71 /**
72 * Draw the inlined annotation. By default it draws the text of the annotation with gray color.
73 * User can override this method to draw anything.
74 *
75 * @param gc the graphics context
76 * @param textWidget the text widget to draw on
77 * @param offset the offset of the line
78 * @param length the length of the line
79 * @param color the color of the line
80 * @param x the x position of the annotation
81 * @param y the y position of the annotation
82 * @return the text width.
83 */
84 protected int drawAndComputeWidth(GC gc, StyledText textWidget, int offset, int length, Color color, int x, int y) {
85 // Draw the text annotation and returns the width
86 super.draw(gc, textWidget, offset, length, color, x, y);
87 return (int) (gc.stringExtent(getText()).x + 2 * gc.getFontMetrics().getAverageCharacterWidth());
88 }
89
90 int getRedrawnCharacterWidth() {
91 return redrawnCharacterWidth;
92 }
93
94 void setRedrawnCharacterWidth(int redrawnCharacterWidth) {
95 this.redrawnCharacterWidth= redrawnCharacterWidth;
96 }
97
98 @Override
99 boolean contains(int x, int y) {
100 return (x >= this.fX && x <= this.fX + width && y >= this.fY && y <= this.fY + getTextWidget().getLineHeight());
101 }
102
103 /**
104 * Returns the style to apply with GlyphMetrics width only if needed.
105 *
106 * As it's using Widget position, the results can be passed directly to
107 * {@link StyledText#setStyleRange(StyleRange)} and family. However, in case of a Viewer
108 * providing project/folder with {@link ITextViewerExtension5}, the range must be transformed to
109 * model position before passing it to a {@link TextPresentation}.
110 *
111 * @param style the current style and null otherwise.
112 * @return the style to apply with GlyphMetrics width only if needed. It uses widget position,
113 * not model position.
114 */
115 StyleRange updateStyle(StyleRange style) {
116 Position widgetPosition= computeWidgetPosition();
117 boolean usePreviousChar= drawRightToPreviousChar(widgetPosition.getOffset());
118 if (width == 0 || getRedrawnCharacterWidth() == 0) {
119 return null;
120 }
121 int fullWidth= width + getRedrawnCharacterWidth();
122 if (style == null) {
123 style= new StyleRange();
124 style.start= widgetPosition.getOffset();
125 if (usePreviousChar) {
126 style.start--;
127 }
128 style.length= 1;
129 }
130 GlyphMetrics metrics= style.metrics;
131 if (!isMarkedDeleted()) {
132 if (metrics == null) {
133 metrics= new GlyphMetrics(0, 0, fullWidth);
134 } else {
135 if (metrics.width == fullWidth) {
136 return null;
137 }
138 /**
139 * We must create a new GlyphMetrics instance because comparison with similarTo used
140 * later in StyledText#setStyleRange will compare the same (modified) and won't
141 * realize an update happened.
142 */
143 metrics= new GlyphMetrics(0, 0, fullWidth);
144 }
145 } else {
146 metrics= null;
147 }
148 style.metrics= metrics;
149 return style;
150 }
151
152 boolean drawRightToPreviousChar(int widgetOffset) {
153 return widgetOffset > 0 && getTextWidget().getLineAtOffset(widgetOffset) == getTextWidget().getLineAtOffset(widgetOffset - 1);
154 }
155
156 }
0 /**
1 * Copyright (c) 2017, 2018 Angelo ZERR.
2 *
3 * This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License 2.0
5 * which accompanies this distribution, and is available at
6 * https://www.eclipse.org/legal/epl-2.0/
7 *
8 * SPDX-License-Identifier: EPL-2.0
9 *
10 * Contributors:
11 * Angelo Zerr <angelo.zerr@gmail.com> - [CodeMining] Provide inline annotations support - Bug 527675
12 */
13 package org.eclipse.jface.text.source.inlined;
14
15 import org.eclipse.swt.custom.StyledText;
16
17 import org.eclipse.jface.text.Position;
18 import org.eclipse.jface.text.source.ISourceViewer;
19
20 /**
21 * Inlined annotation which is drawn before a line and which takes some place with a given height.
22 *
23 * @since 3.13
24 */
25 public class LineHeaderAnnotation extends AbstractInlinedAnnotation {
26
27 int oldLine;
28
29 /**
30 * Line header annotation constructor.
31 *
32 * @param position the position where the annotation must be drawn.
33 * @param viewer the {@link ISourceViewer} where the annotation must be drawn.
34 */
35 public LineHeaderAnnotation(Position position, ISourceViewer viewer) {
36 super(position, viewer);
37 oldLine= -1;
38 }
39
40 /**
41 * Returns the annotation height. By default, returns the {@link StyledText#getLineHeight()}.
42 *
43 * @return the annotation height.
44 */
45 public int getHeight() {
46 StyledText styledText= super.getTextWidget();
47 return styledText.getLineHeight();
48 }
49
50 @Override
51 boolean contains(int x, int y) {
52 return (x >= this.fX && y >= this.fY && y <= this.fY + getHeight());
53 }
54 }
0 /**
1 * Copyright (c) 2017, 2018 Angelo ZERR.
2 *
3 * This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License 2.0
5 * which accompanies this distribution, and is available at
6 * https://www.eclipse.org/legal/epl-2.0/
7 *
8 * SPDX-License-Identifier: EPL-2.0
9 *
10 * Contributors:
11 * Angelo Zerr <angelo.zerr@gmail.com> - [CodeMining] Provide inline annotations support - Bug 527675
12 */
13 package org.eclipse.jface.text.source.inlined;
14
15 import org.eclipse.swt.custom.StyledText;
16
17 import org.eclipse.jface.text.Position;
18 import org.eclipse.jface.text.source.ISourceViewer;
19
20 /**
21 * Inlined annotation which is drawn before a line and which takes some place with a given height.
22 *
23 * @since 3.13
24 */
25 public class LineHeaderAnnotation extends AbstractInlinedAnnotation {
26
27 int oldLine;
28
29 /**
30 * Line header annotation constructor.
31 *
32 * @param position the position where the annotation must be drawn.
33 * @param viewer the {@link ISourceViewer} where the annotation must be drawn.
34 */
35 public LineHeaderAnnotation(Position position, ISourceViewer viewer) {
36 super(position, viewer);
37 oldLine= -1;
38 }
39
40 /**
41 * Returns the annotation height. By default, returns the {@link StyledText#getLineHeight()}.
42 *
43 * @return the annotation height.
44 */
45 public int getHeight() {
46 StyledText styledText= super.getTextWidget();
47 return styledText.getLineHeight();
48 }
49
50 @Override
51 boolean contains(int x, int y) {
52 return (x >= this.fX && y >= this.fY && y <= this.fY + getHeight());
53 }
54 }
0 /**
1 * Copyright (c) 2017 Angelo ZERR.
0 /**
1 * Copyright (c) 2017 Angelo ZERR.
22 *
3 * This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License 2.0
5 * which accompanies this distribution, and is available at
3 * This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License 2.0
5 * which accompanies this distribution, and is available at
66 * https://www.eclipse.org/legal/epl-2.0/
77 *
8 * SPDX-License-Identifier: EPL-2.0
9 *
10 * Contributors:
11 * Angelo Zerr <angelo.zerr@gmail.com> - [CodeMining] Provide inline annotations support - Bug 527675
12 */
13 package org.eclipse.jface.text.source.inlined;
14
15 import org.eclipse.jface.text.BadLocationException;
16 import org.eclipse.jface.text.IDocument;
17 import org.eclipse.jface.text.Position;
18
19 /**
20 * Utilities class to retrieve position.
21 *
22 * @since 3.13
23 */
24 public class Positions {
25
26 /**
27 * Returns the line position by taking care or not of of leading spaces.
28 *
29 * @param lineIndex the line index
30 * @param document the document
31 * @param leadingSpaces true if line spacing must take care of and not otherwise.
32 * @return the line position by taking care of leading spaces.
33 * @throws BadLocationException if the line number is invalid in this document
34 */
35 public static Position of(int lineIndex, IDocument document, boolean leadingSpaces) throws BadLocationException {
36 int offset= document.getLineOffset(lineIndex);
37 int lineLength= document.getLineLength(lineIndex);
38 String line= document.get(offset, lineLength);
39 if (leadingSpaces) {
40 offset+= getLeadingSpaces(line);
41 }
42 return new Position(offset, 1);
43 }
44
45 /**
46 * Returns the leading spaces of the given line text.
47 *
48 * @param line the line text.
49 * @return the leading spaces of the given line text.
50 */
51 private static int getLeadingSpaces(String line) {
52 int counter= 0;
53 char[] chars= line.toCharArray();
54 for (char c : chars) {
55 if (c == '\t')
56 counter++;
57 else if (c == ' ')
58 counter++;
59 else
60 break;
61 }
62 return counter;
63 }
64 }
8 * SPDX-License-Identifier: EPL-2.0
9 *
10 * Contributors:
11 * Angelo Zerr <angelo.zerr@gmail.com> - [CodeMining] Provide inline annotations support - Bug 527675
12 */
13 package org.eclipse.jface.text.source.inlined;
14
15 import org.eclipse.jface.text.BadLocationException;
16 import org.eclipse.jface.text.IDocument;
17 import org.eclipse.jface.text.Position;
18
19 /**
20 * Utilities class to retrieve position.
21 *
22 * @since 3.13
23 */
24 public class Positions {
25
26 /**
27 * Returns the line position by taking care or not of of leading spaces.
28 *
29 * @param lineIndex the line index
30 * @param document the document
31 * @param leadingSpaces true if line spacing must take care of and not otherwise.
32 * @return the line position by taking care of leading spaces.
33 * @throws BadLocationException if the line number is invalid in this document
34 */
35 public static Position of(int lineIndex, IDocument document, boolean leadingSpaces) throws BadLocationException {
36 int offset= document.getLineOffset(lineIndex);
37 int lineLength= document.getLineLength(lineIndex);
38 String line= document.get(offset, lineLength);
39 if (leadingSpaces) {
40 offset+= getLeadingSpaces(line);
41 }
42 return new Position(offset, 1);
43 }
44
45 /**
46 * Returns the leading spaces of the given line text.
47 *
48 * @param line the line text.
49 * @return the leading spaces of the given line text.
50 */
51 private static int getLeadingSpaces(String line) {
52 int counter= 0;
53 char[] chars= line.toCharArray();
54 for (char c : chars) {
55 if (c == '\t')
56 counter++;
57 else if (c == ' ')
58 counter++;
59 else
60 break;
61 }
62 return counter;
63 }
64 }
280280
281281 private int getCaretOffset(TemplateBuffer buffer) {
282282
283 TemplateVariable[] variables= buffer.getVariables();
283 TemplateVariable[] variables= buffer.getVariables();
284284 for (int i= 0; i != variables.length; i++) {
285285 TemplateVariable variable= variables[i];
286286 if (variable.getType().equals(GlobalTemplateVariables.Cursor.NAME))
335335
336336 @Override
337337 public String getAdditionalProposalInfo() {
338 try {
339 fContext.setReadOnly(true);
338 try {
339 fContext.setReadOnly(true);
340340 TemplateBuffer templateBuffer;
341341 try {
342342 templateBuffer= fContext.evaluate(fTemplate);
346346
347347 return templateBuffer.getString();
348348
349 } catch (BadLocationException e) {
349 } catch (BadLocationException e) {
350350 return null;
351351 }
352352 }
1313 <parent>
1414 <artifactId>eclipse.platform.text</artifactId>
1515 <groupId>eclipse.platform.text</groupId>
16 <version>4.11.0-SNAPSHOT</version>
16 <version>4.12.0-SNAPSHOT</version>
1717 </parent>
1818 <groupId>org.eclipse.core</groupId>
1919 <artifactId>org.eclipse.jface.text.examples</artifactId>
0 /**
1 * Copyright (c) 2017 Angelo ZERR.
0 /**
1 * Copyright (c) 2017 Angelo ZERR.
22 *
3 * This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License 2.0
5 * which accompanies this distribution, and is available at
3 * This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License 2.0
5 * which accompanies this distribution, and is available at
66 * https://www.eclipse.org/legal/epl-2.0/
77 *
8 * SPDX-License-Identifier: EPL-2.0
9 *
10 * Contributors:
11 * Angelo Zerr <angelo.zerr@gmail.com> - [CodeMining] Add CodeMining support in SourceViewer - Bug 527515
12 */
13 package org.eclipse.jface.text.examples.codemining;
14
15 import org.eclipse.jface.text.BadLocationException;
16 import org.eclipse.jface.text.IDocument;
17 import org.eclipse.jface.text.codemining.ICodeMiningProvider;
18 import org.eclipse.jface.text.codemining.LineHeaderCodeMining;
19
20 /**
21 * Abstract class for class name mining.
22 *
23 */
24 public abstract class AbstractClassCodeMining extends LineHeaderCodeMining {
25
26 private final String className;
27
28 public AbstractClassCodeMining(String className, int afterLineNumber, IDocument document,
29 ICodeMiningProvider resolver) throws BadLocationException {
30 super(afterLineNumber, document, resolver);
31 this.className = className;
32 }
33
34 public String getClassName() {
35 return className;
36 }
37
38 public static String getLineText(IDocument document, int line) {
39 try {
40 int lo = document.getLineOffset(line);
41 int ll = document.getLineLength(line);
42 return document.get(lo, ll);
43 } catch (Exception e) {
44 e.printStackTrace();
45 return null;
46 }
47 }
48
49 }
8 * SPDX-License-Identifier: EPL-2.0
9 *
10 * Contributors:
11 * Angelo Zerr <angelo.zerr@gmail.com> - [CodeMining] Add CodeMining support in SourceViewer - Bug 527515
12 */
13 package org.eclipse.jface.text.examples.codemining;
14
15 import org.eclipse.jface.text.BadLocationException;
16 import org.eclipse.jface.text.IDocument;
17 import org.eclipse.jface.text.codemining.ICodeMiningProvider;
18 import org.eclipse.jface.text.codemining.LineHeaderCodeMining;
19
20 /**
21 * Abstract class for class name mining.
22 *
23 */
24 public abstract class AbstractClassCodeMining extends LineHeaderCodeMining {
25
26 private final String className;
27
28 public AbstractClassCodeMining(String className, int afterLineNumber, IDocument document,
29 ICodeMiningProvider resolver) throws BadLocationException {
30 super(afterLineNumber, document, resolver);
31 this.className = className;
32 }
33
34 public String getClassName() {
35 return className;
36 }
37
38 public static String getLineText(IDocument document, int line) {
39 try {
40 int lo = document.getLineOffset(line);
41 int ll = document.getLineLength(line);
42 return document.get(lo, ll);
43 } catch (Exception e) {
44 e.printStackTrace();
45 return null;
46 }
47 }
48
49 }
0 /**
1 * Copyright (c) 2017 Angelo ZERR.
0 /**
1 * Copyright (c) 2017 Angelo ZERR.
22 *
3 * This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License 2.0
5 * which accompanies this distribution, and is available at
3 * This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License 2.0
5 * which accompanies this distribution, and is available at
66 * https://www.eclipse.org/legal/epl-2.0/
77 *
8 * SPDX-License-Identifier: EPL-2.0
9 *
10 * Contributors:
11 * Angelo Zerr <angelo.zerr@gmail.com> - [CodeMining] Add CodeMining support in SourceViewer - Bug 527515
12 */
13 package org.eclipse.jface.text.examples.codemining;
14
15 import java.util.concurrent.CompletableFuture;
16
17 import org.eclipse.core.runtime.IProgressMonitor;
18 import org.eclipse.jface.text.BadLocationException;
19 import org.eclipse.jface.text.IDocument;
20 import org.eclipse.jface.text.ITextViewer;
21 import org.eclipse.jface.text.codemining.ICodeMiningProvider;
22
23 /**
24 * Class implementation mining.
25 *
26 */
27 public class ClassImplementationCodeMining extends AbstractClassCodeMining {
28
29 public ClassImplementationCodeMining(String className, int afterLineNumber, IDocument document,
30 ICodeMiningProvider provider) throws BadLocationException {
31 super(className, afterLineNumber, document, provider);
32 }
33
34 @Override
35 protected CompletableFuture<Void> doResolve(ITextViewer viewer, IProgressMonitor monitor) {
36 return CompletableFuture.runAsync(() -> {
37 IDocument document = viewer.getDocument();
38 String className = super.getClassName();
39 int refCount = 0;
40 int lineCount = document.getNumberOfLines();
41 for (int i = 0; i < lineCount; i++) {
42 // check if request was canceled.
43 monitor.isCanceled();
44 String line = getLineText(document, i);
45 refCount += line.contains("implements " + className) ? 1 : 0;
46 }
47 super.setLabel(refCount + " implementation");
48 });
49 }
50
51 }
8 * SPDX-License-Identifier: EPL-2.0
9 *
10 * Contributors:
11 * Angelo Zerr <angelo.zerr@gmail.com> - [CodeMining] Add CodeMining support in SourceViewer - Bug 527515
12 */
13 package org.eclipse.jface.text.examples.codemining;
14
15 import java.util.concurrent.CompletableFuture;
16
17 import org.eclipse.core.runtime.IProgressMonitor;
18 import org.eclipse.jface.text.BadLocationException;
19 import org.eclipse.jface.text.IDocument;
20 import org.eclipse.jface.text.ITextViewer;
21 import org.eclipse.jface.text.codemining.ICodeMiningProvider;
22
23 /**
24 * Class implementation mining.
25 *
26 */
27 public class ClassImplementationCodeMining extends AbstractClassCodeMining {
28
29 public ClassImplementationCodeMining(String className, int afterLineNumber, IDocument document,
30 ICodeMiningProvider provider) throws BadLocationException {
31 super(className, afterLineNumber, document, provider);
32 }
33
34 @Override
35 protected CompletableFuture<Void> doResolve(ITextViewer viewer, IProgressMonitor monitor) {
36 return CompletableFuture.runAsync(() -> {
37 IDocument document = viewer.getDocument();
38 String className = super.getClassName();
39 int refCount = 0;
40 int lineCount = document.getNumberOfLines();
41 for (int i = 0; i < lineCount; i++) {
42 // check if request was canceled.
43 monitor.isCanceled();
44 String line = getLineText(document, i);
45 refCount += line.contains("implements " + className) ? 1 : 0;
46 }
47 super.setLabel(refCount + " implementation");
48 });
49 }
50
51 }
0 /**
1 * Copyright (c) 2017 Angelo ZERR.
0 /**
1 * Copyright (c) 2017 Angelo ZERR.
22 *
3 * This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License 2.0
5 * which accompanies this distribution, and is available at
3 * This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License 2.0
5 * which accompanies this distribution, and is available at
66 * https://www.eclipse.org/legal/epl-2.0/
77 *
8 * SPDX-License-Identifier: EPL-2.0
9 *
10 * Contributors:
11 * Angelo Zerr <angelo.zerr@gmail.com> - [CodeMining] Add CodeMining support in SourceViewer - Bug 527515
12 */
13 package org.eclipse.jface.text.examples.codemining;
14
15 import java.util.ArrayList;
16 import java.util.List;
17 import java.util.concurrent.CompletableFuture;
18
19 import org.eclipse.core.runtime.IProgressMonitor;
20 import org.eclipse.jface.text.BadLocationException;
21 import org.eclipse.jface.text.IDocument;
22 import org.eclipse.jface.text.ITextViewer;
23 import org.eclipse.jface.text.codemining.AbstractCodeMiningProvider;
24 import org.eclipse.jface.text.codemining.ICodeMining;
25
26 /**
27 * Class implementation mining provider.
28 *
29 */
30 public class ClassImplementationsCodeMiningProvider extends AbstractCodeMiningProvider {
31
32 @Override
33 public CompletableFuture<List<? extends ICodeMining>> provideCodeMinings(ITextViewer viewer,
34 IProgressMonitor monitor) {
35 return CompletableFuture.supplyAsync(() -> {
36 IDocument document = viewer.getDocument();
37 List<ICodeMining> lenses = new ArrayList<>();
38 int lineCount = document.getNumberOfLines();
39 for (int i = 0; i < lineCount; i++) {
40 // check if request was canceled.
41 monitor.isCanceled();
42 updateContentMining(i, document, "class ", lenses);
43 updateContentMining(i, document, "interface ", lenses);
44 }
45 return lenses;
46 });
47 }
48
49 private void updateContentMining(int lineIndex, IDocument document, String token, List<ICodeMining> lenses) {
50 String line = AbstractClassCodeMining.getLineText(document, lineIndex).trim();
51 int index = line.indexOf(token);
52 if (index == 0) {
53 String className = line.substring(index + token.length(), line.length());
54 index = className.indexOf(" ");
55 if (index != -1) {
56 className = className.substring(0, index);
57 }
58 if (className.length() > 0) {
59 try {
60 lenses.add(new ClassImplementationCodeMining(className, lineIndex, document, this));
61 } catch (BadLocationException e) {
62 e.printStackTrace();
63 }
64 }
65 }
66 }
67
68 }
8 * SPDX-License-Identifier: EPL-2.0
9 *
10 * Contributors:
11 * Angelo Zerr <angelo.zerr@gmail.com> - [CodeMining] Add CodeMining support in SourceViewer - Bug 527515
12 */
13 package org.eclipse.jface.text.examples.codemining;
14
15 import java.util.ArrayList;
16 import java.util.List;
17 import java.util.concurrent.CompletableFuture;
18
19 import org.eclipse.core.runtime.IProgressMonitor;
20 import org.eclipse.jface.text.BadLocationException;
21 import org.eclipse.jface.text.IDocument;
22 import org.eclipse.jface.text.ITextViewer;
23 import org.eclipse.jface.text.codemining.AbstractCodeMiningProvider;
24 import org.eclipse.jface.text.codemining.ICodeMining;
25
26 /**
27 * Class implementation mining provider.
28 *
29 */
30 public class ClassImplementationsCodeMiningProvider extends AbstractCodeMiningProvider {
31
32 @Override
33 public CompletableFuture<List<? extends ICodeMining>> provideCodeMinings(ITextViewer viewer,
34 IProgressMonitor monitor) {
35 return CompletableFuture.supplyAsync(() -> {
36 IDocument document = viewer.getDocument();
37 List<ICodeMining> lenses = new ArrayList<>();
38 int lineCount = document.getNumberOfLines();
39 for (int i = 0; i < lineCount; i++) {
40 // check if request was canceled.
41 monitor.isCanceled();
42 updateContentMining(i, document, "class ", lenses);
43 updateContentMining(i, document, "interface ", lenses);
44 }
45 return lenses;
46 });
47 }
48
49 private void updateContentMining(int lineIndex, IDocument document, String token, List<ICodeMining> lenses) {
50 String line = AbstractClassCodeMining.getLineText(document, lineIndex).trim();
51 int index = line.indexOf(token);
52 if (index == 0) {
53 String className = line.substring(index + token.length(), line.length());
54 index = className.indexOf(" ");
55 if (index != -1) {
56 className = className.substring(0, index);
57 }
58 if (className.length() > 0) {
59 try {
60 lenses.add(new ClassImplementationCodeMining(className, lineIndex, document, this));
61 } catch (BadLocationException e) {
62 e.printStackTrace();
63 }
64 }
65 }
66 }
67
68 }
0 /**
1 * Copyright (c) 2017 Angelo ZERR.
0 /**
1 * Copyright (c) 2017 Angelo ZERR.
22 *
3 * This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License 2.0
5 * which accompanies this distribution, and is available at
3 * This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License 2.0
5 * which accompanies this distribution, and is available at
66 * https://www.eclipse.org/legal/epl-2.0/
77 *
8 * SPDX-License-Identifier: EPL-2.0
9 *
10 * Contributors:
11 * Angelo Zerr <angelo.zerr@gmail.com> - [CodeMining] Add CodeMining support in SourceViewer - Bug 527515
12 */
13 package org.eclipse.jface.text.examples.codemining;
14
15 import java.util.concurrent.CancellationException;
16 import java.util.concurrent.CompletableFuture;
17
18 import org.eclipse.core.runtime.IProgressMonitor;
19 import org.eclipse.jface.text.BadLocationException;
20 import org.eclipse.jface.text.IDocument;
21 import org.eclipse.jface.text.ITextViewer;
22 import org.eclipse.jface.text.codemining.ICodeMiningProvider;
23
24 /**
25 * Class reference mining.
26 *
27 */
28 public class ClassReferenceCodeMining extends AbstractClassCodeMining {
29
30 private Object lock = new Object();
31
32 public ClassReferenceCodeMining(String className, int afterLineNumber, IDocument document, ICodeMiningProvider provider)
33 throws BadLocationException {
34 super(className, afterLineNumber, document, provider);
35 }
36
37 @Override
38 protected CompletableFuture<Void> doResolve(ITextViewer viewer, IProgressMonitor monitor) {
39 return CompletableFuture.runAsync(() -> {
40 IDocument document = viewer.getDocument();
41 String className = super.getClassName();
42 try {
43 int wait = Integer.parseInt(className);
44 try {
45 for (int i = 0; i < wait; i++) {
46 monitor.isCanceled();
47 synchronized (lock) {
48 lock.wait(1000);
49 }
50 }
51 } catch (InterruptedException e) {
52 Thread.currentThread().interrupt();
53 }
54 } catch (NumberFormatException e) {
55
56 } catch (CancellationException e) {
57 e.printStackTrace();
58 throw e;
59 }
60
61 int refCount = 0;
62 int lineCount = document.getNumberOfLines();
63 for (int i = 0; i < lineCount; i++) {
64 // check if request was canceled.
65 monitor.isCanceled();
66 String line = getLineText(document, i);
67 refCount += line.contains("new " + className) ? 1 : 0;
68 }
69 super.setLabel(refCount + " references");
70 });
71 }
72
73 }
8 * SPDX-License-Identifier: EPL-2.0
9 *
10 * Contributors:
11 * Angelo Zerr <angelo.zerr@gmail.com> - [CodeMining] Add CodeMining support in SourceViewer - Bug 527515
12 */
13 package org.eclipse.jface.text.examples.codemining;
14
15 import java.util.concurrent.CancellationException;
16 import java.util.concurrent.CompletableFuture;
17
18 import org.eclipse.core.runtime.IProgressMonitor;
19 import org.eclipse.jface.text.BadLocationException;
20 import org.eclipse.jface.text.IDocument;
21 import org.eclipse.jface.text.ITextViewer;
22 import org.eclipse.jface.text.codemining.ICodeMiningProvider;
23
24 /**
25 * Class reference mining.
26 *
27 */
28 public class ClassReferenceCodeMining extends AbstractClassCodeMining {
29
30 private Object lock = new Object();
31
32 public ClassReferenceCodeMining(String className, int afterLineNumber, IDocument document, ICodeMiningProvider provider)
33 throws BadLocationException {
34 super(className, afterLineNumber, document, provider);
35 }
36
37 @Override
38 protected CompletableFuture<Void> doResolve(ITextViewer viewer, IProgressMonitor monitor) {
39 return CompletableFuture.runAsync(() -> {
40 IDocument document = viewer.getDocument();
41 String className = super.getClassName();
42 try {
43 int wait = Integer.parseInt(className);
44 try {
45 for (int i = 0; i < wait; i++) {
46 monitor.isCanceled();
47 synchronized (lock) {
48 lock.wait(1000);
49 }
50 }
51 } catch (InterruptedException e) {
52 Thread.currentThread().interrupt();
53 }
54 } catch (NumberFormatException e) {
55
56 } catch (CancellationException e) {
57 e.printStackTrace();
58 throw e;
59 }
60
61 int refCount = 0;
62 int lineCount = document.getNumberOfLines();
63 for (int i = 0; i < lineCount; i++) {
64 // check if request was canceled.
65 monitor.isCanceled();
66 String line = getLineText(document, i);
67 refCount += line.contains("new " + className) ? 1 : 0;
68 }
69 super.setLabel(refCount + " references");
70 });
71 }
72
73 }
0 /**
1 * Copyright (c) 2017 Angelo ZERR.
0 /**
1 * Copyright (c) 2017 Angelo ZERR.
22 *
3 * This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License 2.0
5 * which accompanies this distribution, and is available at
3 * This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License 2.0
5 * which accompanies this distribution, and is available at
66 * https://www.eclipse.org/legal/epl-2.0/
77 *
8 * SPDX-License-Identifier: EPL-2.0
9 *
10 * Contributors:
11 * Angelo Zerr <angelo.zerr@gmail.com> - [CodeMining] Add CodeMining support in SourceViewer - Bug 527515
12 */
13 package org.eclipse.jface.text.examples.codemining;
14
15 import java.util.ArrayList;
16 import java.util.List;
17 import java.util.concurrent.CompletableFuture;
18
19 import org.eclipse.core.runtime.IProgressMonitor;
20 import org.eclipse.jface.text.BadLocationException;
21 import org.eclipse.jface.text.IDocument;
22 import org.eclipse.jface.text.ITextViewer;
23 import org.eclipse.jface.text.codemining.AbstractCodeMiningProvider;
24 import org.eclipse.jface.text.codemining.ICodeMining;
25
26 /**
27 * Class reference mining provider.
28 *
29 */
30 public class ClassReferenceCodeMiningProvider extends AbstractCodeMiningProvider {
31
32 @Override
33 public CompletableFuture<List<? extends ICodeMining>> provideCodeMinings(ITextViewer viewer,
34 IProgressMonitor monitor) {
35 return CompletableFuture.supplyAsync(() -> {
36 IDocument document = viewer.getDocument();
37 List<ICodeMining> lenses = new ArrayList<>();
38 int lineCount = document.getNumberOfLines();
39 for (int i = 0; i < lineCount; i++) {
40 // check if request was canceled.
41 monitor.isCanceled();
42 String line = AbstractClassCodeMining.getLineText(document, i).trim();
43 int index = line.indexOf("class ");
44 if (index == 0) {
45 String className = line.substring(index + "class ".length(), line.length()).trim();
46 if (className.length() > 0) {
47 try {
48 lenses.add(new ClassReferenceCodeMining(className, i, document, this));
49 } catch (BadLocationException e) {
50 e.printStackTrace();
51 }
52 }
53 }
54 }
55 return lenses;
56 });
57 }
58
59 }
8 * SPDX-License-Identifier: EPL-2.0
9 *
10 * Contributors:
11 * Angelo Zerr <angelo.zerr@gmail.com> - [CodeMining] Add CodeMining support in SourceViewer - Bug 527515
12 */
13 package org.eclipse.jface.text.examples.codemining;
14
15 import java.util.ArrayList;
16 import java.util.List;
17 import java.util.concurrent.CompletableFuture;
18
19 import org.eclipse.core.runtime.IProgressMonitor;
20 import org.eclipse.jface.text.BadLocationException;
21 import org.eclipse.jface.text.IDocument;
22 import org.eclipse.jface.text.ITextViewer;
23 import org.eclipse.jface.text.codemining.AbstractCodeMiningProvider;
24 import org.eclipse.jface.text.codemining.ICodeMining;
25
26 /**
27 * Class reference mining provider.
28 *
29 */
30 public class ClassReferenceCodeMiningProvider extends AbstractCodeMiningProvider {
31
32 @Override
33 public CompletableFuture<List<? extends ICodeMining>> provideCodeMinings(ITextViewer viewer,
34 IProgressMonitor monitor) {
35 return CompletableFuture.supplyAsync(() -> {
36 IDocument document = viewer.getDocument();
37 List<ICodeMining> lenses = new ArrayList<>();
38 int lineCount = document.getNumberOfLines();
39 for (int i = 0; i < lineCount; i++) {
40 // check if request was canceled.
41 monitor.isCanceled();
42 String line = AbstractClassCodeMining.getLineText(document, i).trim();
43 int index = line.indexOf("class ");
44 if (index == 0) {
45 String className = line.substring(index + "class ".length(), line.length()).trim();
46 if (className.length() > 0) {
47 try {
48 lenses.add(new ClassReferenceCodeMining(className, i, document, this));
49 } catch (BadLocationException e) {
50 e.printStackTrace();
51 }
52 }
53 }
54 }
55 return lenses;
56 });
57 }
58
59 }
0 /**
1 * Copyright (c) 2017 Angelo ZERR.
0 /**
1 * Copyright (c) 2017 Angelo ZERR.
22 *
3 * This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License 2.0
5 * which accompanies this distribution, and is available at
3 * This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License 2.0
5 * which accompanies this distribution, and is available at
66 * https://www.eclipse.org/legal/epl-2.0/
77 *
8 * SPDX-License-Identifier: EPL-2.0
9 *
10 * Contributors:
11 * Angelo Zerr <angelo.zerr@gmail.com> - [CodeMining] Add CodeMining support in SourceViewer - Bug 527515
12 */
13 package org.eclipse.jface.text.examples.codemining;
14
15 import org.eclipse.jface.text.Document;
16 import org.eclipse.jface.text.IDocument;
17 import org.eclipse.jface.text.IRegion;
18 import org.eclipse.jface.text.ITextViewerExtension2;
19 import org.eclipse.jface.text.codemining.ICodeMiningProvider;
20 import org.eclipse.jface.text.reconciler.DirtyRegion;
21 import org.eclipse.jface.text.reconciler.IReconcilingStrategy;
22 import org.eclipse.jface.text.reconciler.MonoReconciler;
23 import org.eclipse.jface.text.source.Annotation;
24 import org.eclipse.jface.text.source.AnnotationModel;
25 import org.eclipse.jface.text.source.AnnotationPainter;
26 import org.eclipse.jface.text.source.IAnnotationAccess;
27 import org.eclipse.jface.text.source.ISourceViewer;
28 import org.eclipse.jface.text.source.ISourceViewerExtension5;
29 import org.eclipse.jface.text.source.SourceViewer;
30 import org.eclipse.swt.SWT;
31 import org.eclipse.swt.layout.FillLayout;
32 import org.eclipse.swt.widgets.Display;
33 import org.eclipse.swt.widgets.Shell;
34
35 /**
36 * A Code Mining demo with class references and implementations minings.
37 *
38 */
39 public class CodeMiningDemo {
40
41 public static void main(String[] args) throws Exception {
42
43 Display display = new Display();
44 Shell shell = new Shell(display);
45 shell.setLayout(new FillLayout());
46 shell.setText("Code Mining demo");
47
48 ISourceViewer sourceViewer = new SourceViewer(shell, null, SWT.V_SCROLL | SWT.BORDER);
49 sourceViewer.setDocument(
50 new Document("// Type class & new keyword and see references CodeMining\n"
51 + "// Name class with a number N to emulate Nms before resolving the references CodeMining \n\n"
52 + "class A\n" + "new A\n" + "new A\n\n" + "class 5\n" + "new 5\n" + "new 5\n" + "new 5"),
53 new AnnotationModel());
54 // Add AnnotationPainter (required by CodeMining)
55 addAnnotationPainter(sourceViewer);
56 // Initialize codemining providers
57 ((ISourceViewerExtension5) sourceViewer).setCodeMiningProviders(new ICodeMiningProvider[] {
58 new ClassReferenceCodeMiningProvider(), new ClassImplementationsCodeMiningProvider() });
59 // Execute codemining in a reconciler
60 MonoReconciler reconciler = new MonoReconciler(new IReconcilingStrategy() {
61
62 @Override
63 public void setDocument(IDocument document) {
64 ((ISourceViewerExtension5) sourceViewer).updateCodeMinings();
65 }
66
67 @Override
68 public void reconcile(DirtyRegion dirtyRegion, IRegion subRegion) {
69
70 }
71
72 @Override
73 public void reconcile(IRegion partition) {
74 ((ISourceViewerExtension5) sourceViewer).updateCodeMinings();
75 }
76 }, false);
77 reconciler.install(sourceViewer);
78
79 shell.open();
80 while (!shell.isDisposed()) {
81 if (!display.readAndDispatch())
82 display.sleep();
83 }
84 display.dispose();
85 }
86
87 private static void addAnnotationPainter(ISourceViewer viewer) {
88 IAnnotationAccess annotationAccess = new IAnnotationAccess() {
89 @Override
90 public Object getType(Annotation annotation) {
91 return annotation.getType();
92 }
93
94 @Override
95 public boolean isMultiLine(Annotation annotation) {
96 return true;
97 }
98
99 @Override
100 public boolean isTemporary(Annotation annotation) {
101 return true;
102 }
103
104 };
105 AnnotationPainter painter = new AnnotationPainter(viewer, annotationAccess);
106 ((ITextViewerExtension2) viewer).addPainter(painter);
107 // Register this annotation painter as CodeMining annotation painter.
108 ((ISourceViewerExtension5) viewer).setCodeMiningAnnotationPainter(painter);
109 }
110
111 }
8 * SPDX-License-Identifier: EPL-2.0
9 *
10 * Contributors:
11 * Angelo Zerr <angelo.zerr@gmail.com> - [CodeMining] Add CodeMining support in SourceViewer - Bug 527515
12 */
13 package org.eclipse.jface.text.examples.codemining;
14
15 import org.eclipse.jface.text.Document;
16 import org.eclipse.jface.text.IDocument;
17 import org.eclipse.jface.text.IRegion;
18 import org.eclipse.jface.text.ITextViewerExtension2;
19 import org.eclipse.jface.text.codemining.ICodeMiningProvider;
20 import org.eclipse.jface.text.reconciler.DirtyRegion;
21 import org.eclipse.jface.text.reconciler.IReconcilingStrategy;
22 import org.eclipse.jface.text.reconciler.MonoReconciler;
23 import org.eclipse.jface.text.source.Annotation;
24 import org.eclipse.jface.text.source.AnnotationModel;
25 import org.eclipse.jface.text.source.AnnotationPainter;
26 import org.eclipse.jface.text.source.IAnnotationAccess;
27 import org.eclipse.jface.text.source.ISourceViewer;
28 import org.eclipse.jface.text.source.ISourceViewerExtension5;
29 import org.eclipse.jface.text.source.SourceViewer;
30 import org.eclipse.swt.SWT;
31 import org.eclipse.swt.layout.FillLayout;
32 import org.eclipse.swt.widgets.Display;
33 import org.eclipse.swt.widgets.Shell;
34
35 /**
36 * A Code Mining demo with class references and implementations minings.
37 *
38 */
39 public class CodeMiningDemo {
40
41 public static void main(String[] args) throws Exception {
42
43 Display display = new Display();
44 Shell shell = new Shell(display);
45 shell.setLayout(new FillLayout());
46 shell.setText("Code Mining demo");
47
48 ISourceViewer sourceViewer = new SourceViewer(shell, null, SWT.V_SCROLL | SWT.BORDER);
49 sourceViewer.setDocument(
50 new Document("// Type class & new keyword and see references CodeMining\n"
51 + "// Name class with a number N to emulate Nms before resolving the references CodeMining \n\n"
52 + "class A\n" + "new A\n" + "new A\n\n" + "class 5\n" + "new 5\n" + "new 5\n" + "new 5"),
53 new AnnotationModel());
54 // Add AnnotationPainter (required by CodeMining)
55 addAnnotationPainter(sourceViewer);
56 // Initialize codemining providers
57 ((ISourceViewerExtension5) sourceViewer).setCodeMiningProviders(new ICodeMiningProvider[] {
58 new ClassReferenceCodeMiningProvider(), new ClassImplementationsCodeMiningProvider() });
59 // Execute codemining in a reconciler
60 MonoReconciler reconciler = new MonoReconciler(new IReconcilingStrategy() {
61
62 @Override
63 public void setDocument(IDocument document) {
64 ((ISourceViewerExtension5) sourceViewer).updateCodeMinings();
65 }
66
67 @Override
68 public void reconcile(DirtyRegion dirtyRegion, IRegion subRegion) {
69
70 }
71
72 @Override
73 public void reconcile(IRegion partition) {
74 ((ISourceViewerExtension5) sourceViewer).updateCodeMinings();
75 }
76 }, false);
77 reconciler.install(sourceViewer);
78
79 shell.open();
80 while (!shell.isDisposed()) {
81 if (!display.readAndDispatch())
82 display.sleep();
83 }
84 display.dispose();
85 }
86
87 private static void addAnnotationPainter(ISourceViewer viewer) {
88 IAnnotationAccess annotationAccess = new IAnnotationAccess() {
89 @Override
90 public Object getType(Annotation annotation) {
91 return annotation.getType();
92 }
93
94 @Override
95 public boolean isMultiLine(Annotation annotation) {
96 return true;
97 }
98
99 @Override
100 public boolean isTemporary(Annotation annotation) {
101 return true;
102 }
103
104 };
105 AnnotationPainter painter = new AnnotationPainter(viewer, annotationAccess);
106 ((ITextViewerExtension2) viewer).addPainter(painter);
107 // Register this annotation painter as CodeMining annotation painter.
108 ((ISourceViewerExtension5) viewer).setCodeMiningAnnotationPainter(painter);
109 }
110
111 }
0 /**s
1 * Copyright (c) 2017 Angelo ZERR.
0 /**s
1 * Copyright (c) 2017 Angelo ZERR.
22 *
3 * This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License 2.0
5 * which accompanies this distribution, and is available at
3 * This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License 2.0
5 * which accompanies this distribution, and is available at
66 * https://www.eclipse.org/legal/epl-2.0/
77 *
8 * SPDX-License-Identifier: EPL-2.0
9 *
10 * Contributors:
11 * Angelo Zerr <angelo.zerr@gmail.com> - [CodeMining] Provide inline annotations support - Bug 527675
12 */
13 package org.eclipse.jface.text.examples.sources.inlined;
14
15 import java.util.function.Consumer;
16
17 import org.eclipse.jface.text.BadLocationException;
18 import org.eclipse.jface.text.IDocument;
19 import org.eclipse.jface.text.IRegion;
20 import org.eclipse.jface.text.Position;
21 import org.eclipse.jface.text.source.ISourceViewer;
22 import org.eclipse.jface.text.source.inlined.LineContentAnnotation;
23 import org.eclipse.jface.util.Geometry;
24 import org.eclipse.swt.custom.StyledText;
25 import org.eclipse.swt.events.MouseEvent;
26 import org.eclipse.swt.graphics.Color;
27 import org.eclipse.swt.graphics.FontMetrics;
28 import org.eclipse.swt.graphics.GC;
29 import org.eclipse.swt.graphics.RGB;
30 import org.eclipse.swt.graphics.Rectangle;
31 import org.eclipse.swt.widgets.ColorDialog;
32 import org.eclipse.swt.widgets.Shell;
33
34 /**
35 * Color annotation displays a colorized square before the rgb declaration.
36 */
37 public class ColorAnnotation extends LineContentAnnotation {
38
39 private Color color;
40
41 private Consumer<MouseEvent> action = e -> {
42 StyledText styledText = super.getTextWidget();
43 Shell shell = new Shell(styledText.getDisplay());
44 Rectangle location = Geometry.toDisplay(styledText, new Rectangle(e.x, e.y, 1, 1));
45 shell.setLocation(location.x, location.y);
46 // Open color dialog
47 ColorDialog dialog = new ColorDialog(shell);
48 // dialog.setRGB(annotation.getRGBA().rgb);
49 RGB color = dialog.open();
50 if (color != null) {
51 // Color was selected, update the viewer
52 try {
53 int offset = getPosition().getOffset();
54 IDocument document = getViewer().getDocument();
55 IRegion line = document.getLineInformation(document.getLineOfOffset(offset));
56 int length = line.getLength() - (offset - line.getOffset());
57 String rgb = formatToRGB(color);
58 document.replace(offset, length, rgb);
59 } catch (BadLocationException e1) {
60
61 }
62 }
63 };
64
65 /**
66 * Format the given rgb to hexa color.
67 *
68 * @param rgb
69 * @return the hexa color from the given rgb.
70 */
71 private static String formatToRGB(RGB rgb) {
72 return new StringBuilder("rgb(").append(rgb.red).append(",").append(rgb.green).append(",").append(rgb.blue)
73 .append(")").toString();
74 }
75
76 public ColorAnnotation(Position pos, ISourceViewer viewer) {
77 super(pos, viewer);
78 }
79
80 public void setColor(Color color) {
81 this.color = color;
82 }
83
84 @Override
85 protected int drawAndComputeWidth(GC gc, StyledText textWidget, int offset, int length, Color color, int x, int y) {
86 FontMetrics fontMetrics = gc.getFontMetrics();
87 int size = getSquareSize(fontMetrics);
88 x += fontMetrics.getLeading();
89 y += fontMetrics.getDescent();
90
91 Rectangle rect = new Rectangle(x, y, size, size);
92
93 // Fill square
94 gc.setBackground(this.color);
95 gc.fillRectangle(rect);
96
97 // Draw square box
98 gc.setForeground(textWidget.getForeground());
99 gc.drawRectangle(rect);
100 return getSquareWidth(gc.getFontMetrics());
101 }
102
103 /**
104 * Returns the colorized square size.
105 *
106 * @param fontMetrics
107 * @return the colorized square size.
108 */
109 public static int getSquareSize(FontMetrics fontMetrics) {
110 return fontMetrics.getHeight() - 2 * fontMetrics.getDescent();
111 }
112
113 /**
114 * Compute width of square
115 *
116 * @param styledText
117 * @return the width of square
118 */
119 private static int getSquareWidth(FontMetrics fontMetrics) {
120 // width = 2 spaces + size width of square
121 int width = 2 * fontMetrics.getAverageCharWidth() + getSquareSize(fontMetrics);
122 return width;
123 }
124
125 @Override
126 public Consumer<MouseEvent> getAction(MouseEvent e) {
127 return action;
128 }
129 }
8 * SPDX-License-Identifier: EPL-2.0
9 *
10 * Contributors:
11 * Angelo Zerr <angelo.zerr@gmail.com> - [CodeMining] Provide inline annotations support - Bug 527675
12 */
13 package org.eclipse.jface.text.examples.sources.inlined;
14
15 import java.util.function.Consumer;
16
17 import org.eclipse.jface.text.BadLocationException;
18 import org.eclipse.jface.text.IDocument;
19 import org.eclipse.jface.text.IRegion;
20 import org.eclipse.jface.text.Position;
21 import org.eclipse.jface.text.source.ISourceViewer;
22 import org.eclipse.jface.text.source.inlined.LineContentAnnotation;
23 import org.eclipse.jface.util.Geometry;
24 import org.eclipse.swt.custom.StyledText;
25 import org.eclipse.swt.events.MouseEvent;
26 import org.eclipse.swt.graphics.Color;
27 import org.eclipse.swt.graphics.FontMetrics;
28 import org.eclipse.swt.graphics.GC;
29 import org.eclipse.swt.graphics.RGB;
30 import org.eclipse.swt.graphics.Rectangle;
31 import org.eclipse.swt.widgets.ColorDialog;
32 import org.eclipse.swt.widgets.Shell;
33
34 /**
35 * Color annotation displays a colorized square before the rgb declaration.
36 */
37 public class ColorAnnotation extends LineContentAnnotation {
38
39 private Color color;
40
41 private Consumer<MouseEvent> action = e -> {
42 StyledText styledText = super.getTextWidget();
43 Shell shell = new Shell(styledText.getDisplay());
44 Rectangle location = Geometry.toDisplay(styledText, new Rectangle(e.x, e.y, 1, 1));
45 shell.setLocation(location.x, location.y);
46 // Open color dialog
47 ColorDialog dialog = new ColorDialog(shell);
48 // dialog.setRGB(annotation.getRGBA().rgb);
49 RGB color = dialog.open();
50 if (color != null) {
51 // Color was selected, update the viewer
52 try {
53 int offset = getPosition().getOffset();
54 IDocument document = getViewer().getDocument();
55 IRegion line = document.getLineInformation(document.getLineOfOffset(offset));
56 int length = line.getLength() - (offset - line.getOffset());
57 String rgb = formatToRGB(color);
58 document.replace(offset, length, rgb);
59 } catch (BadLocationException e1) {
60
61 }
62 }
63 };
64
65 /**
66 * Format the given rgb to hexa color.
67 *
68 * @param rgb
69 * @return the hexa color from the given rgb.
70 */
71 private static String formatToRGB(RGB rgb) {
72 return new StringBuilder("rgb(").append(rgb.red).append(",").append(rgb.green).append(",").append(rgb.blue)
73 .append(")").toString();
74 }
75
76 public ColorAnnotation(Position pos, ISourceViewer viewer) {
77 super(pos, viewer);
78 }
79
80 public void setColor(Color color) {
81 this.color = color;
82 }
83
84 @Override
85 protected int drawAndComputeWidth(GC gc, StyledText textWidget, int offset, int length, Color color, int x, int y) {
86 FontMetrics fontMetrics = gc.getFontMetrics();
87 int size = getSquareSize(fontMetrics);
88 x += fontMetrics.getLeading();
89 y += fontMetrics.getDescent();
90
91 Rectangle rect = new Rectangle(x, y, size, size);
92
93 // Fill square
94 gc.setBackground(this.color);
95 gc.fillRectangle(rect);
96
97 // Draw square box
98 gc.setForeground(textWidget.getForeground());
99 gc.drawRectangle(rect);
100 return getSquareWidth(gc.getFontMetrics());
101 }
102
103 /**
104 * Returns the colorized square size.
105 *
106 * @param fontMetrics
107 * @return the colorized square size.
108 */
109 public static int getSquareSize(FontMetrics fontMetrics) {
110 return fontMetrics.getHeight() - 2 * fontMetrics.getDescent();
111 }
112
113 /**
114 * Compute width of square
115 *
116 * @param styledText
117 * @return the width of square
118 */
119 private static int getSquareWidth(FontMetrics fontMetrics) {
120 // width = 2 spaces + size width of square
121 int width = 2 * fontMetrics.getAverageCharWidth() + getSquareSize(fontMetrics);
122 return width;
123 }
124
125 @Override
126 public Consumer<MouseEvent> getAction(MouseEvent e) {
127 return action;
128 }
129 }
0 /**
1 * Copyright (c) 2017 Angelo ZERR.
0 /**
1 * Copyright (c) 2017 Angelo ZERR.
22 *
3 * This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License 2.0
5 * which accompanies this distribution, and is available at
3 * This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License 2.0
5 * which accompanies this distribution, and is available at
66 * https://www.eclipse.org/legal/epl-2.0/
77 *
8 * SPDX-License-Identifier: EPL-2.0
9 *
10 * Contributors:
11 * Angelo Zerr <angelo.zerr@gmail.com> - [CodeMining] Provide inline annotations support - Bug 527675
12 */
13 package org.eclipse.jface.text.examples.sources.inlined;
14
15 import org.eclipse.jface.text.Position;
16 import org.eclipse.jface.text.source.ISourceViewer;
17 import org.eclipse.jface.text.source.inlined.LineHeaderAnnotation;
18
19 /**
20 * Color status annotation shows the result of rgb parse before each line which
21 * defines 'color:'.
22 */
23 public class ColorStatusAnnotation extends LineHeaderAnnotation {
24
25 public ColorStatusAnnotation(Position position, ISourceViewer viewer) {
26 super(position, viewer);
27 }
28
29 public void setStatus(String status) {
30 super.setText(status);
31 }
32
33 }
8 * SPDX-License-Identifier: EPL-2.0
9 *
10 * Contributors:
11 * Angelo Zerr <angelo.zerr@gmail.com> - [CodeMining] Provide inline annotations support - Bug 527675
12 */
13 package org.eclipse.jface.text.examples.sources.inlined;
14
15 import org.eclipse.jface.text.Position;
16 import org.eclipse.jface.text.source.ISourceViewer;
17 import org.eclipse.jface.text.source.inlined.LineHeaderAnnotation;
18
19 /**
20 * Color status annotation shows the result of rgb parse before each line which
21 * defines 'color:'.
22 */
23 public class ColorStatusAnnotation extends LineHeaderAnnotation {
24
25 public ColorStatusAnnotation(Position position, ISourceViewer viewer) {
26 super(position, viewer);
27 }
28
29 public void setStatus(String status) {
30 super.setText(status);
31 }
32
33 }
0 /**
1 * Copyright (c) 2017 Angelo ZERR.
2 *
3 * This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License 2.0
5 * which accompanies this distribution, and is available at
0 /**
1 * Copyright (c) 2017 Angelo ZERR.
2 *
3 * This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License 2.0
5 * which accompanies this distribution, and is available at
66 * https://www.eclipse.org/legal/epl-2.0/
77 *
8 * SPDX-License-Identifier: EPL-2.0
9 *
10 * Contributors:
11 * Angelo Zerr <angelo.zerr@gmail.com> - [CodeMining] Provide inline annotations support - Bug 527675
12 */
13 package org.eclipse.jface.text.examples.sources.inlined;
14
15 import java.util.HashSet;
16 import java.util.Set;
17 import java.util.regex.Matcher;
18 import java.util.regex.Pattern;
19
20 import org.eclipse.jface.text.BadLocationException;
21 import org.eclipse.jface.text.Document;
22 import org.eclipse.jface.text.IDocument;
23 import org.eclipse.jface.text.IRegion;
24 import org.eclipse.jface.text.ITextViewerExtension2;
25 import org.eclipse.jface.text.Position;
26 import org.eclipse.jface.text.reconciler.DirtyRegion;
27 import org.eclipse.jface.text.reconciler.IReconcilingStrategy;
28 import org.eclipse.jface.text.reconciler.MonoReconciler;
29 import org.eclipse.jface.text.source.Annotation;
30 import org.eclipse.jface.text.source.AnnotationModel;
31 import org.eclipse.jface.text.source.AnnotationPainter;
32 import org.eclipse.jface.text.source.IAnnotationAccess;
33 import org.eclipse.jface.text.source.ISourceViewer;
34 import org.eclipse.jface.text.source.SourceViewer;
35 import org.eclipse.jface.text.source.inlined.AbstractInlinedAnnotation;
36 import org.eclipse.jface.text.source.inlined.InlinedAnnotationSupport;
37 import org.eclipse.jface.text.source.inlined.LineContentAnnotation;
38 import org.eclipse.jface.text.source.inlined.LineHeaderAnnotation;
39 import org.eclipse.jface.text.source.inlined.Positions;
40 import org.eclipse.swt.SWT;
41 import org.eclipse.swt.graphics.Color;
42 import org.eclipse.swt.graphics.Device;
43 import org.eclipse.swt.layout.FillLayout;
44 import org.eclipse.swt.widgets.Display;
45 import org.eclipse.swt.widgets.Shell;
46
47 /**
48 * An inlined demo with {@link LineHeaderAnnotation} and
49 * {@link LineContentAnnotation} annotations both:
50 *
51 * <ul>
52 * <li>a status OK, NOK is displayed before the line which starts with 'color:'.
53 * This status is the result of the content after 'color' which must be a rgb
54 * content. Here {@link ColorStatusAnnotation} is used.</li>
55 * <li>a colorized square is displayed before the rgb declaration (inside the
56 * line content). Here {@link ColorAnnotation} is used.</li>
57 * </ul>
58 *
59 */
60 public class InlinedAnnotationDemo {
61
62 public static void main(String[] args) throws Exception {
63
64 Display display = new Display();
65 Shell shell = new Shell(display);
66 shell.setLayout(new FillLayout());
67 shell.setText("Inlined annotation demo");
68
69 // Create source viewer and initialize the content
70 ISourceViewer sourceViewer = new SourceViewer(shell, null, SWT.V_SCROLL | SWT.BORDER);
71 sourceViewer.setDocument(new Document("\ncolor:rgb(255, 255, 0)"), new AnnotationModel());
72
73 // Initialize inlined annotations support
74 InlinedAnnotationSupport support = new InlinedAnnotationSupport();
75 support.install(sourceViewer, createAnnotationPainter(sourceViewer));
76
77 // Refresh inlined annotation in none UI Thread with reconciler.
78 MonoReconciler reconciler = new MonoReconciler(new IReconcilingStrategy() {
79
80 @Override
81 public void setDocument(IDocument document) {
82 Set<AbstractInlinedAnnotation> annotations = getInlinedAnnotation(sourceViewer, support);
83 support.updateAnnotations(annotations);
84 }
85
86 @Override
87 public void reconcile(IRegion partition) {
88 Set<AbstractInlinedAnnotation> anns = getInlinedAnnotation(sourceViewer, support);
89 support.updateAnnotations(anns);
90 }
91
92 @Override
93 public void reconcile(DirtyRegion dirtyRegion, IRegion subRegion) {
94
95 }
96 }, false);
97 reconciler.setDelay(1);
98 reconciler.install(sourceViewer);
99
100 shell.open();
101 while (!shell.isDisposed()) {
102 if (!display.readAndDispatch())
103 display.sleep();
104 }
105 display.dispose();
106 }
107
108 /**
109 * Create annotation painter.
110 *
111 * @param viewer
112 * the viewer.
113 * @return annotation painter.
114 */
115 private static AnnotationPainter createAnnotationPainter(ISourceViewer viewer) {
116 IAnnotationAccess annotationAccess = new IAnnotationAccess() {
117 @Override
118 public Object getType(Annotation annotation) {
119 return annotation.getType();
120 }
121
122 @Override
123 public boolean isMultiLine(Annotation annotation) {
124 return true;
125 }
126
127 @Override
128 public boolean isTemporary(Annotation annotation) {
129 return true;
130 }
131
132 };
133 AnnotationPainter painter = new AnnotationPainter(viewer, annotationAccess);
134 ((ITextViewerExtension2) viewer).addPainter(painter);
135 return painter;
136 }
137
138 /**
139 * Returns the inlined annotations list to display in the given viewer.
140 *
141 * @param viewer
142 * the viewer
143 * @param support
144 * the inlined annotation suppor.
145 * @return the inlined annotations list to display in the given viewer.
146 */
147 private static Set<AbstractInlinedAnnotation> getInlinedAnnotation(ISourceViewer viewer,
148 InlinedAnnotationSupport support) {
149 IDocument document = viewer.getDocument();
150 Set<AbstractInlinedAnnotation> annotations = new HashSet<>();
151 int lineCount = document.getNumberOfLines();
152 for (int i = 0; i < lineCount; i++) {
153 String line = getLineText(document, i).trim();
154 int index = line.indexOf("color:");
155 if (index == 0) {
156 String rgb = line.substring(index + "color:".length(), line.length()).trim();
157 try {
158 String status = "OK!";
159 Color color = parse(rgb, viewer.getTextWidget().getDisplay());
160 if (color != null) {
161 } else {
162 status = "ERROR!";
163 }
164 // Status color annotation
165 Position pos = Positions.of(i, document, true);
166 ColorStatusAnnotation statusAnnotation = support.findExistingAnnotation(pos);
167 if (statusAnnotation == null) {
168 statusAnnotation = new ColorStatusAnnotation(pos, viewer);
169 }
170 statusAnnotation.setStatus(status);
171 annotations.add(statusAnnotation);
172
173 // Color annotation
174 if (color != null) {
175 Position colorPos = new Position(pos.offset + index + "color:".length(), 1);
176 ColorAnnotation colorAnnotation = support.findExistingAnnotation(colorPos);
177 if (colorAnnotation == null) {
178 colorAnnotation = new ColorAnnotation(colorPos, viewer);
179 }
180 colorAnnotation.setColor(color);
181 annotations.add(colorAnnotation);
182 }
183
184 // rgb parameter names annotations
185 int rgbIndex = line.indexOf("rgb");
186 if (rgbIndex != -1) {
187 rgbIndex = rgbIndex + "rgb".length();
188 int startOffset = pos.offset + rgbIndex;
189 String rgbContent = line.substring(rgbIndex, line.length());
190 int startIndex = addRGBParamNameAnnotation("red:", rgbContent, 0, startOffset, viewer, support,
191 annotations);
192 if (startIndex != -1) {
193 startIndex = addRGBParamNameAnnotation("green:", rgbContent, startIndex, startOffset, viewer,
194 support, annotations);
195 if (startIndex != -1) {
196 startIndex = addRGBParamNameAnnotation("blue:", rgbContent, startIndex, startOffset,
197 viewer, support, annotations);
198 }
199 }
200 }
201
202 } catch (BadLocationException e) {
203 e.printStackTrace();
204 }
205 }
206 }
207 return annotations;
208 }
209
210 /**
211 * Add RGB parameter name annotation
212 *
213 * @param paramName
214 * @param rgbContent
215 * @param startIndex
216 * @param startOffset
217 * @param viewer
218 * @param support
219 * @param annotations
220 * @return the current parsed index
221 */
222 private static int addRGBParamNameAnnotation(String paramName, String rgbContent, int startIndex, int startOffset,
223 ISourceViewer viewer, InlinedAnnotationSupport support, Set<AbstractInlinedAnnotation> annotations) {
224 char startChar = startIndex == 0 ? '(' : ',';
225 char[] chars = rgbContent.toCharArray();
226 for (int i = startIndex; i < chars.length; i++) {
227 char c = chars[i];
228 if (c == startChar) {
229 if (i == chars.length - 1) {
230 return -1;
231 }
232 Position paramPos = new Position(startOffset + i + 1, 1);
233 LineContentAnnotation colorParamAnnotation = support.findExistingAnnotation(paramPos);
234 if (colorParamAnnotation == null) {
235 colorParamAnnotation = new LineContentAnnotation(paramPos, viewer);
236 }
237 colorParamAnnotation.setText(paramName);
238 annotations.add(colorParamAnnotation);
239 return i + 1;
240 }
241 }
242 return -1;
243 }
244
245 /**
246 * Parse the given input rgb color and returns an instance of SWT Color and null
247 * otherwise.
248 *
249 * @param input
250 * the rgb string color
251 * @param device
252 * @return the created color and null otherwise.
253 */
254 private static Color parse(String input, Device device) {
255 Pattern c = Pattern.compile("rgb *\\( *([0-9]+), *([0-9]+), *([0-9]+) *\\)");
256 Matcher m = c.matcher(input);
257 if (m.matches()) {
258 try {
259 return new Color(device, Integer.valueOf(m.group(1)), // r
260 Integer.valueOf(m.group(2)), // g
261 Integer.valueOf(m.group(3))); // b
262 } catch (Exception e) {
263
264 }
265 }
266 return null;
267 }
268
269 /**
270 * Returns the line text.
271 *
272 * @param document
273 * the document.
274 * @param line
275 * the line index.
276 * @return the line text.
277 */
278 private static String getLineText(IDocument document, int line) {
279 try {
280 int offset = document.getLineOffset(line);
281 int length = document.getLineLength(line);
282 return document.get(offset, length);
283 } catch (Exception e) {
284 e.printStackTrace();
285 return null;
286 }
287 }
288 }
8 * SPDX-License-Identifier: EPL-2.0
9 *
10 * Contributors:
11 * Angelo Zerr <angelo.zerr@gmail.com> - [CodeMining] Provide inline annotations support - Bug 527675
12 */
13 package org.eclipse.jface.text.examples.sources.inlined;
14
15 import java.util.HashSet;
16 import java.util.Set;
17 import java.util.regex.Matcher;
18 import java.util.regex.Pattern;
19
20 import org.eclipse.jface.text.BadLocationException;
21 import org.eclipse.jface.text.Document;
22 import org.eclipse.jface.text.IDocument;
23 import org.eclipse.jface.text.IRegion;
24 import org.eclipse.jface.text.ITextViewerExtension2;
25 import org.eclipse.jface.text.Position;
26 import org.eclipse.jface.text.reconciler.DirtyRegion;
27 import org.eclipse.jface.text.reconciler.IReconcilingStrategy;
28 import org.eclipse.jface.text.reconciler.MonoReconciler;
29 import org.eclipse.jface.text.source.Annotation;
30 import org.eclipse.jface.text.source.AnnotationModel;
31 import org.eclipse.jface.text.source.AnnotationPainter;
32 import org.eclipse.jface.text.source.IAnnotationAccess;
33 import org.eclipse.jface.text.source.ISourceViewer;
34 import org.eclipse.jface.text.source.SourceViewer;
35 import org.eclipse.jface.text.source.inlined.AbstractInlinedAnnotation;
36 import org.eclipse.jface.text.source.inlined.InlinedAnnotationSupport;
37 import org.eclipse.jface.text.source.inlined.LineContentAnnotation;
38 import org.eclipse.jface.text.source.inlined.LineHeaderAnnotation;
39 import org.eclipse.jface.text.source.inlined.Positions;
40 import org.eclipse.swt.SWT;
41 import org.eclipse.swt.graphics.Color;
42 import org.eclipse.swt.graphics.Device;
43 import org.eclipse.swt.layout.FillLayout;
44 import org.eclipse.swt.widgets.Display;
45 import org.eclipse.swt.widgets.Shell;
46
47 /**
48 * An inlined demo with {@link LineHeaderAnnotation} and
49 * {@link LineContentAnnotation} annotations both:
50 *
51 * <ul>
52 * <li>a status OK, NOK is displayed before the line which starts with 'color:'.
53 * This status is the result of the content after 'color' which must be a rgb
54 * content. Here {@link ColorStatusAnnotation} is used.</li>
55 * <li>a colorized square is displayed before the rgb declaration (inside the
56 * line content). Here {@link ColorAnnotation} is used.</li>
57 * </ul>
58 *
59 */
60 public class InlinedAnnotationDemo {
61
62 public static void main(String[] args) throws Exception {
63
64 Display display = new Display();
65 Shell shell = new Shell(display);
66 shell.setLayout(new FillLayout());
67 shell.setText("Inlined annotation demo");
68
69 // Create source viewer and initialize the content
70 ISourceViewer sourceViewer = new SourceViewer(shell, null, SWT.V_SCROLL | SWT.BORDER);
71 sourceViewer.setDocument(new Document("\ncolor:rgb(255, 255, 0)"), new AnnotationModel());
72
73 // Initialize inlined annotations support
74 InlinedAnnotationSupport support = new InlinedAnnotationSupport();
75 support.install(sourceViewer, createAnnotationPainter(sourceViewer));
76
77 // Refresh inlined annotation in none UI Thread with reconciler.
78 MonoReconciler reconciler = new MonoReconciler(new IReconcilingStrategy() {
79
80 @Override
81 public void setDocument(IDocument document) {
82 Set<AbstractInlinedAnnotation> annotations = getInlinedAnnotation(sourceViewer, support);
83 support.updateAnnotations(annotations);
84 }
85
86 @Override
87 public void reconcile(IRegion partition) {
88 Set<AbstractInlinedAnnotation> anns = getInlinedAnnotation(sourceViewer, support);
89 support.updateAnnotations(anns);
90 }
91
92 @Override
93 public void reconcile(DirtyRegion dirtyRegion, IRegion subRegion) {
94
95 }
96 }, false);
97 reconciler.setDelay(1);
98 reconciler.install(sourceViewer);
99
100 shell.open();
101 while (!shell.isDisposed()) {
102 if (!display.readAndDispatch())
103 display.sleep();
104 }
105 display.dispose();
106 }
107
108 /**
109 * Create annotation painter.
110 *
111 * @param viewer
112 * the viewer.
113 * @return annotation painter.
114 */
115 private static AnnotationPainter createAnnotationPainter(ISourceViewer viewer) {
116 IAnnotationAccess annotationAccess = new IAnnotationAccess() {
117 @Override
118 public Object getType(Annotation annotation) {
119 return annotation.getType();
120 }
121
122 @Override
123 public boolean isMultiLine(Annotation annotation) {
124 return true;
125 }
126
127 @Override
128 public boolean isTemporary(Annotation annotation) {
129 return true;
130 }
131
132 };
133 AnnotationPainter painter = new AnnotationPainter(viewer, annotationAccess);
134 ((ITextViewerExtension2) viewer).addPainter(painter);
135 return painter;
136 }
137
138 /**
139 * Returns the inlined annotations list to display in the given viewer.
140 *
141 * @param viewer
142 * the viewer
143 * @param support
144 * the inlined annotation suppor.
145 * @return the inlined annotations list to display in the given viewer.
146 */
147 private static Set<AbstractInlinedAnnotation> getInlinedAnnotation(ISourceViewer viewer,
148 InlinedAnnotationSupport support) {
149 IDocument document = viewer.getDocument();
150 Set<AbstractInlinedAnnotation> annotations = new HashSet<>();
151 int lineCount = document.getNumberOfLines();
152 for (int i = 0; i < lineCount; i++) {
153 String line = getLineText(document, i).trim();
154 int index = line.indexOf("color:");
155 if (index == 0) {
156 String rgb = line.substring(index + "color:".length(), line.length()).trim();
157 try {
158 String status = "OK!";
159 Color color = parse(rgb, viewer.getTextWidget().getDisplay());
160 if (color != null) {
161 } else {
162 status = "ERROR!";
163 }
164 // Status color annotation
165 Position pos = Positions.of(i, document, true);
166 ColorStatusAnnotation statusAnnotation = support.findExistingAnnotation(pos);
167 if (statusAnnotation == null) {
168 statusAnnotation = new ColorStatusAnnotation(pos, viewer);
169 }
170 statusAnnotation.setStatus(status);
171 annotations.add(statusAnnotation);
172
173 // Color annotation
174 if (color != null) {
175 Position colorPos = new Position(pos.offset + index + "color:".length(), 1);
176 ColorAnnotation colorAnnotation = support.findExistingAnnotation(colorPos);
177 if (colorAnnotation == null) {
178 colorAnnotation = new ColorAnnotation(colorPos, viewer);
179 }
180 colorAnnotation.setColor(color);
181 annotations.add(colorAnnotation);
182 }
183
184 // rgb parameter names annotations
185 int rgbIndex = line.indexOf("rgb");
186 if (rgbIndex != -1) {
187 rgbIndex = rgbIndex + "rgb".length();
188 int startOffset = pos.offset + rgbIndex;
189 String rgbContent = line.substring(rgbIndex, line.length());
190 int startIndex = addRGBParamNameAnnotation("red:", rgbContent, 0, startOffset, viewer, support,
191 annotations);
192 if (startIndex != -1) {
193 startIndex = addRGBParamNameAnnotation("green:", rgbContent, startIndex, startOffset, viewer,
194 support, annotations);
195 if (startIndex != -1) {
196 startIndex = addRGBParamNameAnnotation("blue:", rgbContent, startIndex, startOffset,
197 viewer, support, annotations);
198 }
199 }
200 }
201
202 } catch (BadLocationException e) {
203 e.printStackTrace();
204 }
205 }
206 }
207 return annotations;
208 }
209
210 /**
211 * Add RGB parameter name annotation
212 *
213 * @param paramName
214 * @param rgbContent
215 * @param startIndex
216 * @param startOffset
217 * @param viewer
218 * @param support
219 * @param annotations
220 * @return the current parsed index
221 */
222 private static int addRGBParamNameAnnotation(String paramName, String rgbContent, int startIndex, int startOffset,
223 ISourceViewer viewer, InlinedAnnotationSupport support, Set<AbstractInlinedAnnotation> annotations) {
224 char startChar = startIndex == 0 ? '(' : ',';
225 char[] chars = rgbContent.toCharArray();
226 for (int i = startIndex; i < chars.length; i++) {
227 char c = chars[i];
228 if (c == startChar) {
229 if (i == chars.length - 1) {
230 return -1;
231 }
232 Position paramPos = new Position(startOffset + i + 1, 1);
233 LineContentAnnotation colorParamAnnotation = support.findExistingAnnotation(paramPos);
234 if (colorParamAnnotation == null) {
235 colorParamAnnotation = new LineContentAnnotation(paramPos, viewer);
236 }
237 colorParamAnnotation.setText(paramName);
238 annotations.add(colorParamAnnotation);
239 return i + 1;
240 }
241 }
242 return -1;
243 }
244
245 /**
246 * Parse the given input rgb color and returns an instance of SWT Color and null
247 * otherwise.
248 *
249 * @param input
250 * the rgb string color
251 * @param device
252 * @return the created color and null otherwise.
253 */
254 private static Color parse(String input, Device device) {
255 Pattern c = Pattern.compile("rgb *\\( *([0-9]+), *([0-9]+), *([0-9]+) *\\)");
256 Matcher m = c.matcher(input);
257 if (m.matches()) {
258 try {
259 return new Color(device, Integer.valueOf(m.group(1)), // r
260 Integer.valueOf(m.group(2)), // g
261 Integer.valueOf(m.group(3))); // b
262 } catch (Exception e) {
263
264 }
265 }
266 return null;
267 }
268
269 /**
270 * Returns the line text.
271 *
272 * @param document
273 * the document.
274 * @param line
275 * the line index.
276 * @return the line text.
277 */
278 private static String getLineText(IDocument document, int line) {
279 try {
280 int offset = document.getLineOffset(line);
281 int length = document.getLineLength(line);
282 return document.get(offset, length);
283 } catch (Exception e) {
284 e.printStackTrace();
285 return null;
286 }
287 }
288 }
11 Bundle-ManifestVersion: 2
22 Bundle-Name: %Plugin.name
33 Bundle-SymbolicName: org.eclipse.jface.text.tests
4 Bundle-Version: 3.11.500.qualifier
4 Bundle-Version: 3.11.700.qualifier
55 Bundle-Vendor: %Plugin.providerName
66 Bundle-Localization: plugin
77 Export-Package:
88 org.eclipse.jface.text.tests,
9 org.eclipse.jface.text.tests.codemining,
910 org.eclipse.jface.text.tests.contentassist,
1011 org.eclipse.jface.text.tests.reconciler,
1112 org.eclipse.jface.text.tests.rules,
1313 <parent>
1414 <artifactId>tests-pom</artifactId>
1515 <groupId>eclipse.platform.text</groupId>
16 <version>4.11.0-SNAPSHOT</version>
16 <version>4.12.0-SNAPSHOT</version>
1717 <relativePath>../tests-pom/</relativePath>
1818 </parent>
1919 <groupId>org.eclipse.jface</groupId>
2020 <artifactId>org.eclipse.jface.text.tests</artifactId>
21 <version>3.11.500-SNAPSHOT</version>
21 <version>3.11.700-SNAPSHOT</version>
2222 <packaging>eclipse-test-plugin</packaging>
2323 <properties>
2424 <testSuite>${project.artifactId}</testSuite>
403403 fUndoManager.beginCompoundChange();
404404 fUndoManager.endCompoundChange();
405405
406 // insert the atomic changes
406 // insert the atomic changes
407407 doRepeatableChange(document);
408408
409409 assertTrue(fUndoManager.undoable());
+0
-181
org.eclipse.jface.text.tests/src/org/eclipse/jface/text/tests/CodeMiningTest.java less more
0 /*******************************************************************************
1 * Copyright (c) 2019 Red Hat Inc. and others.
2 *
3 * This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License 2.0
5 * which accompanies this distribution, and is available at
6 * https://www.eclipse.org/legal/epl-2.0/
7 *
8 * SPDX-License-Identifier: EPL-2.0
9 *
10 * Contributors:
11 * - Mickael Istria (Red Hat Inc.) - initial implementation
12 *******************************************************************************/
13 package org.eclipse.jface.text.tests;
14
15 import java.util.concurrent.atomic.AtomicInteger;
16
17 import org.junit.After;
18 import org.junit.Assert;
19 import org.junit.Assume;
20 import org.junit.Before;
21 import org.junit.Rule;
22 import org.junit.Test;
23
24 import org.eclipse.swt.SWT;
25 import org.eclipse.swt.custom.StyledText;
26 import org.eclipse.swt.layout.FillLayout;
27 import org.eclipse.swt.widgets.Display;
28 import org.eclipse.swt.widgets.Shell;
29
30 import org.eclipse.jface.util.Util;
31
32 import org.eclipse.jface.text.BadLocationException;
33 import org.eclipse.jface.text.Document;
34 import org.eclipse.jface.text.IDocument;
35 import org.eclipse.jface.text.IRegion;
36 import org.eclipse.jface.text.codemining.ICodeMiningProvider;
37 import org.eclipse.jface.text.reconciler.DirtyRegion;
38 import org.eclipse.jface.text.reconciler.IReconcilingStrategy;
39 import org.eclipse.jface.text.reconciler.MonoReconciler;
40 import org.eclipse.jface.text.source.AnnotationModel;
41 import org.eclipse.jface.text.source.AnnotationPainter;
42 import org.eclipse.jface.text.source.SourceViewer;
43 import org.eclipse.jface.text.tests.util.DisplayHelper;
44
45 public class CodeMiningTest {
46
47 private SourceViewer fViewer;
48 private Shell fShell;
49
50 @Rule public ScreenshotOnFailureRule rule = new ScreenshotOnFailureRule();
51
52 @Before
53 public void setUp() {
54 fShell= new Shell(Display.getDefault());
55 fShell.setSize(500, 200);
56 fShell.setLayout(new FillLayout());
57 fViewer= new SourceViewer(fShell, null, SWT.NONE);
58 final StyledText textWidget= fViewer.getTextWidget();
59 MonoReconciler reconciler = new MonoReconciler(new IReconcilingStrategy() {
60 @Override
61 public void setDocument(IDocument document) {
62 fViewer.updateCodeMinings();
63 }
64
65 @Override
66 public void reconcile(DirtyRegion dirtyRegion, IRegion subRegion) {
67 // nothing to do
68 }
69
70 @Override
71 public void reconcile(IRegion partition) {
72 fViewer.updateCodeMinings();
73 }
74 }, false);
75 reconciler.install(fViewer);
76 fViewer.setDocument(new Document(), new AnnotationModel());
77 fViewer.setCodeMiningProviders(new ICodeMiningProvider[] { new DelayedEchoCodeMiningProvider() });
78 AnnotationPainter annotationPainter = new AnnotationPainter(fViewer, null);
79 fViewer.setCodeMiningAnnotationPainter(annotationPainter);
80 fViewer.addPainter(annotationPainter);
81 // this currently needs to be repeated
82 fViewer.setCodeMiningProviders(new ICodeMiningProvider[] { new DelayedEchoCodeMiningProvider() });
83 final Display display = textWidget.getDisplay();
84 fShell.open();
85 Assert.assertTrue(new DisplayHelper() {
86 @Override
87 protected boolean condition() {
88 return fViewer.getTextWidget().isVisible();
89 }
90 }.waitForCondition(display, 3000));
91 DisplayHelper.sleep(textWidget.getDisplay(), 1000);
92 }
93
94 @After
95 public void tearDown() {
96 fShell.dispose();
97 fViewer = null;
98 }
99
100 @Test
101 public void testCodeMiningFirstLine() {
102 fViewer.getDocument().set("echo");
103 Assert.assertTrue(new DisplayHelper() {
104 @Override
105 protected boolean condition() {
106 return fViewer.getTextWidget().getLineVerticalIndent(0) > 0;
107 }
108 }.waitForCondition(fViewer.getControl().getDisplay(), 3000));
109 }
110
111 @Test
112 public void testCodeMiningCtrlHome() throws BadLocationException {
113 Assume.assumeFalse("See bug 541415. For whatever reason, this shortcut doesn't work on Mac", Util.isMac());
114 DelayedEchoCodeMiningProvider.DELAY = 500;
115 fViewer.getDocument().set(TextViewerTest.generate5000Lines());
116 Assert.assertTrue(new DisplayHelper() {
117 @Override
118 protected boolean condition() {
119 return fViewer.getTextWidget().getText().length() > 5000;
120 }
121 }.waitForCondition(fViewer.getControl().getDisplay(), 3000));
122 TextViewerTest.ctrlEnd(fViewer);
123 final int lastLine = fViewer.getDocument().getNumberOfLines() - 1;
124 final int lastLineOffset = fViewer.getDocument().getLineOffset(lastLine);
125 Assert.assertTrue(new DisplayHelper() {
126 @Override
127 protected boolean condition() {
128 return lastLineOffset >= fViewer.getVisibleRegion().getOffset() && lastLineOffset <= fViewer.getVisibleRegion().getOffset() + fViewer.getVisibleRegion().getLength();
129 }
130 }.waitForCondition(fViewer.getControl().getDisplay(), 3000));
131 DisplayHelper.sleep(fViewer.getControl().getDisplay(), 500);
132 AtomicInteger events = new AtomicInteger();
133 fViewer.addViewportListener(offset ->
134 events.incrementAndGet());
135 TextViewerTest.ctrlHome(fViewer);
136 Assert.assertTrue(new DisplayHelper() {
137 @Override
138 protected boolean condition() {
139 return events.get() > 0;
140 }
141 }.waitForCondition(fViewer.getControl().getDisplay(), 3000));
142 Assert.assertEquals(0, fViewer.getVisibleRegion().getOffset());
143 // wait for codemining to style line
144 Assert.assertTrue(new DisplayHelper() {
145 @Override
146 protected boolean condition() {
147 return fViewer.getTextWidget().getLineVerticalIndent(0) > 0;
148 }
149 }.waitForCondition(fViewer.getControl().getDisplay(), 300000));
150 }
151
152 @Test
153 public void testCodeMiningCtrlEnd() throws BadLocationException {
154 Assume.assumeFalse("See bug 541415. For whatever reason, this shortcut doesn't work on Mac", Util.isMac());
155 fViewer.getDocument().set(TextViewerTest.generate5000Lines());
156 Assert.assertTrue(new DisplayHelper() {
157 @Override
158 protected boolean condition() {
159 return fViewer.getTextWidget().getText().length() > 5000 && fViewer.getTextWidget().getLineVerticalIndent(0) > 0;
160 }
161 }.waitForCondition(fViewer.getControl().getDisplay(), 3000));
162 DisplayHelper.sleep(fViewer.getTextWidget().getDisplay(), 500);
163 TextViewerTest.ctrlEnd(fViewer);
164 final int lastLine = fViewer.getDocument().getNumberOfLines() - 1;
165 final int lastLineOffset = fViewer.getDocument().getLineOffset(lastLine);
166 Assert.assertTrue(new DisplayHelper() {
167 @Override
168 protected boolean condition() {
169 return lastLineOffset >= fViewer.getVisibleRegion().getOffset() && lastLineOffset <= fViewer.getVisibleRegion().getOffset() + fViewer.getVisibleRegion().getLength();
170 }
171 }.waitForCondition(fViewer.getControl().getDisplay(), 3000));
172 Assert.assertTrue(new DisplayHelper() {
173 @Override
174 protected boolean condition() {
175 return fViewer.getTextWidget().getLineVerticalIndent(lastLine) > 0;
176 }
177 }.waitForCondition(fViewer.getControl().getDisplay(), 3000));
178 }
179
180 }
+0
-64
org.eclipse.jface.text.tests/src/org/eclipse/jface/text/tests/DelayedEchoCodeMiningProvider.java less more
0 /*******************************************************************************
1 * Copyright (c) 2019 Red Hat Inc. and others.
2 *
3 * This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License 2.0
5 * which accompanies this distribution, and is available at
6 * https://www.eclipse.org/legal/epl-2.0/
7 *
8 * SPDX-License-Identifier: EPL-2.0
9 *
10 * Contributors:
11 * - Mickael Istria (Red Hat Inc.) - initial implementation
12 *******************************************************************************/
13 package org.eclipse.jface.text.tests;
14
15 import java.util.ArrayList;
16 import java.util.List;
17 import java.util.concurrent.CompletableFuture;
18
19 import org.eclipse.core.runtime.IProgressMonitor;
20
21 import org.eclipse.jface.text.BadLocationException;
22 import org.eclipse.jface.text.IDocument;
23 import org.eclipse.jface.text.ITextViewer;
24 import org.eclipse.jface.text.codemining.AbstractCodeMiningProvider;
25 import org.eclipse.jface.text.codemining.ICodeMining;
26 import org.eclipse.jface.text.codemining.ICodeMiningProvider;
27 import org.eclipse.jface.text.codemining.LineHeaderCodeMining;
28
29 public class DelayedEchoCodeMiningProvider extends AbstractCodeMiningProvider implements ICodeMiningProvider {
30
31 public static int DELAY = 0;
32
33 @Override
34 public CompletableFuture<List<? extends ICodeMining>> provideCodeMinings(ITextViewer viewer, IProgressMonitor monitor) {
35 return CompletableFuture.supplyAsync(() -> {
36 try {
37 Thread.sleep(DELAY);
38 } catch (InterruptedException e1) {
39 e1.printStackTrace();
40 return null;
41 }
42 IDocument document = viewer.getDocument();
43 List<ICodeMining> res = new ArrayList<>();
44 for (int lineNumber = 0; lineNumber < document.getNumberOfLines(); lineNumber++) {
45 try {
46 String lineContent = document.get(document.getLineOffset(lineNumber), document.getLineLength(lineNumber));
47 if (!lineContent.trim().isEmpty()) {
48 LineHeaderCodeMining mining = new LineHeaderCodeMining(lineNumber, document, DelayedEchoCodeMiningProvider.this) {
49 // Nothing in particular
50 };
51 mining.setLabel(lineContent);
52 res.add(mining);
53 }
54 } catch (BadLocationException e) {
55 e.printStackTrace();
56 }
57
58 }
59 return res;
60 });
61 }
62
63 }
1616 import org.junit.runners.Suite;
1717 import org.junit.runners.Suite.SuiteClasses;
1818
19 import org.eclipse.jface.text.tests.codemining.CodeMiningTest;
20 import org.eclipse.jface.text.tests.codemining.CodeMiningProjectionViewerTest;
1921 import org.eclipse.jface.text.tests.contentassist.AsyncContentAssistTest;
2022 import org.eclipse.jface.text.tests.reconciler.AbstractReconcilerTest;
2123 import org.eclipse.jface.text.tests.rules.DefaultPartitionerTest;
5456 WordRuleTest.class,
5557
5658 TemplatePersistenceDataTest.class,
57 CodeMiningTest.class
59 CodeMiningTest.class,
60 CodeMiningProjectionViewerTest.class
5861 })
5962 public class JFaceTextTestSuite {
6063 // see @SuiteClasses
1616
1717 import org.eclipse.test.Screenshots;
1818
19 final class ScreenshotOnFailureRule extends TestWatcher {
19 public final class ScreenshotOnFailureRule extends TestWatcher {
2020 @Override
2121 protected void failed(Throwable e, org.junit.runner.Description description) {
2222 Screenshots.takeScreenshot(description.getTestClass(), description.getMethodName());
00 /*******************************************************************************
1 * Copyright (c) 2014-2019 Google, Inc and others.
1 * Copyright (c) 2014, 2019 Google, Inc and others.
22 *
33 * This program and the accompanying materials
44 * are made available under the terms of the Eclipse Public License 2.0
88 * SPDX-License-Identifier: EPL-2.0
99 *
1010 * Contributors:
11 * - Sergey Prigogin (Google) - initial API and implementation
12 * - Mickael Istria (Red Hat Inc.) - [Bug 544708] Ctrl+Home
11 * Sergey Prigogin (Google) - initial API and implementation
12 * Mickael Istria (Red Hat Inc.) - [Bug 544708] Ctrl+Home
13 * Paul Pazderski - [Bug 545530] Test for TextViewer's default IDocumentAdapter implementation.
1314 *******************************************************************************/
1415 package org.eclipse.jface.text.tests;
1516
16
1717 import static org.junit.Assert.assertEquals;
1818 import static org.junit.Assert.assertTrue;
19 import static org.junit.Assert.fail;
20 import static org.junit.Assume.assumeNotNull;
1921
2022 import java.util.concurrent.atomic.AtomicBoolean;
2123
2426 import org.junit.Test;
2527
2628 import org.eclipse.swt.SWT;
29 import org.eclipse.swt.custom.StyledTextContent;
2730 import org.eclipse.swt.layout.FillLayout;
2831 import org.eclipse.swt.widgets.Control;
2932 import org.eclipse.swt.widgets.Display;
3437 import org.eclipse.jface.util.Util;
3538
3639 import org.eclipse.jface.text.Document;
40 import org.eclipse.jface.text.IDocumentAdapter;
3741 import org.eclipse.jface.text.ITextViewer;
3842 import org.eclipse.jface.text.TextViewer;
3943 import org.eclipse.jface.text.source.SourceViewer;
123127 }
124128 }
125129
130 /**
131 * Test if {@link TextViewer}s default {@link IDocumentAdapter} implementation adhere to
132 * {@link IDocumentAdapter}s JavaDoc.
133 */
134 @Test
135 public void testDefaultContentImplementation() {
136 final Shell shell= new Shell();
137 try {
138 final StyledTextContent content;
139 try {
140 final TextViewer textViewer= new TextViewer(shell, SWT.NONE);
141 textViewer.setDocument(new Document());
142 content= textViewer.getTextWidget().getContent();
143 } catch (Exception ex) {
144 fail("Failed to obtain default instance of TextViewers document adapter. " + ex.getMessage());
145 return;
146 }
147 assumeNotNull(content);
148
149 final String line0= "Hello ";
150 final String line1= "";
151 final String line2= "World!";
152 final String text= line0 + "\n" + line1 + "\r\n" + line2;
153 content.setText(text);
154 assertEquals("Get text range failed.", "H", content.getTextRange(0, 1));
155 assertEquals("Get text range failed.", "ll", content.getTextRange(2, 2));
156 assertEquals("Adapter content length wrong.", text.length(), content.getCharCount());
157 assertEquals("Adapter returned wrong content.", line0, content.getLine(0));
158 assertEquals("Adapter returned wrong content.", line1, content.getLine(1));
159 assertEquals("Adapter returned wrong content.", line2, content.getLine(2));
160
161 content.setText("\r\n\r\n");
162 assertEquals("Wrong line for offset.", 0, content.getLineAtOffset(0));
163 assertEquals("Wrong line for offset.", 0, content.getLineAtOffset(1));
164 assertEquals("Wrong line for offset.", 1, content.getLineAtOffset(2));
165 assertEquals("Wrong line for offset.", 1, content.getLineAtOffset(3));
166 assertEquals("Wrong line for offset.", 2, content.getLineAtOffset(4));
167 assertEquals("Wrong line for offset.", content.getLineCount() - 1, content.getLineAtOffset(content.getCharCount()));
168
169 content.setText(null);
170 assertEquals("Adapter returned wrong line count.", 1, content.getLineCount());
171 content.setText("");
172 assertEquals("Adapter returned wrong line count.", 1, content.getLineCount());
173 content.setText("a\n");
174 assertEquals("Adapter returned wrong line count.", 2, content.getLineCount());
175 content.setText("\n\n");
176 assertEquals("Adapter returned wrong line count.", 3, content.getLineCount());
177
178 content.setText("\r\ntest\r\n");
179 assertEquals("Wrong offset for line.", 0, content.getOffsetAtLine(0));
180 assertEquals("Wrong offset for line.", 2, content.getOffsetAtLine(1));
181 assertEquals("Wrong offset for line.", 8, content.getOffsetAtLine(2));
182 content.setText("");
183 assertEquals("Wrong offset for line.", 0, content.getOffsetAtLine(0));
184 } finally {
185 shell.dispose();
186 }
187 }
188
126189 public static void ctrlEnd(ITextViewer viewer) {
127190 postKeyEvent(viewer.getTextWidget(), SWT.END, SWT.CTRL, SWT.KeyDown);
128191 }
149212 DisplayHelper.driveEventQueue(display);
150213 }
151214
152
153215 public static String generate5000Lines() {
154216 StringBuilder b = new StringBuilder("start");
155217 for (int i = 0; i < 5000; i++) {
158220 b.append("end");
159221 return b.toString();
160222 }
161
162223 }
0 /**
1 * Copyright (c) 2019 Red Hat Inc., and others
2 *
3 * This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License 2.0
5 * which accompanies this distribution, and is available at
6 * https://www.eclipse.org/legal/epl-2.0/
7 *
8 * SPDX-License-Identifier: EPL-2.0
9 *
10 * Contributors:
11 * - Mickael Istria (Red Hat Inc.)
12 */
13 package org.eclipse.jface.text.tests.codemining;
14
15 import java.util.ArrayList;
16 import java.util.List;
17 import java.util.concurrent.CompletableFuture;
18 import java.util.concurrent.atomic.AtomicReference;
19
20 import org.junit.After;
21 import org.junit.Assert;
22 import org.junit.Before;
23 import org.junit.Test;
24 import org.osgi.framework.Bundle;
25
26 import org.eclipse.swt.SWT;
27 import org.eclipse.swt.graphics.Color;
28 import org.eclipse.swt.graphics.RGB;
29 import org.eclipse.swt.layout.FillLayout;
30 import org.eclipse.swt.widgets.Shell;
31
32 import org.eclipse.core.runtime.ILog;
33 import org.eclipse.core.runtime.ILogListener;
34 import org.eclipse.core.runtime.IProgressMonitor;
35 import org.eclipse.core.runtime.IStatus;
36 import org.eclipse.core.runtime.Platform;
37
38 import org.eclipse.jface.text.BadLocationException;
39 import org.eclipse.jface.text.Document;
40 import org.eclipse.jface.text.ITextViewer;
41 import org.eclipse.jface.text.Position;
42 import org.eclipse.jface.text.codemining.ICodeMining;
43 import org.eclipse.jface.text.codemining.ICodeMiningProvider;
44 import org.eclipse.jface.text.codemining.LineContentCodeMining;
45 import org.eclipse.jface.text.source.Annotation;
46 import org.eclipse.jface.text.source.AnnotationPainter;
47 import org.eclipse.jface.text.source.IAnnotationAccess;
48 import org.eclipse.jface.text.source.ISharedTextColors;
49 import org.eclipse.jface.text.source.projection.ProjectionAnnotation;
50 import org.eclipse.jface.text.source.projection.ProjectionAnnotationModel;
51 import org.eclipse.jface.text.source.projection.ProjectionSupport;
52 import org.eclipse.jface.text.source.projection.ProjectionViewer;
53 import org.eclipse.jface.text.tests.util.DisplayHelper;
54
55 public class CodeMiningProjectionViewerTest {
56
57 private final class RepeatLettersCodeMiningProvider implements ICodeMiningProvider {
58 @Override
59 public CompletableFuture<List<? extends ICodeMining>> provideCodeMinings(ITextViewer viewer, IProgressMonitor monitor) {
60 List<LineContentCodeMining> codeMinings = new ArrayList<>();
61 for (int i = 0; i < viewer.getDocument().getLength(); i++) {
62 try {
63 char c= viewer.getDocument().getChar(i);
64 if (Character.isLetter(c)) {
65 codeMinings.add(new StaticContentLineCodeMining(i, c, this));
66 }
67 } catch (BadLocationException e) {
68 e.printStackTrace();
69 }
70 }
71 return CompletableFuture.completedFuture(codeMinings);
72 }
73
74 @Override
75 public void dispose() {
76 }
77 }
78
79 private Shell fParent;
80 private ProjectionViewer fViewer;
81
82 @Before
83 public void setUp() {
84 fParent= new Shell();
85 fParent.setSize(500, 200);
86 fParent.setLayout(new FillLayout());
87 fViewer= new ProjectionViewer(fParent, null, null, false, SWT.NONE);
88 IAnnotationAccess annotationAccess = new IAnnotationAccess() {
89 @Override
90 public Object getType(Annotation annotation) {
91 return annotation.getType();
92 }
93
94 @Override
95 public boolean isMultiLine(Annotation annotation) {
96 return true;
97 }
98
99 @Override
100 public boolean isTemporary(Annotation annotation) {
101 return true;
102 }
103 };
104 // code minings
105 AnnotationPainter painter = new AnnotationPainter(fViewer, annotationAccess);
106 fViewer.addPainter(painter);
107 fViewer.setCodeMiningAnnotationPainter(painter);
108 // projection/folding
109 fViewer.setDocument(new Document(), new ProjectionAnnotationModel());
110 ProjectionSupport projectionSupport = new ProjectionSupport(fViewer, annotationAccess, new ISharedTextColors() {
111 @Override
112 public Color getColor(RGB rgb) {
113 return null;
114 }
115
116 @Override
117 public void dispose() {
118 }
119 });
120 projectionSupport.install();
121 fViewer.doOperation(ProjectionViewer.TOGGLE);
122 }
123
124 @After
125 public void tearDown() {
126 fParent.dispose();
127 }
128
129 @Test
130 public void testCollapse() throws Exception {
131 fViewer.setCodeMiningProviders(new ICodeMiningProvider[] {
132 new RepeatLettersCodeMiningProvider()
133 });
134 fViewer.getDocument().set("1a\n2a\n3a\n4a\n5a\n6a\n");
135 ProjectionAnnotation annotation= new ProjectionAnnotation(true);
136 fViewer.getProjectionAnnotationModel().addAnnotation(annotation, new Position(0, fViewer.getDocument().getLineOffset(4)));
137 fViewer.doOperation(ProjectionViewer.COLLAPSE_ALL);
138 fViewer.updateCodeMinings();
139 fParent.open();
140
141 Bundle bundle = Platform.getBundle("org.eclipse.ui.workbench");
142 ILog log = null;
143 AtomicReference<IStatus> logError = new AtomicReference<>();
144 ILogListener logListener= (status, plugin) -> {
145 logError.set(status);
146 };
147 if (bundle != null && bundle.getState() == Bundle.ACTIVE) {
148 log = Platform.getLog(bundle);
149 log.addLogListener(logListener);
150 }
151 try {
152 // without workbench, next line throws Exception directly
153 DisplayHelper.sleep(fParent.getDisplay(), 1000);
154 Assert.assertNull(logError.get());
155 } finally {
156 if (log != null) {
157 log.removeLogListener(logListener);
158 }
159 }
160 }
161 }
0 /*******************************************************************************
1 * Copyright (c) 2019 Red Hat Inc. and others.
2 *
3 * This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License 2.0
5 * which accompanies this distribution, and is available at
6 * https://www.eclipse.org/legal/epl-2.0/
7 *
8 * SPDX-License-Identifier: EPL-2.0
9 *
10 * Contributors:
11 * - Mickael Istria (Red Hat Inc.) - initial implementation
12 *******************************************************************************/
13 package org.eclipse.jface.text.tests.codemining;
14
15 import java.util.Collections;
16 import java.util.List;
17 import java.util.concurrent.CompletableFuture;
18 import java.util.concurrent.atomic.AtomicInteger;
19
20 import org.junit.After;
21 import org.junit.Assert;
22 import org.junit.Assume;
23 import org.junit.Before;
24 import org.junit.Rule;
25 import org.junit.Test;
26
27 import org.eclipse.swt.SWT;
28 import org.eclipse.swt.custom.StyledText;
29 import org.eclipse.swt.graphics.GC;
30 import org.eclipse.swt.graphics.Image;
31 import org.eclipse.swt.graphics.ImageData;
32 import org.eclipse.swt.graphics.Rectangle;
33 import org.eclipse.swt.layout.FillLayout;
34 import org.eclipse.swt.widgets.Display;
35 import org.eclipse.swt.widgets.Shell;
36
37 import org.eclipse.core.runtime.IProgressMonitor;
38
39 import org.eclipse.jface.util.Util;
40
41 import org.eclipse.jface.text.BadLocationException;
42 import org.eclipse.jface.text.Document;
43 import org.eclipse.jface.text.IDocument;
44 import org.eclipse.jface.text.IRegion;
45 import org.eclipse.jface.text.ITextViewer;
46 import org.eclipse.jface.text.Position;
47 import org.eclipse.jface.text.codemining.ICodeMining;
48 import org.eclipse.jface.text.codemining.ICodeMiningProvider;
49 import org.eclipse.jface.text.reconciler.DirtyRegion;
50 import org.eclipse.jface.text.reconciler.IReconcilingStrategy;
51 import org.eclipse.jface.text.reconciler.MonoReconciler;
52 import org.eclipse.jface.text.source.AnnotationModel;
53 import org.eclipse.jface.text.source.AnnotationPainter;
54 import org.eclipse.jface.text.source.SourceViewer;
55 import org.eclipse.jface.text.tests.ScreenshotOnFailureRule;
56 import org.eclipse.jface.text.tests.TextViewerTest;
57 import org.eclipse.jface.text.tests.util.DisplayHelper;
58
59 public class CodeMiningTest {
60
61 private SourceViewer fViewer;
62 private Shell fShell;
63
64 @Rule public ScreenshotOnFailureRule rule = new ScreenshotOnFailureRule();
65
66 @Before
67 public void setUp() {
68 fShell= new Shell(Display.getDefault());
69 fShell.setSize(500, 200);
70 fShell.setLayout(new FillLayout());
71 fViewer= new SourceViewer(fShell, null, SWT.NONE);
72 final StyledText textWidget= fViewer.getTextWidget();
73 textWidget.setText("a");
74 textWidget.setText("");
75 MonoReconciler reconciler = new MonoReconciler(new IReconcilingStrategy() {
76 @Override
77 public void setDocument(IDocument document) {
78 fViewer.updateCodeMinings();
79 }
80
81 @Override
82 public void reconcile(DirtyRegion dirtyRegion, IRegion subRegion) {
83 // nothing to do
84 }
85
86 @Override
87 public void reconcile(IRegion partition) {
88 fViewer.updateCodeMinings();
89 }
90 }, false);
91 reconciler.install(fViewer);
92 fViewer.setDocument(new Document(), new AnnotationModel());
93 fViewer.setCodeMiningProviders(new ICodeMiningProvider[] { new DelayedEchoCodeMiningProvider() });
94 AnnotationPainter annotationPainter = new AnnotationPainter(fViewer, null);
95 fViewer.setCodeMiningAnnotationPainter(annotationPainter);
96 fViewer.addPainter(annotationPainter);
97 // this currently needs to be repeated
98 fViewer.setCodeMiningProviders(new ICodeMiningProvider[] { new DelayedEchoCodeMiningProvider() });
99 final Display display = textWidget.getDisplay();
100 fShell.open();
101 Assert.assertTrue(new DisplayHelper() {
102 @Override
103 protected boolean condition() {
104 return fViewer.getTextWidget().isVisible();
105 }
106 }.waitForCondition(display, 3000));
107 DisplayHelper.sleep(textWidget.getDisplay(), 1000);
108 }
109
110 @After
111 public void tearDown() {
112 fShell.dispose();
113 fViewer = null;
114 }
115
116 @Test
117 public void testCodeMiningFirstLine() {
118 fViewer.getDocument().set("echo");
119 Assert.assertTrue(new DisplayHelper() {
120 @Override
121 protected boolean condition() {
122 return fViewer.getTextWidget().getLineVerticalIndent(0) > 0;
123 }
124 }.waitForCondition(fViewer.getControl().getDisplay(), 3000));
125 }
126
127 @Test
128 public void testCodeMiningCtrlHome() throws BadLocationException {
129 Assume.assumeFalse("See bug 541415. For whatever reason, this shortcut doesn't work on Mac", Util.isMac());
130 DelayedEchoCodeMiningProvider.DELAY = 500;
131 fViewer.getDocument().set(TextViewerTest.generate5000Lines());
132 Assert.assertTrue(new DisplayHelper() {
133 @Override
134 protected boolean condition() {
135 return fViewer.getTextWidget().getText().length() > 5000;
136 }
137 }.waitForCondition(fViewer.getControl().getDisplay(), 3000));
138 TextViewerTest.ctrlEnd(fViewer);
139 final int lastLine = fViewer.getDocument().getNumberOfLines() - 1;
140 final int lastLineOffset = fViewer.getDocument().getLineOffset(lastLine);
141 Assert.assertTrue(new DisplayHelper() {
142 @Override
143 protected boolean condition() {
144 return lastLineOffset >= fViewer.getVisibleRegion().getOffset() && lastLineOffset <= fViewer.getVisibleRegion().getOffset() + fViewer.getVisibleRegion().getLength();
145 }
146 }.waitForCondition(fViewer.getControl().getDisplay(), 3000));
147 DisplayHelper.sleep(fViewer.getControl().getDisplay(), 500);
148 AtomicInteger events = new AtomicInteger();
149 fViewer.addViewportListener(offset ->
150 events.incrementAndGet());
151 TextViewerTest.ctrlHome(fViewer);
152 Assert.assertTrue(new DisplayHelper() {
153 @Override
154 protected boolean condition() {
155 return events.get() > 0;
156 }
157 }.waitForCondition(fViewer.getControl().getDisplay(), 3000));
158 Assert.assertEquals(0, fViewer.getVisibleRegion().getOffset());
159 // wait for codemining to style line
160 Assert.assertTrue(new DisplayHelper() {
161 @Override
162 protected boolean condition() {
163 return fViewer.getTextWidget().getLineVerticalIndent(0) > 0;
164 }
165 }.waitForCondition(fViewer.getControl().getDisplay(), 300000));
166 }
167
168 @Test
169 public void testCodeMiningCtrlEnd() throws BadLocationException {
170 Assume.assumeFalse("See bug 541415. For whatever reason, this shortcut doesn't work on Mac", Util.isMac());
171 fViewer.getDocument().set(TextViewerTest.generate5000Lines());
172 Assert.assertTrue(new DisplayHelper() {
173 @Override
174 protected boolean condition() {
175 return fViewer.getTextWidget().getText().length() > 5000 && fViewer.getTextWidget().getLineVerticalIndent(0) > 0;
176 }
177 }.waitForCondition(fViewer.getControl().getDisplay(), 3000));
178 DisplayHelper.sleep(fViewer.getTextWidget().getDisplay(), 500);
179 TextViewerTest.ctrlEnd(fViewer);
180 final int lastLine = fViewer.getDocument().getNumberOfLines() - 1;
181 final int lastLineOffset = fViewer.getDocument().getLineOffset(lastLine);
182 Assert.assertTrue(new DisplayHelper() {
183 @Override
184 protected boolean condition() {
185 return lastLineOffset >= fViewer.getVisibleRegion().getOffset() && lastLineOffset <= fViewer.getVisibleRegion().getOffset() + fViewer.getVisibleRegion().getLength();
186 }
187 }.waitForCondition(fViewer.getControl().getDisplay(), 3000));
188 Assert.assertTrue(new DisplayHelper() {
189 @Override
190 protected boolean condition() {
191 return fViewer.getTextWidget().getLineVerticalIndent(lastLine) > 0;
192 }
193 }.waitForCondition(fViewer.getControl().getDisplay(), 3000));
194 }
195
196 @Test
197 public void testCodeMiningMultiLine() throws BadLocationException {
198 fViewer.getDocument().set("a\nbc");
199 fViewer.setCodeMiningProviders(new ICodeMiningProvider[] { new ICodeMiningProvider() {
200 @Override
201 public CompletableFuture<List<? extends ICodeMining>> provideCodeMinings(ITextViewer viewer, IProgressMonitor monitor) {
202 return CompletableFuture.completedFuture(Collections.singletonList(new StaticContentLineCodeMining(new Position(0, 3), "long enough code mining to be wider than actual text", this)));
203 }
204
205 @Override
206 public void dispose() {
207 }
208 } });
209 StyledText widget = fViewer.getTextWidget();
210 Assert.assertFalse("Code mining is visible on 2nd line", new DisplayHelper() {
211 @Override
212 protected boolean condition() {
213 try {
214 return widget.getStyleRangeAtOffset(0) != null && widget.getStyleRangeAtOffset(0).metrics != null
215 && hasCodeMiningPrintedAfterTextOnLine(fViewer, 1);
216 } catch (BadLocationException e) {
217 e.printStackTrace();
218 return true;
219 }
220 }
221 }.waitForCondition(fViewer.getTextWidget().getDisplay(), 1000));
222 }
223
224 private static boolean hasCodeMiningPrintedAfterTextOnLine(ITextViewer viewer, int line) throws BadLocationException {
225 StyledText widget = viewer.getTextWidget();
226 IDocument document= viewer.getDocument();
227 Rectangle secondLineBounds = widget.getTextBounds(document.getLineOffset(1), document.getLineOffset(line) + document.getLineLength(line) - 1);
228 Image image = new Image(widget.getDisplay(), widget.getSize().x, widget.getSize().y);
229 GC gc = new GC(widget);
230 gc.copyArea(image, 0, 0);
231 gc.dispose();
232 ImageData imageData = image.getImageData();
233 secondLineBounds.x += secondLineBounds.width; // look only area after text
234 for (int x = secondLineBounds.x + 1; x < image.getBounds().width && x < imageData.width; x++) {
235 for (int y = secondLineBounds.y; y < secondLineBounds.y + secondLineBounds.height && y < imageData.height; y++) {
236 if (!imageData.palette.getRGB(imageData.getPixel(x, y)).equals(widget.getBackground().getRGB())) {
237 // code mining printed
238 image.dispose();
239 return true;
240 }
241 }
242 }
243 image.dispose();
244 return false;
245 }
246 }
0 /*******************************************************************************
1 * Copyright (c) 2019 Red Hat Inc. and others.
2 *
3 * This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License 2.0
5 * which accompanies this distribution, and is available at
6 * https://www.eclipse.org/legal/epl-2.0/
7 *
8 * SPDX-License-Identifier: EPL-2.0
9 *
10 * Contributors:
11 * - Mickael Istria (Red Hat Inc.) - initial implementation
12 *******************************************************************************/
13 package org.eclipse.jface.text.tests.codemining;
14
15 import java.util.ArrayList;
16 import java.util.List;
17 import java.util.concurrent.CompletableFuture;
18
19 import org.eclipse.core.runtime.IProgressMonitor;
20
21 import org.eclipse.jface.text.BadLocationException;
22 import org.eclipse.jface.text.IDocument;
23 import org.eclipse.jface.text.ITextViewer;
24 import org.eclipse.jface.text.codemining.AbstractCodeMiningProvider;
25 import org.eclipse.jface.text.codemining.ICodeMining;
26 import org.eclipse.jface.text.codemining.LineHeaderCodeMining;
27
28 public class DelayedEchoCodeMiningProvider extends AbstractCodeMiningProvider {
29
30 public static int DELAY = 0;
31
32 @Override
33 public CompletableFuture<List<? extends ICodeMining>> provideCodeMinings(ITextViewer viewer, IProgressMonitor monitor) {
34 return CompletableFuture.supplyAsync(() -> {
35 try {
36 Thread.sleep(DELAY);
37 } catch (InterruptedException e1) {
38 e1.printStackTrace();
39 return null;
40 }
41 IDocument document = viewer.getDocument();
42 List<ICodeMining> res = new ArrayList<>();
43 for (int lineNumber = 0; lineNumber < document.getNumberOfLines(); lineNumber++) {
44 try {
45 String lineContent = document.get(document.getLineOffset(lineNumber), document.getLineLength(lineNumber));
46 if (!lineContent.trim().isEmpty()) {
47 LineHeaderCodeMining mining = new LineHeaderCodeMining(lineNumber, document, DelayedEchoCodeMiningProvider.this) {
48 // Nothing in particular
49 };
50 mining.setLabel(lineContent);
51 res.add(mining);
52 }
53 } catch (BadLocationException e) {
54 e.printStackTrace();
55 }
56
57 }
58 return res;
59 });
60 }
61
62 }
0 /**
1 * Copyright (c) 2019 Red Hat Inc., and others
2 *
3 * This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License 2.0
5 * which accompanies this distribution, and is available at
6 * https://www.eclipse.org/legal/epl-2.0/
7 *
8 * SPDX-License-Identifier: EPL-2.0
9 *
10 * Contributors:
11 * - Mickael Istria (Red Hat Inc.)
12 */
13 package org.eclipse.jface.text.tests.codemining;
14
15 import org.eclipse.jface.text.Position;
16 import org.eclipse.jface.text.codemining.ICodeMiningProvider;
17 import org.eclipse.jface.text.codemining.LineContentCodeMining;
18
19 public class StaticContentLineCodeMining extends LineContentCodeMining {
20
21 public StaticContentLineCodeMining(Position position, String message, ICodeMiningProvider provider) {
22 super(position, provider);
23 setLabel(message);
24 }
25
26 public StaticContentLineCodeMining(int i, char c, ICodeMiningProvider repeatLettersCodeMiningProvider) {
27 super(new Position(i, 1), repeatLettersCodeMiningProvider);
28 setLabel(Character.toString(c));
29 }
30
31 @Override
32 public boolean isResolved() {
33 return true;
34 }
35
36 }
242242 int[] offsets= new int[] { 0, 1 };
243243 assertComputePartitioning_InterleavingPartitions(offsets);
244244
245 }
245 }
246246
247247 @Test
248248 public void testBug368219_1() throws Exception {
11 Bundle-ManifestVersion: 2
22 Bundle-Name: %pluginName
33 Bundle-SymbolicName: org.eclipse.search; singleton:=true
4 Bundle-Version: 3.11.500.qualifier
4 Bundle-Version: 3.11.600.qualifier
55 Bundle-Activator: org.eclipse.search.internal.ui.SearchPlugin
66 Bundle-ActivationPolicy: lazy
77 Bundle-Vendor: %providerName
9797 * The scope is WORKSPACE_SCOPE, SELECTED_PROJECTS_SCOPE, SELECTION_SCOPE or WORKING_SET_SCOPE.
9898 * @param scope the newly selected scope
9999 *
100 * @since 2.0
100 * @since 2.0
101101 */
102102 public void setSelectedScope(int scope);
103103
105105 * Tells whether a valid scope is selected.
106106 *
107107 * @return a <code>true</code> if a valid scope is selected in this search page container
108 * @since 2.0
108 * @since 2.0
109109 */
110110 public boolean hasValidScope();
111111
151151 } else {
152152 fIsUIUpdateScheduled= false;
153153 turnOnDecoration();
154 updateBusyLabel();
155 if (fScheduleEnsureSelection) {
156 fScheduleEnsureSelection= false;
157 AbstractTextSearchResult result = getInput();
158 if (result != null && fViewer.getSelection().isEmpty()) {
159 navigateNext(true);
160 }
161 }
154 updateBusyLabel();
155 if (fScheduleEnsureSelection) {
156 fScheduleEnsureSelection= false;
157 AbstractTextSearchResult result = getInput();
158 if (result != null && fViewer.getSelection().isEmpty()) {
159 navigateNext(true);
160 }
161 }
162162 }
163163 fViewPart.updateLabel();
164164 return Status.OK_STATUS;
209209 }
210210
211211 private volatile boolean fIsUIUpdateScheduled= false;
212 private volatile boolean fScheduleEnsureSelection= false;
212 private volatile boolean fScheduleEnsureSelection= false;
213213 private static final String KEY_LAYOUT = "org.eclipse.search.resultpage.layout"; //$NON-NLS-1$
214214
215215 /**
605605
606606 @Override
607607 public void queryFinished(final ISearchQuery query) {
608 // handle the end of the query in the UIUpdateJob, as ui updates
609 // may not be finished here.
610 postEnsureSelection();
608 // handle the end of the query in the UIUpdateJob, as ui updates
609 // may not be finished here.
610 postEnsureSelection();
611611 }
612612 };
613613 }
616616 * Posts a UI update to make sure an element is selected.
617617 * @since 3.2
618618 */
619 protected void postEnsureSelection() {
620 fScheduleEnsureSelection= true;
621 scheduleUIUpdate();
622 }
619 protected void postEnsureSelection() {
620 fScheduleEnsureSelection= true;
621 scheduleUIUpdate();
622 }
623623
624624
625625 private void updateBusyLabel() {
2020 */
2121 public abstract class MatchFilter {
2222
23 /**
24 * Returns whether the given match is filtered by this filter.
25 *
26 * @param match the match to look at
27 * @return returns <code>true</code> if the given match should be filtered or <code>false</code> if not.
28 */
23 /**
24 * Returns whether the given match is filtered by this filter.
25 *
26 * @param match the match to look at
27 * @return returns <code>true</code> if the given match should be filtered or <code>false</code> if not.
28 */
2929 public abstract boolean filters(Match match);
3030
31 /**
32 * Returns the name of the filter as shown in the match filter selection dialog.
33 *
34 * @return the name of the filter as shown in the match filter selection dialog.
35 */
31 /**
32 * Returns the name of the filter as shown in the match filter selection dialog.
33 *
34 * @return the name of the filter as shown in the match filter selection dialog.
35 */
3636 public abstract String getName();
3737
38 /**
39 * Returns the description of the filter as shown in the match filter selection dialog.
40 *
41 * @return the description of the filter as shown in the match filter selection dialog.
42 */
38 /**
39 * Returns the description of the filter as shown in the match filter selection dialog.
40 *
41 * @return the description of the filter as shown in the match filter selection dialog.
42 */
4343 public abstract String getDescription();
4444
4545 /**
46 * Returns the label of the filter as shown by the filter action.
47 *
48 * @return the label of the filter as shown by the filter action.
49 */
46 * Returns the label of the filter as shown by the filter action.
47 *
48 * @return the label of the filter as shown by the filter action.
49 */
5050 public abstract String getActionLabel();
5151
5252 /**
53 * Returns an ID of this filter.
54 *
55 * @return the id of the filter to be used when persisting this filter.
56 */
53 * Returns an ID of this filter.
54 *
55 * @return the id of the filter to be used when persisting this filter.
56 */
5757 public abstract String getID();
5858
5959 }
3636
3737 /**
3838 * Specified the input for a search query.
39 * <p>
40 * Clients may instantiate this class.
41 * </p>
39 * <p>
40 * Clients may instantiate this class.
41 * </p>
4242 */
4343 public static abstract class TextSearchInput {
4444
3535 private ISearchResult fSearch;
3636
3737 public ShowSearchFromHistoryAction(ISearchResult search) {
38 super("", AS_RADIO_BUTTON); //$NON-NLS-1$
38 super("", AS_RADIO_BUTTON); //$NON-NLS-1$
3939 fSearch= search;
4040
4141 String label= escapeAmp(search.getLabel());
320320 table.setLayoutData(gd);
321321
322322
323 fRemoveButton= new Button(parent, SWT.PUSH);
324 fRemoveButton.setText(SearchMessages.SearchesDialog_remove_label);
325 fRemoveButton.addSelectionListener(new SelectionAdapter() {
326 @Override
323 fRemoveButton= new Button(parent, SWT.PUSH);
324 fRemoveButton.setText(SearchMessages.SearchesDialog_remove_label);
325 fRemoveButton.addSelectionListener(new SelectionAdapter() {
326 @Override
327327 public void widgetSelected(SelectionEvent event) {
328 buttonPressed(REMOVE_ID);
329 }
330 });
328 buttonPressed(REMOVE_ID);
329 }
330 });
331331 fRemoveButton.setLayoutData(new GridData(GridData.BEGINNING, GridData.BEGINNING, false, false));
332332 SWTUtil.setButtonDimensionHint(fRemoveButton);
333333
2222 // Do not instantiate
2323 }
2424
25 static {
26 NLS.initializeMessages(BUNDLE_NAME, SearchMessages.class);
27 }
25 static {
26 NLS.initializeMessages(BUNDLE_NAME, SearchMessages.class);
27 }
2828
2929 public static String AbstractTextSearchViewPage_update_job_name;
3030 public static String MatchFilterSelectionAction_label;
9191 public static String PinSearchViewAction_label;
9292 public static String PinSearchViewAction_tooltip;
9393 public static String SearchPageRegistry_error_creating_extensionpoint;
94 public static String TextSearchGroup_submenu_text;
95 public static String FindInWorkspaceActionDelegate_text;
96 public static String FindInProjectActionDelegate_text;
97 public static String FindInWorkingSetActionDelegate_text;
98 public static String FindInFileActionDelegate_text;
94 public static String TextSearchGroup_submenu_text;
95 public static String FindInWorkspaceActionDelegate_text;
96 public static String FindInProjectActionDelegate_text;
97 public static String FindInWorkingSetActionDelegate_text;
98 public static String FindInFileActionDelegate_text;
9999 public static String TextSearchQueryProviderRegistry_defaultProviderLabel;
100100 public static String RetrieverAction_dialog_title;
101101 public static String RetrieverAction_empty_selection;
1313 <parent>
1414 <artifactId>eclipse.platform.text</artifactId>
1515 <groupId>eclipse.platform.text</groupId>
16 <version>4.11.0-SNAPSHOT</version>
16 <version>4.12.0-SNAPSHOT</version>
1717 </parent>
1818 <groupId>org.eclipse.search</groupId>
1919 <artifactId>org.eclipse.search</artifactId>
20 <version>3.11.500-SNAPSHOT</version>
20 <version>3.11.600-SNAPSHOT</version>
2121 <packaging>eclipse-plugin</packaging>
2222 </project>
135135 * @return returns true if the file name is matching to a file name pattern
136136 */
137137 private boolean matchesFileName(String fileName) {
138 return getFileNameMatcher().reset(fileName).matches();
138 return getFileNameMatcher().reset(fileName).matches();
139139 }
140140
141141 /**
155155 }
156156
157157
158 private static boolean isWordChar(char c) {
159 return Character.isLetterOrDigit(c);
160 }
158 private static boolean isWordChar(char c) {
159 return Character.isLetterOrDigit(c);
160 }
161161
162162 /**
163163 * Creates a pattern element from an array of patterns in the old 'StringMatcher' format.
171171 StringBuilder pattern= new StringBuilder();
172172 for (int i= 0; i < patterns.length; i++) {
173173 if (i > 0) {
174 // note that this works only as we know that the operands of the
175 // or expression will be simple and need no brackets.
174 // note that this works only as we know that the operands of the
175 // or expression will be simple and need no brackets.
176176 pattern.append('|');
177177 }
178178 appendAsRegEx(true, patterns[i], pattern);
182182
183183
184184 public static StringBuilder appendAsRegEx(boolean isStringMatcher, String pattern, StringBuilder buffer) {
185 boolean isEscaped= false;
186 for (int i = 0; i < pattern.length(); i++) {
187 char c = pattern.charAt(i);
188 switch(c) {
189 // the backslash
190 case '\\':
191 // the backslash is escape char in string matcher
192 if (isStringMatcher && !isEscaped) {
193 isEscaped= true;
194 }
195 else {
196 buffer.append("\\\\"); //$NON-NLS-1$
197 isEscaped= false;
198 }
199 break;
200 // characters that need to be escaped in the regex.
201 case '(':
202 case ')':
203 case '{':
204 case '}':
205 case '.':
206 case '[':
207 case ']':
208 case '$':
209 case '^':
210 case '+':
211 case '|':
212 if (isEscaped) {
213 buffer.append("\\\\"); //$NON-NLS-1$
214 isEscaped= false;
215 }
216 buffer.append('\\');
217 buffer.append(c);
218 break;
219 case '?':
220 if (isStringMatcher && !isEscaped) {
221 buffer.append('.');
222 }
223 else {
224 buffer.append('\\');
225 buffer.append(c);
226 isEscaped= false;
227 }
228 break;
229 case '*':
230 if (isStringMatcher && !isEscaped) {
231 buffer.append(".*"); //$NON-NLS-1$
232 }
233 else {
234 buffer.append('\\');
235 buffer.append(c);
236 isEscaped= false;
237 }
238 break;
239 default:
240 if (isEscaped) {
241 buffer.append("\\\\"); //$NON-NLS-1$
242 isEscaped= false;
243 }
244 buffer.append(c);
245 break;
246 }
247 }
248 if (isEscaped) {
249 buffer.append("\\\\"); //$NON-NLS-1$
250 isEscaped= false;
251 }
252 return buffer;
253 }
185 boolean isEscaped= false;
186 for (int i = 0; i < pattern.length(); i++) {
187 char c = pattern.charAt(i);
188 switch(c) {
189 // the backslash
190 case '\\':
191 // the backslash is escape char in string matcher
192 if (isStringMatcher && !isEscaped) {
193 isEscaped= true;
194 }
195 else {
196 buffer.append("\\\\"); //$NON-NLS-1$
197 isEscaped= false;
198 }
199 break;
200 // characters that need to be escaped in the regex.
201 case '(':
202 case ')':
203 case '{':
204 case '}':
205 case '.':
206 case '[':
207 case ']':
208 case '$':
209 case '^':
210 case '+':
211 case '|':
212 if (isEscaped) {
213 buffer.append("\\\\"); //$NON-NLS-1$
214 isEscaped= false;
215 }
216 buffer.append('\\');
217 buffer.append(c);
218 break;
219 case '?':
220 if (isStringMatcher && !isEscaped) {
221 buffer.append('.');
222 }
223 else {
224 buffer.append('\\');
225 buffer.append(c);
226 isEscaped= false;
227 }
228 break;
229 case '*':
230 if (isStringMatcher && !isEscaped) {
231 buffer.append(".*"); //$NON-NLS-1$
232 }
233 else {
234 buffer.append('\\');
235 buffer.append(c);
236 isEscaped= false;
237 }
238 break;
239 default:
240 if (isEscaped) {
241 buffer.append("\\\\"); //$NON-NLS-1$
242 isEscaped= false;
243 }
244 buffer.append(c);
245 break;
246 }
247 }
248 if (isEscaped) {
249 buffer.append("\\\\"); //$NON-NLS-1$
250 isEscaped= false;
251 }
252 return buffer;
253 }
254254
255255 /**
256256 * Interprets escaped characters in the given replace pattern.
433433 System.out.println(Messages.format(
434434 "[TextSearch] Search duration for {0} files in {1} jobs using {2} threads: {3}ms", args)); //$NON-NLS-1$
435435 }
436 }
436 }
437437 }
438438
439439 public IStatus search(TextSearchScope scope, IProgressMonitor monitor) {
384384 ArrayList<SearchPageDescriptor> filteredList= new ArrayList<>(input.size());
385385 for (SearchPageDescriptor descriptor : input) {
386386 if (!WorkbenchActivityHelper.filterItem(descriptor))
387 filteredList.add(descriptor);
387 filteredList.add(descriptor);
388388
389389 }
390390 return filteredList;
430430 for (int i= 0; i < numPages; i++) {
431431 SearchPageDescriptor descriptor= getDescriptorAt(i);
432432 if (WorkbenchActivityHelper.filterItem(descriptor))
433 continue;
433 continue;
434434
435435 final CTabItem item = new CTabItem(folder, SWT.NONE);
436436 item.setData("descriptor", descriptor); //$NON-NLS-1$
479479 composite.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
480480
481481 // create help control if needed
482 if (isHelpAvailable()) {
483 createHelpControl(composite);
484 }
482 if (isHelpAvailable()) {
483 createHelpControl(composite);
484 }
485485 fCustomizeButton= createButton(composite, CUSTOMIZE_ID, SearchMessages.SearchDialog_customize, true);
486486
487487 Label filler= new Label(composite, SWT.NONE);
215215 }
216216
217217 // public static String ReplaceDialog2_nomatches_error;
218 public static String SearchPreferencePage_textSearchEngine;
218 public static String SearchPreferencePage_textSearchEngine;
219219 public static String TextSearchEngineRegistry_defaulttextsearch_label;
220220 public static String FileSearchQuery_singularPatternWithFileExt;
221221 public static String FileSearchQuery_pluralPatternWithFileExt;
191191 if (sizeHint != null) {
192192 int commaSep= sizeHint.indexOf(',');
193193 if (commaSep != -1) {
194 try {
195 int xval= Integer.parseInt(sizeHint.substring(0, commaSep).trim());
196 int yval= Integer.parseInt(sizeHint.substring(commaSep + 1).trim());
197 return new Point(xval, yval);
198 } catch (NumberFormatException e) {
199 }
194 try {
195 int xval= Integer.parseInt(sizeHint.substring(0, commaSep).trim());
196 int yval= Integer.parseInt(sizeHint.substring(commaSep + 1).trim());
197 return new Point(xval, yval);
198 } catch (NumberFormatException e) {
199 }
200200 }
201201 }
202 return UNKNOWN_SIZE;
202 return UNKNOWN_SIZE;
203203 }
204204
205205 /**
366366 }
367367 }
368368
369 @Override
369 @Override
370370 public String getLocalId() {
371 return getId();
372 }
373
374 @Override
371 return getId();
372 }
373
374 @Override
375375 public String getPluginId() {
376 return fElement.getContributor().getName();
377 }
376 return fElement.getContributor().getName();
377 }
378378 }
301301 }
302302
303303
304 public TextSearchEngineRegistry getTextSearchEngineRegistry() {
305 if (fTextSearchEngineRegistry == null) {
306 fTextSearchEngineRegistry= new TextSearchEngineRegistry();
307 }
308 return fTextSearchEngineRegistry;
309 }
310
311 public TextSearchQueryProviderRegistry getTextSearchQueryProviderRegistry() {
312 if (fTextSearchQueryProviderRegistry == null) {
313 fTextSearchQueryProviderRegistry= new TextSearchQueryProviderRegistry();
314 }
315 return fTextSearchQueryProviderRegistry;
316 }
304 public TextSearchEngineRegistry getTextSearchEngineRegistry() {
305 if (fTextSearchEngineRegistry == null) {
306 fTextSearchEngineRegistry= new TextSearchEngineRegistry();
307 }
308 return fTextSearchEngineRegistry;
309 }
310
311 public TextSearchQueryProviderRegistry getTextSearchQueryProviderRegistry() {
312 if (fTextSearchQueryProviderRegistry == null) {
313 fTextSearchQueryProviderRegistry= new TextSearchQueryProviderRegistry();
314 }
315 return fTextSearchQueryProviderRegistry;
316 }
317317
318318 /**
319319 * Creates all necessary sorter description nodes.
5252 public static final String DEFAULT_PERSPECTIVE= "org.eclipse.search.defaultPerspective"; //$NON-NLS-1$
5353 private static final String NO_DEFAULT_PERSPECTIVE= "org.eclipse.search.defaultPerspective.none"; //$NON-NLS-1$
5454 public static final String BRING_VIEW_TO_FRONT= "org.eclipse.search.bringToFront"; //$NON-NLS-1$
55 public static final String TEXT_SEARCH_ENGINE = "org.eclipse.search.textSearchEngine"; //$NON-NLS-1$
56 public static final String TEXT_SEARCH_QUERY_PROVIDER = "org.eclipse.search.textSearchQueryProvider"; //$NON-NLS-1$
55 public static final String TEXT_SEARCH_ENGINE = "org.eclipse.search.textSearchEngine"; //$NON-NLS-1$
56 public static final String TEXT_SEARCH_QUERY_PROVIDER = "org.eclipse.search.textSearchQueryProvider"; //$NON-NLS-1$
5757 public static final String LIMIT_HISTORY= "org.eclipse.search.limitHistory"; //$NON-NLS-1$
5858
5959 private ColorFieldEditor fColorEditor;
118118 POTENTIAL_MATCH_FG_COLOR,
119119 SearchMessages.SearchPreferencePage_potentialMatchFgColor,
120120 getFieldEditorParent()
121 );
121 );
122122 addField(fColorEditor);
123123
124124 fEmphasizedCheckbox.setEnabled(!arePotentialMatchesIgnored(), getFieldEditorParent());
133133 getFieldEditorParent());
134134 addField(comboEditor);
135135
136 // in case we have a contributed engine, let the user choose.
137 TextSearchEngineRegistry reg= SearchPlugin.getDefault().getTextSearchEngineRegistry();
138 String[][] engineNamesAndIds= reg.getAvailableEngines();
139 if (engineNamesAndIds.length > 1) {
140 comboEditor= new ComboFieldEditor(
141 TEXT_SEARCH_ENGINE,
142 SearchMessages.SearchPreferencePage_textSearchEngine,
143 engineNamesAndIds,
144 getFieldEditorParent());
145 addField(comboEditor);
146 }
136 // in case we have a contributed engine, let the user choose.
137 TextSearchEngineRegistry reg= SearchPlugin.getDefault().getTextSearchEngineRegistry();
138 String[][] engineNamesAndIds= reg.getAvailableEngines();
139 if (engineNamesAndIds.length > 1) {
140 comboEditor= new ComboFieldEditor(
141 TEXT_SEARCH_ENGINE,
142 SearchMessages.SearchPreferencePage_textSearchEngine,
143 engineNamesAndIds,
144 getFieldEditorParent());
145 addField(comboEditor);
146 }
147147 }
148148
149149 @Override
131131 item.fill(parent, -1);
132132 }
133133
134 @Override
134 @Override
135135 public void run() {
136136 // nothing to do
137 }
137 }
138138
139139 private SorterDescriptor findSorter(String pageId) {
140140 Iterator<SorterDescriptor> iter= SearchPlugin.getDefault().getSorterDescriptors().iterator();
8989 return 2;
9090 }
9191
92 @Override
92 @Override
9393 public int compare(Viewer viewer, Object e1, Object e2) {
94 int cat1 = category(e1);
95 int cat2 = category(e2);
96
97 if (cat1 != cat2) {
94 int cat1 = category(e1);
95 int cat2 = category(e2);
96
97 if (cat1 != cat2) {
9898 return cat1 - cat2;
9999 }
100100
101 if (e1 instanceof LineElement && e2 instanceof LineElement) {
101 if (e1 instanceof LineElement && e2 instanceof LineElement) {
102102 LineElement m1= (LineElement) e1;
103103 LineElement m2= (LineElement) e2;
104 return m1.getOffset() - m2.getOffset();
105 }
106
107 String name1= fLabelProvider.getText(e1);
108 String name2= fLabelProvider.getText(e2);
109 if (name1 == null)
110 name1 = "";//$NON-NLS-1$
111 if (name2 == null)
112 name2 = "";//$NON-NLS-1$
104 return m1.getOffset() - m2.getOffset();
105 }
106
107 String name1= fLabelProvider.getText(e1);
108 String name2= fLabelProvider.getText(e2);
109 if (name1 == null)
110 name1 = "";//$NON-NLS-1$
111 if (name2 == null)
112 name2 = "";//$NON-NLS-1$
113113 int result= getComparator().compare(name1, name2);
114114 return result;
115 }
115 }
116116 }
117117
118118 private static final String KEY_SORTING= "org.eclipse.search.resultpage.sorting"; //$NON-NLS-1$
6262 public ReplaceConfigurationPage(ReplaceRefactoring refactoring) {
6363 super("ReplaceConfigurationPage"); //$NON-NLS-1$
6464 fReplaceRefactoring= refactoring;
65 }
66
67 @Override
65 }
66
67 @Override
6868 public void createControl(Composite parent) {
69 Composite result= new Composite(parent, SWT.NONE);
70 GridLayout layout= new GridLayout(2, false);
69 Composite result= new Composite(parent, SWT.NONE);
70 GridLayout layout= new GridLayout(2, false);
7171 result.setLayout(layout);
7272
7373 Label description= new Label(result, SWT.NONE);
152152 Dialog.applyDialogFont(result);
153153
154154 PlatformUI.getWorkbench().getHelpSystem().setHelp(getControl(), ISearchHelpContextIds.REPLACE_DIALOG);
155 }
155 }
156156
157157 final void updateOKStatus() {
158158 RefactoringStatus status= new RefactoringStatus();
175175 fTextFieldContentAssist.setEnabled(enable);
176176 }
177177
178 @Override
178 @Override
179179 protected boolean performFinish() {
180180 initializeRefactoring();
181181 storeSettings();
203203 IDialogSettings settings= SearchPlugin.getDefault().getDialogSettings().addNewSection(SETTINGS_GROUP);
204204 settings.put(SETTINGS_REPLACE_WITH, history.toArray(new String[history.size()]));
205205
206 }
206 }
207207
208208 private void initializeRefactoring() {
209209 fReplaceRefactoring.setReplaceString(fTextField.getText());
210 }
210 }
211211
212212 }
475475 replacementText= PatternConstructor.interpretReplaceEscapes(replacementText, originalText, lineDelimiter);
476476
477477 Matcher matcher= pattern.matcher(originalText);
478 StringBuffer sb = new StringBuffer();
479 matcher.reset();
480 if (matcher.find()) {
481 matcher.appendReplacement(sb, replacementText);
482 } else {
483 return null;
484 }
485 matcher.appendTail(sb);
486 return sb.toString();
478 StringBuffer sb = new StringBuffer();
479 matcher.reset();
480 if (matcher.find()) {
481 matcher.appendReplacement(sb, replacementText);
482 } else {
483 return null;
484 }
485 matcher.appendTail(sb);
486 return sb.toString();
487487 } catch (IndexOutOfBoundsException ex) {
488488 throw new PatternSyntaxException(ex.getLocalizedMessage(), replacementText, -1);
489489 }
278278 ErrorDialog.openError(getShell(), SearchMessages.TextSearchPage_replace_searchproblems_title, SearchMessages.TextSearchPage_replace_searchproblems_message, e.getStatus());
279279 return false;
280280 }
281 return true;
281 return true;
282282 }
283283
284284 @Override
740740 });
741741 fSearchBinaryCheckbox.setLayoutData(new GridData(SWT.BEGINNING, SWT.CENTER, false, false, 1, 1));
742742 fSearchBinaryCheckbox.setFont(searchInGroup.getFont());
743 }
743 }
744744
745745 /**
746746 * Sets the search page's container.
5252 * If every match should show up in the search result view then the match
5353 * itself can be used as key.
5454 *
55 * @param groupFactory the action group factory
56 * or <code>null</code> if no factory is provided.
57 * @param singularLabel the label to be used for this search occurrence
58 * if there is one match
55 * @param groupFactory the action group factory
56 * or <code>null</code> if no factory is provided.
57 * @param singularLabel the label to be used for this search occurrence
58 * if there is one match
5959 * or <code>null</code> if the pluralLabelPattern should be used
60 * @param pluralLabelPattern the label pattern to be used for this search occurrence
61 * if there are more than one matches or none.
62 * This string may contain {0} which will be replace by the match count
63 * @param imageDescriptor the image descriptor to be used for this search occurrence,
60 * @param pluralLabelPattern the label pattern to be used for this search occurrence
61 * if there are more than one matches or none.
62 * This string may contain {0} which will be replace by the match count
63 * @param imageDescriptor the image descriptor to be used for this search occurrence,
6464 * or <code>null</code> if this search should not have an image
6565 * @param pageId the id of the search page which started the search
6666 * @param labelProvider the label provider used by this search result view
67 * or <code>null</code> if the default provider should be used.
67 * or <code>null</code> if the default provider should be used.
6868 * The default label provider shows the resource name and the corresponding image.
6969 * @param gotoAction the action used by the view to go to a marker
7070 * @param groupByKeyComputer the computer used by the view to compute the key for a marker
7171 * @param operation the runnable used by the view to repeat the search
7272 *
7373 * @see IActionGroupFactory
74 * @since 2.0
74 * @since 2.0
7575 */
7676 public void searchStarted(
7777 IActionGroupFactory groupFactory,
199199 *
200200 * @param description the text description of the match
201201 * @param groupByKey the <code>Object</code> by which this match is grouped
202 * @param marker the marker for this match
202 * @param marker the marker for this match
203203 * @param resource the marker's resource passed for optimization
204204 */
205205 public void addMatch(String description, Object groupByKey, IResource resource, IMarker marker);
1313 <parent>
1414 <artifactId>tests-pom</artifactId>
1515 <groupId>eclipse.platform.text</groupId>
16 <version>4.11.0-SNAPSHOT</version>
16 <version>4.12.0-SNAPSHOT</version>
1717 <relativePath>../tests-pom/</relativePath>
1818 </parent>
1919 <groupId>org.eclipse.search</groupId>
11 Bundle-ManifestVersion: 2
22 Bundle-Name: %pluginName
33 Bundle-SymbolicName: org.eclipse.text
4 Bundle-Version: 3.8.100.qualifier
4 Bundle-Version: 3.8.200.qualifier
55 Bundle-Vendor: %providerName
66 Bundle-Localization: plugin
77 Export-Package:
1313 <parent>
1414 <artifactId>eclipse.platform.text</artifactId>
1515 <groupId>eclipse.platform.text</groupId>
16 <version>4.11.0-SNAPSHOT</version>
16 <version>4.12.0-SNAPSHOT</version>
1717 </parent>
1818 <groupId>org.eclipse.text</groupId>
1919 <artifactId>org.eclipse.text</artifactId>
20 <version>3.8.100-SNAPSHOT</version>
20 <version>3.8.200-SNAPSHOT</version>
2121 <packaging>eclipse-plugin</packaging>
2222 </project>
244244 * Returns all positions managed by the document grouped by category.
245245 *
246246 * @return the document's positions
247 */
247 */
248248 protected Map<String, List<Position>> getDocumentManagedPositions() {
249249 return fPositions;
250250 }
6868 * @param detail the detailed message
6969 */
7070 public AssertionFailedException(String detail) {
71 super(detail);
71 super(detail);
7272 }
7373 }
7474
329329 * @since 3.3
330330 */
331331 private char[] allocate(int size) {
332 return new char[size];
333 }
332 return new char[size];
333 }
334334
335335 /*
336336 * Executes System.arraycopy if length != 0. A length < 0 cannot happen -> don't hide coding
627627
628628 /**
629629 * Returns the line delimiter of that line or <code>null</code> if the
630 * line is not closed with a line delimiter.
630 * line is not closed with a line delimiter.
631631 *
632632 * @param line the line of interest
633 * @return the line's delimiter or <code>null</code> if line does not have a delimiter
633 * @return the line's delimiter or <code>null</code> if line does not have a delimiter
634634 * @exception BadLocationException if the line number is invalid in this document
635635 */
636636 String getLineDelimiter(int line) throws BadLocationException;
4747 String[] getManagingPositionCategories();
4848
4949
50 /* zero-length partition support */
50 /* zero-length partition support */
5151
52 /**
52 /**
5353 * Returns the content type of the partition containing the given offset in
5454 * the connected document. There must be a document connected to this
5555 * partitioner.
7070 * a delimited partition starting at <code>offset</code>
7171 * @return the content type of the offset's partition
7272 */
73 String getContentType(int offset, boolean preferOpenPartitions);
73 String getContentType(int offset, boolean preferOpenPartitions);
7474
75 /**
75 /**
7676 * Returns the partition containing the given offset of the connected
7777 * document. There must be a document connected to this partitioner.
7878 * <p>
9292 * a delimited partition starting at <code>offset</code>
9393 * @return the partition containing the offset
9494 */
95 ITypedRegion getPartition(int offset, boolean preferOpenPartitions);
95 ITypedRegion getPartition(int offset, boolean preferOpenPartitions);
9696
97 /**
97 /**
9898 * Returns the partitioning of the given range of the connected document.
9999 * There must be a document connected to this partitioner.
100100 * <p>
117117 * partitioning
118118 * @return the partitioning of the range
119119 */
120 ITypedRegion[] computePartitioning(int offset, int length, boolean includeZeroLengthPartitions);
120 ITypedRegion[] computePartitioning(int offset, int length, boolean includeZeroLengthPartitions);
121121 }
2828 */
2929 public interface ISynchronizable {
3030
31 /**
31 /**
3232 * Sets the lock object for this object. If the lock object is not
3333 * <code>null</code> subsequent calls to specified methods of this object
3434 * are synchronized on this lock object. Which methods are synchronized is
4040 *
4141 * @param lockObject the lock object. May be <code>null</code>.
4242 */
43 void setLockObject(Object lockObject);
43 void setLockObject(Object lockObject);
4444
45 /**
45 /**
4646 * Returns the lock object or <code>null</code> if there is none. Clients
4747 * should use the lock object in order to synchronize concurrent access to
4848 * the implementer.
4949 *
5050 * @return the lock object or <code>null</code>
5151 */
52 Object getLockObject();
52 Object getLockObject();
5353 }
00 /*******************************************************************************
1 * Copyright (c) 2000, 2008 IBM Corporation and others.
1 * Copyright (c) 2000, 2019 IBM Corporation and others.
22 *
33 * This program and the accompanying materials
44 * are made available under the terms of the Eclipse Public License 2.0
329329 if (text != null) {
330330 fTextLength= text.length();
331331 createLines(text, 0, 0);
332 } else {
333 fTextLength= 0;
332334 }
333335 }
334336
171171 *
172172 * @param tracker the list line tracker
173173 */
174 TreeLineTracker(ListLineTracker tracker) {
175 final List<Line> lines= tracker.getLines();
176 final int n= lines.size();
177 if (n == 0)
178 return;
179
180 Line line= lines.get(0);
181 String delim= line.delimiter;
182 if (delim == null)
183 delim= NO_DELIM;
184 int length= line.length;
185 fRoot= new Node(length, delim);
186 Node node= fRoot;
174 TreeLineTracker(ListLineTracker tracker) {
175 final List<Line> lines= tracker.getLines();
176 final int n= lines.size();
177 if (n == 0)
178 return;
179
180 Line line= lines.get(0);
181 String delim= line.delimiter;
182 if (delim == null)
183 delim= NO_DELIM;
184 int length= line.length;
185 fRoot= new Node(length, delim);
186 Node node= fRoot;
187187
188188 for (int i= 1; i < n; i++) {
189 line= lines.get(i);
190 delim= line.delimiter;
191 if (delim == null)
192 delim= NO_DELIM;
193 length= line.length;
189 line= lines.get(i);
190 delim= line.delimiter;
191 if (delim == null)
192 delim= NO_DELIM;
193 length= line.length;
194194 node= insertAfter(node, length, delim);
195 }
195 }
196196
197197 if (node.delimiter != NO_DELIM)
198198 insertAfter(node, 0, NO_DELIM);
199199
200200 if (ASSERT) checkTree();
201 }
201 }
202202
203203 /**
204204 * Returns the node (line) including a certain offset. If the offset is between two
174174 }
175175 }
176176
177 /**
178 * Tries to nest the given <code>LinkedModeModel</code> onto the top of
179 * the stack of environments managed by the receiver. If <code>force</code>
180 * is <code>true</code>, any environments on the stack that create a conflict
181 * are killed.
182 *
183 * @param model the model to nest
184 * @param force whether to force the addition of the model
185 * @return <code>true</code> if nesting was successful, <code>false</code> otherwise (only possible if <code>force</code> is <code>false</code>
186 */
187 public boolean nestEnvironment(LinkedModeModel model, boolean force) {
188 Assert.isNotNull(model);
189
190 try {
191 while (true) {
192 if (fEnvironments.isEmpty()) {
193 model.addLinkingListener(fListener);
194 fEnvironments.push(model);
195 return true;
196 }
197
198 LinkedModeModel top= fEnvironments.peek();
199 if (model.canNestInto(top)) {
200 model.addLinkingListener(fListener);
201 fEnvironments.push(model);
202 return true;
203 } else if (!force) {
204 return false;
205 } else { // force
206 fEnvironments.pop();
207 top.exit(ILinkedModeListener.NONE);
208 // continue;
209 }
210 }
211 } finally {
212 // if we remove any, make sure the new one got inserted
213 Assert.isTrue(fEnvironments.size() > 0);
214 }
215 }
177 /**
178 * Tries to nest the given <code>LinkedModeModel</code> onto the top of
179 * the stack of environments managed by the receiver. If <code>force</code>
180 * is <code>true</code>, any environments on the stack that create a conflict
181 * are killed.
182 *
183 * @param model the model to nest
184 * @param force whether to force the addition of the model
185 * @return <code>true</code> if nesting was successful, <code>false</code> otherwise (only possible if <code>force</code> is <code>false</code>
186 */
187 public boolean nestEnvironment(LinkedModeModel model, boolean force) {
188 Assert.isNotNull(model);
189
190 try {
191 while (true) {
192 if (fEnvironments.isEmpty()) {
193 model.addLinkingListener(fListener);
194 fEnvironments.push(model);
195 return true;
196 }
197
198 LinkedModeModel top= fEnvironments.peek();
199 if (model.canNestInto(top)) {
200 model.addLinkingListener(fListener);
201 fEnvironments.push(model);
202 return true;
203 } else if (!force) {
204 return false;
205 } else { // force
206 fEnvironments.pop();
207 top.exit(ILinkedModeListener.NONE);
208 // continue;
209 }
210 }
211 } finally {
212 // if we remove any, make sure the new one got inserted
213 Assert.isTrue(fEnvironments.size() > 0);
214 }
215 }
216216
217217 /**
218218 * Returns the <code>LinkedModeModel</code> that is on top of the stack of
504504 // register positions
505505 try {
506506 for (LinkedPositionGroup group : fGroups) {
507 group.register(this);
508 }
507 group.register(this);
508 }
509509 return true;
510510 } catch (BadLocationException e){
511511 // if we fail to add, make sure to release all listeners again
519519 * model, throws an IllegalStateException otherwise.
520520 */
521521 private void enforceNotEmpty() {
522 boolean hasPosition= false;
522 boolean hasPosition= false;
523523 for (LinkedPositionGroup linkedPositionGroup : fGroups)
524524 if (!linkedPositionGroup.isEmpty()) {
525525 hasPosition= true;
528528 if (!hasPosition)
529529 throw new IllegalStateException("must specify at least one linked position"); //$NON-NLS-1$
530530
531 }
532
533 /**
531 }
532
533 /**
534534 * Collects all the documents that contained positions are set upon.
535 * @return the set of documents affected by this model
536 */
537 private IDocument[] getDocuments() {
538 Set<IDocument> docs= new HashSet<>();
539 for (LinkedPositionGroup group : fGroups) {
540 docs.addAll(Arrays.asList(group.getDocuments()));
541 }
542 return docs.toArray(new IDocument[docs.size()]);
543 }
544
545 /**
546 * Returns whether the receiver can be nested into the given <code>parent</code>
547 * model. If yes, the parent model and its position that the receiver
548 * fits in are remembered.
549 *
550 * @param parent the parent model candidate
551 * @return <code>true</code> if the receiver can be nested into <code>parent</code>, <code>false</code> otherwise
552 */
553 boolean canNestInto(LinkedModeModel parent) {
554 for (LinkedPositionGroup group : fGroups) {
535 * @return the set of documents affected by this model
536 */
537 private IDocument[] getDocuments() {
538 Set<IDocument> docs= new HashSet<>();
539 for (LinkedPositionGroup group : fGroups) {
540 docs.addAll(Arrays.asList(group.getDocuments()));
541 }
542 return docs.toArray(new IDocument[docs.size()]);
543 }
544
545 /**
546 * Returns whether the receiver can be nested into the given <code>parent</code>
547 * model. If yes, the parent model and its position that the receiver
548 * fits in are remembered.
549 *
550 * @param parent the parent model candidate
551 * @return <code>true</code> if the receiver can be nested into <code>parent</code>, <code>false</code> otherwise
552 */
553 boolean canNestInto(LinkedModeModel parent) {
554 for (LinkedPositionGroup group : fGroups) {
555555 if (!enforceNestability(group, parent)) {
556556 fParentPosition= null;
557557 return false;
558558 }
559559 }
560560
561 Assert.isNotNull(fParentPosition);
562 fParentEnvironment= parent;
563 return true;
564 }
565
566 /**
561 Assert.isNotNull(fParentPosition);
562 fParentEnvironment= parent;
563 return true;
564 }
565
566 /**
567567 * Called by nested models when a group is added to them. All
568568 * positions in all groups of a nested model have to fit inside a
569569 * single position in the parent model.
320320
321321 void register(LinkedModeModel model) throws BadLocationException {
322322 for (LinkedPosition pos : fPositions) {
323 model.register(pos);
324 }
323 model.register(pos);
324 }
325325 }
326326
327327 /**
3030 */
3131 class AnnotationMap implements IAnnotationMap {
3232
33 /**
34 * The lock object used to synchronize the operations explicitly defined by
35 * <code>IAnnotationMap</code>
36 */
37 private Object fLockObject;
38 /**
39 * The internal lock object used if <code>fLockObject</code> is <code>null</code>.
33 /**
34 * The lock object used to synchronize the operations explicitly defined by
35 * <code>IAnnotationMap</code>
36 */
37 private Object fLockObject;
38 /**
39 * The internal lock object used if <code>fLockObject</code> is <code>null</code>.
4040 * @since 3.2
4141 */
42 private final Object fInternalLockObject= new Object();
42 private final Object fInternalLockObject= new Object();
4343
44 /** The map holding the annotations */
45 private Map<Annotation, Position> fInternalMap;
44 /** The map holding the annotations */
45 private Map<Annotation, Position> fInternalMap;
4646
47 /**
48 * Creates a new annotation map with the given capacity.
49 *
50 * @param capacity the capacity
51 */
52 public AnnotationMap(int capacity) {
53 fInternalMap= new HashMap<>(capacity);
54 }
47 /**
48 * Creates a new annotation map with the given capacity.
49 *
50 * @param capacity the capacity
51 */
52 public AnnotationMap(int capacity) {
53 fInternalMap= new HashMap<>(capacity);
54 }
5555
56 @Override
56 @Override
5757 public synchronized void setLockObject(Object lockObject) {
58 fLockObject= lockObject;
59 }
58 fLockObject= lockObject;
59 }
6060
61 @Override
61 @Override
6262 public synchronized Object getLockObject() {
63 if (fLockObject == null)
64 return fInternalLockObject;
65 return fLockObject;
66 }
63 if (fLockObject == null)
64 return fInternalLockObject;
65 return fLockObject;
66 }
6767
68 @Override
68 @Override
6969 public Iterator<Position> valuesIterator() {
70 synchronized (getLockObject()) {
71 return new ArrayList<>(fInternalMap.values()).iterator();
72 }
73 }
70 synchronized (getLockObject()) {
71 return new ArrayList<>(fInternalMap.values()).iterator();
72 }
73 }
7474
75 @Override
75 @Override
7676 public Iterator<Annotation> keySetIterator() {
77 synchronized (getLockObject()) {
78 return new ArrayList<>(fInternalMap.keySet()).iterator();
79 }
80 }
77 synchronized (getLockObject()) {
78 return new ArrayList<>(fInternalMap.keySet()).iterator();
79 }
80 }
8181
82 @Override
82 @Override
8383 public boolean containsKey(Object annotation) {
84 synchronized (getLockObject()) {
85 return fInternalMap.containsKey(annotation);
86 }
87 }
84 synchronized (getLockObject()) {
85 return fInternalMap.containsKey(annotation);
86 }
87 }
8888
89 @Override
89 @Override
9090 public Position put(Annotation annotation, Position position) {
91 synchronized (getLockObject()) {
92 return fInternalMap.put(annotation, position);
93 }
94 }
91 synchronized (getLockObject()) {
92 return fInternalMap.put(annotation, position);
93 }
94 }
9595
96 @Override
96 @Override
9797 public Position get(Object annotation) {
98 synchronized (getLockObject()) {
99 return fInternalMap.get(annotation);
100 }
101 }
98 synchronized (getLockObject()) {
99 return fInternalMap.get(annotation);
100 }
101 }
102102
103 @Override
103 @Override
104104 public void clear() {
105 synchronized (getLockObject()) {
106 fInternalMap.clear();
107 }
108 }
105 synchronized (getLockObject()) {
106 fInternalMap.clear();
107 }
108 }
109109
110 @Override
110 @Override
111111 public Position remove(Object annotation) {
112 synchronized (getLockObject()) {
113 return fInternalMap.remove(annotation);
114 }
115 }
112 synchronized (getLockObject()) {
113 return fInternalMap.remove(annotation);
114 }
115 }
116116
117 @Override
117 @Override
118118 public int size() {
119 synchronized (getLockObject()) {
120 return fInternalMap.size();
121 }
122 }
119 synchronized (getLockObject()) {
120 return fInternalMap.size();
121 }
122 }
123123
124 @Override
124 @Override
125125 public boolean isEmpty() {
126 synchronized (getLockObject()) {
126 synchronized (getLockObject()) {
127127 return fInternalMap.isEmpty();
128128 }
129 }
129 }
130130
131131 @Override
132132 public boolean containsValue(Object value) {
329329 return (IAnnotationMap) fAnnotations;
330330 }
331331
332 @Override
332 @Override
333333 public Object getLockObject() {
334 return getAnnotationMap().getLockObject();
335 }
336
337 @Override
334 return getAnnotationMap().getLockObject();
335 }
336
337 @Override
338338 public void setLockObject(Object lockObject) {
339 getAnnotationMap().setLockObject(lockObject);
340 }
341
342 /**
343 * Returns the current annotation model event. This is the event that will be sent out
344 * when calling <code>fireModelChanged</code>.
345 *
346 * @return the current annotation model event
347 * @since 3.0
348 */
349 protected final AnnotationModelEvent getAnnotationModelEvent() {
350 synchronized (getLockObject()) {
351 if (fModelEvent == null) {
352 fModelEvent= createAnnotationModelEvent();
353 fModelEvent.markWorldChange(false);
354 fModificationStamp= new Object();
355 }
356 return fModelEvent;
357 }
358 }
339 getAnnotationMap().setLockObject(lockObject);
340 }
341
342 /**
343 * Returns the current annotation model event. This is the event that will be sent out
344 * when calling <code>fireModelChanged</code>.
345 *
346 * @return the current annotation model event
347 * @since 3.0
348 */
349 protected final AnnotationModelEvent getAnnotationModelEvent() {
350 synchronized (getLockObject()) {
351 if (fModelEvent == null) {
352 fModelEvent= createAnnotationModelEvent();
353 fModelEvent.markWorldChange(false);
354 fModificationStamp= new Object();
355 }
356 return fModelEvent;
357 }
358 }
359359
360360 @Override
361361 public void addAnnotation(Annotation annotation, Position position) {
441441 IAnnotationModelListenerExtension extension= (IAnnotationModelListenerExtension) listener;
442442 AnnotationModelEvent event= createAnnotationModelEvent();
443443 event.markSealed();
444 extension.modelChanged(event);
444 extension.modelChanged(event);
445445 } else
446 listener.modelChanged(this);
446 listener.modelChanged(this);
447447 }
448448 }
449449
3535 * @param string the string
3636 * @param variables the variable positions
3737 */
38 public TemplateBuffer(String string, TemplateVariable[] variables) {
38 public TemplateBuffer(String string, TemplateVariable[] variables) {
3939 setContent(string, variables);
40 }
40 }
4141
4242 /**
4343 * Sets the content of the template buffer.
8484 * @return the id of the receiver
8585 */
8686 public String getId() {
87 return fId;
87 return fId;
8888 }
8989
9090
234234 List<RangeMarker> positions= variablesToPositions(variables);
235235 List<ReplaceEdit> edits= new ArrayList<>(5);
236236
237 // iterate over all variables and try to resolve them
238 for (int i= 0; i != variables.length; i++) {
239 TemplateVariable variable= variables[i];
237 // iterate over all variables and try to resolve them
238 for (int i= 0; i != variables.length; i++) {
239 TemplateVariable variable= variables[i];
240240
241241 if (!variable.isResolved())
242242 resolve(variable, context);
247247 for (int k= 0; k != offsets.length; k++)
248248 edits.add(new ReplaceEdit(offsets[k], variable.getInitialLength(), value));
249249
250 }
251
252 IDocument document= new Document(buffer.getString());
253 MultiTextEdit edit= new MultiTextEdit(0, document.getLength());
254 edit.addChildren(positions.toArray(new TextEdit[positions.size()]));
255 edit.addChildren(edits.toArray(new TextEdit[edits.size()]));
256 edit.apply(document, TextEdit.UPDATE_REGIONS);
250 }
251
252 IDocument document= new Document(buffer.getString());
253 MultiTextEdit edit= new MultiTextEdit(0, document.getLength());
254 edit.addChildren(positions.toArray(new TextEdit[positions.size()]));
255 edit.addChildren(edits.toArray(new TextEdit[edits.size()]));
256 edit.apply(document, TextEdit.UPDATE_REGIONS);
257257
258258 positionsToVariables(positions, variables);
259259
260 buffer.setContent(document.get(), variables);
261 }
260 buffer.setContent(document.get(), variables);
261 }
262262
263263 /**
264264 * Resolves a single variable in a context. Resolving is delegated to the registered resolver.
276276 }
277277
278278 private static List<RangeMarker> variablesToPositions(TemplateVariable[] variables) {
279 List<RangeMarker> positions= new ArrayList<>(5);
279 List<RangeMarker> positions= new ArrayList<>(5);
280280 for (int i= 0; i != variables.length; i++) {
281 int[] offsets= variables[i].getOffsets();
282 for (int j= 0; j != offsets.length; j++)
281 int[] offsets= variables[i].getOffsets();
282 for (int j= 0; j != offsets.length; j++)
283283 positions.add(new RangeMarker(offsets[j], 0));
284284 }
285285
290290 Iterator<RangeMarker> iterator= positions.iterator();
291291
292292 for (int i= 0; i != variables.length; i++) {
293 TemplateVariable variable= variables[i];
293 TemplateVariable variable= variables[i];
294294
295295 int[] offsets= new int[variable.getOffsets().length];
296296 for (int j= 0; j != offsets.length; j++)
140140 * @return the type name of the variable
141141 */
142142 public String getType() {
143 return fType.getName();
143 return fType.getName();
144144 }
145145
146146 /**
159159 * @return the name of the variable
160160 */
161161 public String getName() {
162 return fName;
162 return fName;
163163 }
164164
165165 /**
250250 * @param unambiguous the new unambiguous state of the variable
251251 */
252252 public void setUnambiguous(boolean unambiguous) {
253 fIsUnambiguous= unambiguous;
254 if (unambiguous)
255 setResolved(true);
253 fIsUnambiguous= unambiguous;
254 if (unambiguous)
255 setResolved(true);
256256 }
257257
258258 /**
109109 * @since 3.3
110110 */
111111 public boolean removeTextEdit(TextEdit edit) {
112 return fEdits.remove(edit);
112 return fEdits.remove(edit);
113113 }
114114
115115 /**
118118 * @since 3.3
119119 */
120120 public void clearTextEdits() {
121 fEdits.clear();
121 fEdits.clear();
122122 }
123123
124124
126126 @Override
127127 public void preferenceChange(PreferenceChangeEvent event) {
128128 /*
129 * Don't load if we are in the process of saving ourselves. We are in sync anyway after the
130 * save operation, and clients may trigger reloading by listening to preference store
131 * updates.
132 */
133 if (!fIgnorePreferenceStoreChanges && fKey.equals(event.getKey()))
134 try {
135 load();
136 } catch (IOException x) {
137 handleException(x);
138 }
129 * Don't load if we are in the process of saving ourselves. We are in sync anyway after the
130 * save operation, and clients may trigger reloading by listening to preference store
131 * updates.
132 */
133 if (!fIgnorePreferenceStoreChanges && fKey.equals(event.getKey()))
134 try {
135 load();
136 } catch (IOException x) {
137 handleException(x);
138 }
139139 }
140140 };
141141 fPreferenceStore.addPreferenceChangeListener(fPropertyListener);
140140 */
141141 protected void undoTextChange() {
142142 try {
143 if (fDocumentUndoManager.fDocument instanceof IDocumentExtension4)
143 if (fDocumentUndoManager.fDocument instanceof IDocumentExtension4) {
144144 ((IDocumentExtension4) fDocumentUndoManager.fDocument).replace(fStart, fText
145145 .length(), fPreservedText, fUndoModificationStamp);
146 else
146 } else {
147147 fDocumentUndoManager.fDocument.replace(fStart, fText.length(),
148148 fPreservedText);
149 }
149150 } catch (BadLocationException x) {
150151 }
151152 }
267268 */
268269 protected void redoTextChange() {
269270 try {
270 if (fDocumentUndoManager.fDocument instanceof IDocumentExtension4)
271 if (fDocumentUndoManager.fDocument instanceof IDocumentExtension4) {
271272 ((IDocumentExtension4) fDocumentUndoManager.fDocument).replace(fStart, fEnd - fStart, fText, fRedoModificationStamp);
272 else
273 } else {
273274 fDocumentUndoManager.fDocument.replace(fStart, fEnd - fStart, fText);
275 }
274276 } catch (BadLocationException x) {
275277 }
276278 }
313315 * @return a new, uncommitted text change or a compound text change
314316 */
315317 protected UndoableTextChange createCurrent() {
316 if (fDocumentUndoManager.fFoldingIntoCompoundChange)
318 if (fDocumentUndoManager.fFoldingIntoCompoundChange) {
317319 return new UndoableCompoundTextChange(fDocumentUndoManager);
320 }
318321 return new UndoableTextChange(fDocumentUndoManager);
319322 }
320323
452455 UndoableTextChange c;
453456
454457 c= fChanges.get(0);
455 fDocumentUndoManager.fireDocumentUndo(c.fStart, c.fPreservedText, c.fText, uiInfo, DocumentUndoEvent.ABOUT_TO_UNDO, true);
458 fDocumentUndoManager.fireDocumentUndo(c.fStart, c.fPreservedText, c.fText, uiInfo, DocumentUndoEvent.ABOUT_TO_UNDO, size > 1);
456459
457460 for (int i= size - 1; i >= 0; --i) {
458461 c= fChanges.get(i);
460463 }
461464 fDocumentUndoManager.resetProcessChangeState();
462465 fDocumentUndoManager.fireDocumentUndo(c.fStart, c.fPreservedText, c.fText, uiInfo,
463 DocumentUndoEvent.UNDONE, true);
466 DocumentUndoEvent.UNDONE, size > 1);
464467 }
465468 return Status.OK_STATUS;
466469 }
473476
474477 UndoableTextChange c;
475478 c= fChanges.get(size - 1);
476 fDocumentUndoManager.fireDocumentUndo(c.fStart, c.fText, c.fPreservedText, uiInfo, DocumentUndoEvent.ABOUT_TO_REDO, true);
479 fDocumentUndoManager.fireDocumentUndo(c.fStart, c.fText, c.fPreservedText, uiInfo, DocumentUndoEvent.ABOUT_TO_REDO, size > 1);
477480
478481 for (int i= 0; i <= size - 1; ++i) {
479482 c= fChanges.get(i);
480483 c.redoTextChange();
481484 }
482485 fDocumentUndoManager.resetProcessChangeState();
483 fDocumentUndoManager.fireDocumentUndo(c.fStart, c.fText, c.fPreservedText, uiInfo, DocumentUndoEvent.REDONE, true);
486 fDocumentUndoManager.fireDocumentUndo(c.fStart, c.fText, c.fPreservedText, uiInfo, DocumentUndoEvent.REDONE, size > 1);
484487 }
485488
486489 return Status.OK_STATUS;
508511 @Override
509512 protected UndoableTextChange createCurrent() {
510513
511 if (!fDocumentUndoManager.fFoldingIntoCompoundChange)
514 if (!fDocumentUndoManager.fFoldingIntoCompoundChange) {
512515 return new UndoableTextChange(fDocumentUndoManager);
516 }
513517
514518 reinitialize();
515519 return this;
518522 @Override
519523 protected void commit() {
520524 // if there is pending data, update the text change
521 if (fStart > -1)
525 if (fStart > -1) {
522526 updateTextChange();
527 }
523528 fDocumentUndoManager.fCurrent= createCurrent();
524529 fDocumentUndoManager.resetProcessChangeState();
525530 }
531536
532537 @Override
533538 protected long getUndoModificationStamp() {
534 if (fStart > -1)
539 if (fStart > -1) {
535540 return super.getUndoModificationStamp();
536 else if (fChanges.size() > 0)
541 } else if (fChanges.size() > 0) {
537542 return fChanges.get(0)
538543 .getUndoModificationStamp();
544 }
539545
540546 return fUndoModificationStamp;
541547 }
542548
543549 @Override
544550 protected long getRedoModificationStamp() {
545 if (fStart > -1)
551 if (fStart > -1) {
546552 return super.getRedoModificationStamp();
547 else if (fChanges.size() > 0)
553 } else if (fChanges.size() > 0) {
548554 return fChanges.get(fChanges.size() - 1)
549555 .getRedoModificationStamp();
556 }
550557
551558 return fRedoModificationStamp;
552559 }
580587 // top operation but changes state.
581588 IUndoableOperation op= fHistory.getUndoOperation(fUndoContext);
582589 boolean wasValid= false;
583 if (op != null)
590 if (op != null) {
584591 wasValid= op.canUndo();
592 }
585593 // Process the change, providing the before and after timestamps
586594 processChange(event.getOffset(), event.getOffset()
587595 + event.getLength(), event.getText(), fReplacedText,
597605 // created, then we should
598606 // notify the history that the current operation changed if its
599607 // validity has changed.
600 if (wasValid != fCurrent.isValid())
608 if (wasValid != fCurrent.isValid()) {
601609 fHistory.operationChanged(op);
610 }
602611 } else {
603612 // if the change created a new fCurrent that we did not yet add
604613 // to the
780789 // single document change.
781790 if (fLastAddedTextEdit != fCurrent) {
782791 fCurrent.pretendCommit();
783 if (fCurrent.isValid())
792 if (fCurrent.isValid()) {
784793 addToOperationHistory(fCurrent);
794 }
785795 }
786796 fCurrent.commit();
787797 }
809819 */
810820 @Override
811821 public void redo() throws ExecutionException {
812 if (isConnected() && redoable())
822 if (isConnected() && redoable()) {
813823 OperationHistoryFactory.getOperationHistory().redo(getUndoContext(), null, null);
824 }
814825 }
815826
816827 @Override
817828 public void undo() throws ExecutionException {
818 if (undoable())
829 if (undoable()) {
819830 OperationHistoryFactory.getOperationHistory().undo(fUndoContext, null, null);
831 }
820832 }
821833
822834 @Override
824836 if (!isConnected()) {
825837 initialize();
826838 }
827 if (!fConnected.contains(client))
839 if (!fConnected.contains(client)) {
828840 fConnected.add(client);
841 }
829842 }
830843
831844 @Override
923936 * Initializes the undo history.
924937 */
925938 private void initializeUndoHistory() {
926 if (fHistory != null && fUndoContext != null)
939 if (fHistory != null && fUndoContext != null) {
927940 fHistory.dispose(fUndoContext, true, true, false);
941 }
928942
929943 }
930944
938952 */
939953 private boolean isWhitespaceText(String text) {
940954
941 if (text == null || text.length() == 0)
955 if (text == null || text.length() == 0) {
942956 return false;
957 }
943958
944959 String[] delimiters= fDocument.getLegalLineDelimiters();
945960 int index= TextUtilities.startsWith(delimiters, text);
948963 int length= text.length();
949964 for (int i= delimiters[index].length(); i < length; i++) {
950965 c= text.charAt(i);
951 if (c != ' ' && c != '\t')
966 if (c != ' ' && c != '\t') {
952967 return false;
968 }
953969 }
954970 return true;
955971 }
982998 final long afterChangeModificationStamp) {
983999
9841000 if (insertedText == null)
1001 {
9851002 insertedText= ""; //$NON-NLS-1$
1003 }
9861004
9871005 if (replacedText == null)
1006 {
9881007 replacedText= ""; //$NON-NLS-1$
1008 }
9891009
9901010 int length= insertedText.length();
9911011 int diff= modelEnd - modelStart;
9921012
993 if (fCurrent.fUndoModificationStamp == IDocumentExtension4.UNKNOWN_MODIFICATION_STAMP)
1013 if (fCurrent.fUndoModificationStamp == IDocumentExtension4.UNKNOWN_MODIFICATION_STAMP) {
9941014 fCurrent.fUndoModificationStamp= beforeChangeModificationStamp;
1015 }
9951016
9961017 // normalize
9971018 if (diff < 0) {
10081029 || (modelStart != fCurrent.fStart
10091030 + fTextBuffer.length())) {
10101031 fCurrent.fRedoModificationStamp= beforeChangeModificationStamp;
1011 if (fCurrent.attemptCommit())
1032 if (fCurrent.attemptCommit()) {
10121033 fCurrent.fUndoModificationStamp= beforeChangeModificationStamp;
1034 }
10131035
10141036 fInserting= true;
10151037 }
1016 if (fCurrent.fStart < 0)
1038 if (fCurrent.fStart < 0) {
10171039 fCurrent.fStart= fCurrent.fEnd= modelStart;
1018 if (length > 0)
1040 }
1041 if (length > 0) {
10191042 fTextBuffer.append(insertedText);
1043 }
10201044 } else if (length > 0) {
10211045 // by pasting or model manipulation
10221046 fCurrent.fRedoModificationStamp= beforeChangeModificationStamp;
1023 if (fCurrent.attemptCommit())
1047 if (fCurrent.attemptCommit()) {
10241048 fCurrent.fUndoModificationStamp= beforeChangeModificationStamp;
1049 }
10251050
10261051 fCurrent.fStart= fCurrent.fEnd= modelStart;
10271052 fTextBuffer.append(insertedText);
10281053 fCurrent.fRedoModificationStamp= afterChangeModificationStamp;
1029 if (fCurrent.attemptCommit())
1054 if (fCurrent.attemptCommit()) {
10301055 fCurrent.fUndoModificationStamp= afterChangeModificationStamp;
1056 }
10311057
10321058 }
10331059 } else {
10671093 // either DEL or backspace for the first time
10681094
10691095 fCurrent.fRedoModificationStamp= beforeChangeModificationStamp;
1070 if (fCurrent.attemptCommit())
1096 if (fCurrent.attemptCommit()) {
10711097 fCurrent.fUndoModificationStamp= beforeChangeModificationStamp;
1098 }
10721099
10731100 // as we can not decide whether it was DEL or backspace
10741101 // we initialize for backspace
10821109 } else if (length > 0) {
10831110 // whereby selection is not empty
10841111 fCurrent.fRedoModificationStamp= beforeChangeModificationStamp;
1085 if (fCurrent.attemptCommit())
1112 if (fCurrent.attemptCommit()) {
10861113 fCurrent.fUndoModificationStamp= beforeChangeModificationStamp;
1114 }
10871115
10881116 fCurrent.fStart= modelStart;
10891117 fCurrent.fEnd= modelEnd;
11031131 || (modelStart != fCurrent.fStart
11041132 + fTextBuffer.length())) {
11051133 fCurrent.fRedoModificationStamp= beforeChangeModificationStamp;
1106 if (fCurrent.attemptCommit())
1134 if (fCurrent.attemptCommit()) {
11071135 fCurrent.fUndoModificationStamp= beforeChangeModificationStamp;
1136 }
11081137
11091138 fOverwriting= true;
11101139 }
11111140
1112 if (fCurrent.fStart < 0)
1141 if (fCurrent.fStart < 0) {
11131142 fCurrent.fStart= modelStart;
1143 }
11141144
11151145 fCurrent.fEnd= modelEnd;
11161146 fTextBuffer.append(insertedText);
11211151 }
11221152 // because of typing or pasting whereby selection is not empty
11231153 fCurrent.fRedoModificationStamp= beforeChangeModificationStamp;
1124 if (fCurrent.attemptCommit())
1154 if (fCurrent.attemptCommit()) {
11251155 fCurrent.fUndoModificationStamp= beforeChangeModificationStamp;
1156 }
11261157
11271158 fCurrent.fStart= modelStart;
11281159 fCurrent.fEnd= modelEnd;
11821213 * clients, <code>false</code> if it is not
11831214 */
11841215 boolean isConnected() {
1185 if (fConnected == null)
1216 if (fConnected == null) {
11861217 return false;
1218 }
11871219 return !fConnected.isEmpty();
11881220 }
11891221
12081240 }
12091241
12101242 IUndoableOperation op= OperationHistoryFactory.getOperationHistory().getUndoOperation(getUndoContext());
1211 if (op != null && !(op instanceof UndoableTextChange))
1243 if (op != null && !(op instanceof UndoableTextChange)) {
12121244 return;
1245 }
12131246
12141247 // Record the transfer itself as an undoable change.
12151248 // If the transfer results from some open operation, recording this change will
12211254 cmd.fText= cmd.fPreservedText= ""; //$NON-NLS-1$
12221255 if (fDocument instanceof IDocumentExtension4) {
12231256 cmd.fRedoModificationStamp= ((IDocumentExtension4)fDocument).getModificationStamp();
1224 if (op != null)
1257 if (op != null) {
12251258 cmd.fUndoModificationStamp= ((UndoableTextChange)op).fRedoModificationStamp;
1259 }
12261260 }
12271261 addToOperationHistory(cmd);
12281262 }
11 Bundle-ManifestVersion: 2
22 Bundle-Name: %Plugin.name
33 Bundle-SymbolicName: org.eclipse.text.tests
4 Bundle-Version: 3.12.100.qualifier
4 Bundle-Version: 3.12.200.qualifier
55 Bundle-Vendor: %Plugin.providerName
66 Bundle-Localization: plugin
77 Export-Package:
1313 <parent>
1414 <artifactId>tests-pom</artifactId>
1515 <groupId>eclipse.platform.text</groupId>
16 <version>4.11.0-SNAPSHOT</version>
16 <version>4.12.0-SNAPSHOT</version>
1717 <relativePath>../tests-pom/</relativePath>
1818 </parent>
1919 <groupId>org.eclipse.text</groupId>
2020 <artifactId>org.eclipse.text.tests</artifactId>
21 <version>3.12.100-SNAPSHOT</version>
21 <version>3.12.200-SNAPSHOT</version>
2222 <packaging>eclipse-test-plugin</packaging>
2323 <properties>
2424 <testSuite>${project.artifactId}</testSuite>
4949 protected final void set(String string) {
5050 fText.set(string);
5151 fTracker.set(string);
52 }
52 }
5353
5454 }
156156
157157 @Test
158158 public void testRemoveReallocateBeforeGap() throws Exception {
159 fText.replace(0, 0, "yyyyyzzzzz");
160 assertGap(10, 15);
161 assertContents("yyyyyzzzzzxxxxx");
159 fText.replace(0, 0, "yyyyyzzzzz");
160 assertGap(10, 15);
161 assertContents("yyyyyzzzzzxxxxx");
162162
163 fText.replace(2, 6, null);
164 assertGap(2, 5);
165 assertContents("yyzzxxxxx");
166 }
163 fText.replace(2, 6, null);
164 assertGap(2, 5);
165 assertContents("yyzzxxxxx");
166 }
167167 }
159159
160160 @Test
161161 public void testRemoveReallocateBeforeGap() throws Exception {
162 fText.replace(0, 0, "yyyyyzzzzz");
163 assertGap(10, 15);
164 assertContents("yyyyyzzzzzxxxxx");
162 fText.replace(0, 0, "yyyyyzzzzz");
163 assertGap(10, 15);
164 assertContents("yyyyyzzzzzxxxxx");
165165
166 fText.replace(2, 6, null);
167 assertGap(2, 7);
168 assertContents("yyzzxxxxx");
169 }
166 fText.replace(2, 6, null);
167 assertGap(2, 7);
168 assertContents("yyzzxxxxx");
169 }
170170 }
00 /*******************************************************************************
1 * Copyright (c) 2000, 2008 IBM Corporation and others.
1 * Copyright (c) 2000, 2019 IBM Corporation and others.
22 *
33 * This program and the accompanying materials
44 * are made available under the terms of the Eclipse Public License 2.0
381381
382382 @Test
383383 public void testNoDelimiterLine() throws Exception {
384 set("abcef");
385 checkLines(new int[] { 5 });
386
387 replace(0, 0, ""); // switch to TreeLineTracker
388 checkLines(new int[] { 5 });
389 }
384 set("abcef");
385 checkLines(new int[] { 5 });
386
387 replace(0, 0, ""); // switch to TreeLineTracker
388 checkLines(new int[] { 5 });
389 }
390390
391391 @Test
392392 public void testFunnyLastLineCompatibility2() throws Exception {
543543 } catch (BadLocationException e) {
544544 }
545545 }
546
547 /**
548 * Test for Bug 545565. Some ListLineTracker methods yield wrong results after tracker content
549 * was set to <code>null</code>.
550 *
551 * @throws BadLocationException if test failed
552 */
553 @Test
554 public void testBug545565_setNull() throws BadLocationException {
555 int initialContentLength= fText.getLength();
556 set(null);
557 assertEquals("Tracker not empty.", 1, fTracker.getNumberOfLines());
558 assertEquals("Tracker not empty.", 0, fTracker.getLineLength(0));
559 try {
560 fTracker.getLineInformationOfOffset(5);
561 fail("No exception for bad location.");
562 } catch (BadLocationException e) {
563 // expected
564 }
565 try {
566 fTracker.getLineInformationOfOffset(initialContentLength);
567 fail("No exception for bad location.");
568 } catch (BadLocationException e) {
569 // expected
570 }
571 try {
572 fTracker.getLineNumberOfOffset(5);
573 fail("No exception for bad location.");
574 } catch (BadLocationException e) {
575 // expected
576 }
577 try {
578 fTracker.getLineNumberOfOffset(initialContentLength);
579 fail("No exception for bad location.");
580 } catch (BadLocationException e) {
581 // expected
582 }
583 try {
584 fTracker.getNumberOfLines(5, 3);
585 fail("No exception for bad location.");
586 } catch (BadLocationException e) {
587 // expected
588 }
589 }
590
591 /**
592 * Check if ListLineTracker and TreeLineTracker return same result for same input in context of
593 * Bug 545565.
594 *
595 * @throws BadLocationException if test fails
596 */
597 @Test
598 public void testBug545565_compareTrackerResult() throws BadLocationException {
599 set(null);
600 int lineFromListTracker= fTracker.getLineNumberOfOffset(0);
601 replace(0, 0, null);
602 int lineFromTreeTracker= fTracker.getLineNumberOfOffset(0);
603 assertEquals("Trackers returned different lines for same offset.", lineFromTreeTracker, lineFromListTracker);
604 }
546605 }
11 Bundle-ManifestVersion: 2
22 Bundle-Name: %pluginName
33 Bundle-SymbolicName: org.eclipse.ui.editors; singleton:=true
4 Bundle-Version: 3.11.400.qualifier
4 Bundle-Version: 3.11.500.qualifier
55 Bundle-Activator: org.eclipse.ui.internal.editors.text.EditorsPlugin
66 Bundle-ActivationPolicy: lazy
77 Bundle-Vendor: %providerName
1313 <parent>
1414 <artifactId>eclipse.platform.text</artifactId>
1515 <groupId>eclipse.platform.text</groupId>
16 <version>4.11.0-SNAPSHOT</version>
16 <version>4.12.0-SNAPSHOT</version>
1717 </parent>
1818 <groupId>org.eclipse.ui</groupId>
1919 <artifactId>org.eclipse.ui.editors</artifactId>
20 <version>3.11.400-SNAPSHOT</version>
20 <version>3.11.500-SNAPSHOT</version>
2121 <packaging>eclipse-plugin</packaging>
2222 </project>
8282 * @param editor the target editor
8383 */
8484 public PredefinedEncodingAction(ResourceBundle bundle, String prefix, String encoding, ITextEditor editor) {
85 super(bundle, prefix, editor);
85 super(bundle, prefix, editor);
8686 fEncoding= encoding;
8787 if (prefix == null)
8888 setText(encoding);
9797 * @param editor the target editor
9898 */
9999 public PredefinedEncodingAction(ResourceBundle bundle, String encoding, ITextEditor editor) {
100 super(bundle, null, editor);
100 super(bundle, null, editor);
101101 fEncoding= encoding;
102102 setText(encoding);
103103 fLabel= getText();
672672
673673 IFileEditorInput input= (IFileEditorInput) element;
674674
675 try {
676 refreshFile(input.getFile());
677 } catch (CoreException x) {
678 handleCoreException(x, TextEditorMessages.FileDocumentProvider_createElementInfo);
675 // Note that file.isSynchronized does not require a scheduling rule and thus helps to identify a no-op attempt
676 // to refresh the file. The no-op will otherwise be blocked by a running build or cancel a running build
677 IFile file= input.getFile();
678 if (!file.isSynchronized(IResource.DEPTH_ZERO)) {
679 try {
680 refreshFile(file);
681 } catch (CoreException x) {
682 handleCoreException(x, TextEditorMessages.FileDocumentProvider_createElementInfo);
683 }
679684 }
680685
681686 IDocument d= null;
11271132 protected ISchedulingRule getValidateStateRule(Object element) {
11281133 if (element instanceof IFileEditorInput) {
11291134 IFileEditorInput input= (IFileEditorInput) element;
1130 return fResourceRuleFactory.validateEditRule(new IResource[] { input.getFile() });
1135 IFile file= input.getFile();
1136 ISchedulingRule validateEditRule= fResourceRuleFactory.validateEditRule(new IResource[] { file });
1137 if (validateEditRule == null) {
1138 // Note that factory decides to provide a null rule for modifiable files (not read-only).
1139 // Null rule means, that org.eclipse.core.internal.resources.WorkManager.checkIn(ISchedulingRule, IProgressMonitor)
1140 // will run jobManager.beginRule(null, monitor); which will NOT show any progress dialog
1141 // and will *immediately* lock UI thread via lock.acquire(); while the workspace is locked
1142 // Providing here a file we enforce the progress dialog, where this operation can be cancelled by user,
1143 // so that an occasional "Modify" or "Save" of the editor will NOT block UI forever.
1144 return file;
1145 } else {
1146 return validateEditRule;
1147 }
11311148 }
11321149 return null;
11331150 }
9696 /**
9797 * Installs the encoding support on the given text editor.
9898 * <p>
99 * Subclasses may override to install their own encoding
100 * support or to disable the default encoding support.
101 * </p>
99 * Subclasses may override to install their own encoding
100 * support or to disable the default encoding support.
101 * </p>
102102 * @since 2.1
103103 */
104104 protected void installEncodingSupport() {
2323 * @since 2.1
2424 * @noinstantiate This class is not intended to be instantiated by clients.
2525 * @noextend This class is not intended to be subclassed by clients.
26 */
26 */
2727 public class TextEditorPreferenceConstants {
2828
2929 /**
5959
6060 /**
6161 * A named preference that controls whether the print margin is turned on or off
62 * (value <code>"printMargin"</code>).
62 * (value <code>"printMargin"</code>).
6363 * <p>
6464 * The preference value is of type <code>Boolean</code>.
6565 * </p>
124124
125125 /**
126126 * A named preference that controls whether the overview ruler shows unknown indicators
127 * (value <code>"othersIndicationInOverviewRuler"</code>).
127 * (value <code>"othersIndicationInOverviewRuler"</code>).
128128 * <p>
129129 * The preference value is of type <code>Boolean</code>.
130130 * </p>
136136
137137 /**
138138 * A named preference that controls if the overview ruler is shown in the UI
139 * (value <code>"overviewRuler"</code>).
139 * (value <code>"overviewRuler"</code>).
140140 * <p>
141141 * The preference value is of type <code>Boolean</code>.
142142 * </p>
280280 public final static String EDITOR_SEARCH_RESULT_INDICATION_IN_OVERVIEW_RULER= "searchResultIndicationInOverviewRuler"; //$NON-NLS-1$
281281
282282 /**
283 * Initializes the given preference store with the default values.
283 * Initializes the given preference store with the default values.
284284 *
285 * @param store the preference store to be initialized
286 */
285 * @param store the preference store to be initialized
286 */
287287 public static void initializeDefaultValues(IPreferenceStore store) {
288288
289289 // set defaults from AbstractDecoratedTextEditor
10161016 public ISchedulingRule getSchedulingRule() {
10171017 if (info.fElement instanceof IFileEditorInput) {
10181018 IFileEditorInput input= (IFileEditorInput) info.fElement;
1019 return fResourceRuleFactory.validateEditRule(new IResource[] { input.getFile() });
1019 IFile file= input.getFile();
1020 ISchedulingRule validateEditRule= fResourceRuleFactory.validateEditRule(new IResource[] { file });
1021 if (validateEditRule == null) {
1022 // Note that factory decides to provide a null rule for modifiable files (not read-only).
1023 // Null rule means, that org.eclipse.core.internal.resources.WorkManager.checkIn(ISchedulingRule, IProgressMonitor)
1024 // will run jobManager.beginRule(null, monitor); which will NOT show any progress dialog
1025 // and will *immediately* lock UI thread via lock.acquire(); while the workspace is locked
1026 // Providing here a file we enforce the progress dialog, where this operation can be cancelled by user,
1027 // so that an occasional "Modify" or "Save" of the editor will NOT block UI forever.
1028 return file;
1029 } else {
1030 return validateEditRule;
1031 }
10201032 }
10211033 return null;
10221034 }
8989 return filterUnacceptableFiles(files);
9090 }
9191
92 final IFilter filter= new IFilter() {
92 final IFilter filter= new IFilter() {
9393 @Override
9494 public boolean accept(IResource resource) {
9595 return resource != null && isAcceptableLocation(resource.getFullPath());
374374 * @param chars the number of characters
375375 * @return the number of pixels
376376 */
377 protected int convertWidthInCharsToPixels(int chars) {
378 // test for failure to initialize for backward compatibility
379 if (fFontMetrics == null)
380 return 0;
381 return Dialog.convertWidthInCharsToPixels(fFontMetrics, chars);
382 }
377 protected int convertWidthInCharsToPixels(int chars) {
378 // test for failure to initialize for backward compatibility
379 if (fFontMetrics == null)
380 return 0;
381 return Dialog.convertWidthInCharsToPixels(fFontMetrics, chars);
382 }
383383
384384 /**
385385 * Returns the number of pixels corresponding to the height of the given number of characters.
393393 * @param chars the number of characters
394394 * @return the number of pixels
395395 */
396 protected int convertHeightInCharsToPixels(int chars) {
397 // test for failure to initialize for backward compatibility
398 if (fFontMetrics == null)
399 return 0;
400 return Dialog.convertHeightInCharsToPixels(fFontMetrics, chars);
401 }
396 protected int convertHeightInCharsToPixels(int chars) {
397 // test for failure to initialize for backward compatibility
398 if (fFontMetrics == null)
399 return 0;
400 return Dialog.convertHeightInCharsToPixels(fFontMetrics, chars);
401 }
402402
403403 /**
404404 * Initializes the computation of horizontal and vertical dialog units based on the size of
409409 *
410410 * @param testControl a control from which to obtain the current font
411411 */
412 protected void initializeDialogUnits(Control testControl) {
413 // Compute and store a font metric
414 GC gc = new GC(testControl);
415 gc.setFont(JFaceResources.getDialogFont());
416 fFontMetrics = gc.getFontMetrics();
417 gc.dispose();
418 }
412 protected void initializeDialogUnits(Control testControl) {
413 // Compute and store a font metric
414 GC gc = new GC(testControl);
415 gc.setFont(JFaceResources.getDialogFont());
416 fFontMetrics = gc.getFontMetrics();
417 gc.dispose();
418 }
419419
420420 private void handleAnnotationListSelection() {
421421 ListItem item= getSelectedItem();
544544
545545 private void initializeFields() {
546546
547 // Update slaves
548 Iterator<SelectionListener> iter= fMasterSlaveListeners.iterator();
549 while (iter.hasNext()) {
550 SelectionListener listener= iter.next();
551 listener.widgetSelected(null);
552 }
547 // Update slaves
548 Iterator<SelectionListener> iter= fMasterSlaveListeners.iterator();
549 while (iter.hasNext()) {
550 SelectionListener listener= iter.next();
551 listener.widgetSelected(null);
552 }
553553 }
554554
555555 @Override
2222 */
2323 public class PreviousPulldownActionDelegate extends NextPreviousPulldownActionDelegate {
2424
25 @Override
25 @Override
2626 public String getPreferenceKey(AnnotationPreference annotationPreference) {
27 return annotationPreference.getIsGoToPreviousNavigationTargetKey();
28 }
27 return annotationPreference.getIsGoToPreviousNavigationTargetKey();
28 }
2929
3030 }
6464 if (containsOnlyFiles(resources))
6565 return files;
6666
67 final IFilter filter= new IFilter() {
67 final IFilter filter= new IFilter() {
6868 @Override
6969 public boolean accept(IResource resource) {
7070 return resource != null && isAcceptableLocation(resource.getFullPath());
7777
7878 void filterElements(Collection<Object> elements) throws InterruptedException;
7979
80 void filterElements(Object[] elements) throws InterruptedException;
80 void filterElements(Object[] elements) throws InterruptedException;
8181 }
8282
8383
6262 }
6363
6464 private SelectResourcesBlock fResourceGroup;
65 private List<Object> fAcceptedFileTypes = new ArrayList<>();
66 private IResource[] fInput;
67 private String fTitle;
68 private String fInstruction;
69 private Label fCountIndication;
65 private List<Object> fAcceptedFileTypes = new ArrayList<>();
66 private IResource[] fInput;
67 private String fTitle;
68 private String fInstruction;
69 private Label fCountIndication;
7070 private IFilter fAcceptableLocationsFilter;
7171
7272
129129 return (displayHeight / fontHeight) > 50;
130130 }
131131
132 private ITreeContentProvider getResourceProvider(final int resourceType) {
133 return new WorkbenchContentProvider() {
134 @Override
132 private ITreeContentProvider getResourceProvider(final int resourceType) {
133 return new WorkbenchContentProvider() {
134 @Override
135135 public Object[] getChildren(Object o) {
136 if (o instanceof IWorkspaceRoot) {
137 HashSet<IResource> projects= new HashSet<>();
138 for (int i= 0; i < fInput.length; i++) {
139 IResource project= fInput[i].getProject();
140 if ((project.getType() & resourceType) > 0)
141 projects.add(project);
142 }
143 return projects.toArray();
144 }
145
146 if (o instanceof IContainer) {
147 IResource[] members = null;
148 try {
149 members = ((IContainer) o).members();
150 } catch (CoreException e) {
151 //just return an empty set of children
152 return new Object[0];
153 }
154
155 //filter out the desired resource types
156 ArrayList<IResource> results = new ArrayList<>();
157 for (int i = 0; i < members.length; i++) {
158 //And the test bits with the resource types to see if they are what we want
159 if ((members[i].getType() & resourceType) > 0 && (resourceType != IResource.FILE || fAcceptableLocationsFilter == null || fAcceptableLocationsFilter.accept(members[i]))) {
160 results.add(members[i]);
161 }
162 }
163 return results.toArray();
164 }
165
166 //input element case
167 if (o instanceof ArrayList)
168 return ((ArrayList<?>) o).toArray();
169
170 return new Object[0];
171 }
172 };
173 }
174
175 protected Composite createSelectionButtonGroup(Composite parent) {
136 if (o instanceof IWorkspaceRoot) {
137 HashSet<IResource> projects= new HashSet<>();
138 for (int i= 0; i < fInput.length; i++) {
139 IResource project= fInput[i].getProject();
140 if ((project.getType() & resourceType) > 0)
141 projects.add(project);
142 }
143 return projects.toArray();
144 }
145
146 if (o instanceof IContainer) {
147 IResource[] members = null;
148 try {
149 members = ((IContainer) o).members();
150 } catch (CoreException e) {
151 //just return an empty set of children
152 return new Object[0];
153 }
154
155 //filter out the desired resource types
156 ArrayList<IResource> results = new ArrayList<>();
157 for (int i = 0; i < members.length; i++) {
158 //And the test bits with the resource types to see if they are what we want
159 if ((members[i].getType() & resourceType) > 0 && (resourceType != IResource.FILE || fAcceptableLocationsFilter == null || fAcceptableLocationsFilter.accept(members[i]))) {
160 results.add(members[i]);
161 }
162 }
163 return results.toArray();
164 }
165
166 //input element case
167 if (o instanceof ArrayList)
168 return ((ArrayList<?>) o).toArray();
169
170 return new Object[0];
171 }
172 };
173 }
174
175 protected Composite createSelectionButtonGroup(Composite parent) {
176176
177177 Font font= parent.getFont();
178178
224224 return buttonComposite;
225225 }
226226
227 protected void handleSelectFileTypes() {
227 protected void handleSelectFileTypes() {
228228 Object[] acceptedFileTypes= queryFileTypes();
229229 if (acceptedFileTypes != null) {
230230 fAcceptedFileTypes= Arrays.asList(acceptedFileTypes);
232232 }
233233 }
234234
235 protected Object[] queryFileTypes() {
235 protected Object[] queryFileTypes() {
236236 TypeFilteringDialog dialog= new TypeFilteringDialog(getShell(), fAcceptedFileTypes);
237237 dialog.open();
238238 return dialog.getResult();
239239 }
240240
241 private void filterSelection() {
241 private void filterSelection() {
242242
243243 final IFilter filter= resource -> hasAcceptedFileType(resource);
244244
247247
248248 Runnable runnable= () -> setSelection(resources, filter);
249249
250 BusyIndicator.showWhile(getShell().getDisplay(), runnable);
251 }
252
253 protected boolean hasAcceptedFileType(IResource resource) {
250 BusyIndicator.showWhile(getShell().getDisplay(), runnable);
251 }
252
253 protected boolean hasAcceptedFileType(IResource resource) {
254254 if (fAcceptedFileTypes == null)
255255 return true;
256256
10571057 fFieldsInitialized= true;
10581058 updateStatus(new StatusInfo());
10591059
1060 // Update slaves
1061 Iterator<SelectionListener> iter= fMasterSlaveListeners.iterator();
1062 while (iter.hasNext()) {
1063 SelectionListener listener= iter.next();
1064 listener.widgetSelected(null);
1065 }
1060 // Update slaves
1061 Iterator<SelectionListener> iter= fMasterSlaveListeners.iterator();
1062 while (iter.hasNext()) {
1063 SelectionListener listener= iter.next();
1064 listener.widgetSelected(null);
1065 }
10661066
10671067 }
10681068
11841184 setAction(ITextEditorActionConstants.QUICKDIFF_REVERTDELETION, action);
11851185
11861186 IAction action2= new CompositeRevertAction(this, new IAction[] {
1187 getAction(ITextEditorActionConstants.QUICKDIFF_REVERTSELECTION),
1188 getAction(ITextEditorActionConstants.QUICKDIFF_REVERTBLOCK),
1189 getAction(ITextEditorActionConstants.QUICKDIFF_REVERTDELETION),
1190 getAction(ITextEditorActionConstants.QUICKDIFF_REVERTLINE)});
1187 getAction(ITextEditorActionConstants.QUICKDIFF_REVERTSELECTION),
1188 getAction(ITextEditorActionConstants.QUICKDIFF_REVERTBLOCK),
1189 getAction(ITextEditorActionConstants.QUICKDIFF_REVERTDELETION),
1190 getAction(ITextEditorActionConstants.QUICKDIFF_REVERTLINE)});
11911191 action2.setActionDefinitionId(ITextEditorActionDefinitionIds.QUICKDIFF_REVERT);
11921192 setAction(ITextEditorActionConstants.QUICKDIFF_REVERT, action2);
11931193
13091309
13101310 IAnnotationHover hover= fLineColumn.getHover();
13111311 showFocusedRulerHover(hover, sourceViewer, caretOffset);
1312 }
1312 }
13131313
13141314 /**
13151315 * Opens a sticky annotation ruler hover for the caret line. Does nothing if no annotation hover
15271527 // Check whether file exists and if so, confirm overwrite
15281528 final File localFile= new File(path);
15291529 if (localFile.exists()) {
1530 MessageDialog overwriteDialog= new MessageDialog(
1531 shell,
1532 TextEditorMessages.AbstractDecoratedTextEditor_saveAs_overwrite_title,
1533 null,
1534 NLSUtility.format(TextEditorMessages.AbstractDecoratedTextEditor_saveAs_overwrite_message, path),
1535 MessageDialog.WARNING,
1536 new String[] { IDialogConstants.YES_LABEL, IDialogConstants.NO_LABEL },
1537 1); // 'No' is the default
1530 MessageDialog overwriteDialog= new MessageDialog(
1531 shell,
1532 TextEditorMessages.AbstractDecoratedTextEditor_saveAs_overwrite_title,
1533 null,
1534 NLSUtility.format(TextEditorMessages.AbstractDecoratedTextEditor_saveAs_overwrite_message, path),
1535 MessageDialog.WARNING,
1536 new String[] { IDialogConstants.YES_LABEL, IDialogConstants.NO_LABEL },
1537 1); // 'No' is the default
15381538 if (overwriteDialog.open() != Window.OK) {
15391539 if (progressMonitor != null) {
15401540 progressMonitor.setCanceled(true);
101101
102102 /**
103103 * A named preference that controls whether the print margin is turned on or off
104 * (value <code>"printMargin"</code>).
104 * (value <code>"printMargin"</code>).
105105 * <p>
106106 * The preference value is of type <code>Boolean</code>.
107107 * </p>
169169
170170 /**
171171 * A named preference that controls whether the overview ruler shows unknown indicators
172 * (value <code>"othersIndicationInOverviewRuler"</code>).
172 * (value <code>"othersIndicationInOverviewRuler"</code>).
173173 * <p>
174174 * The preference value is of type <code>Boolean</code>.
175175 * </p>
180180
181181 /**
182182 * A named preference that controls if the overview ruler is shown in the UI
183 * (value <code>"overviewRuler"</code>).
183 * (value <code>"overviewRuler"</code>).
184184 * <p>
185185 * The preference value is of type <code>Boolean</code>.
186186 * </p>
671671 public static final String EDITOR_HOVER_ENRICH_MODE= AbstractTextEditor.PREFERENCE_HOVER_ENRICH_MODE;
672672
673673 /**
674 * Initializes the given preference store with the default values.
675 *
676 * @param store the preference store to be initialized
677 */
674 * Initializes the given preference store with the default values.
675 *
676 * @param store the preference store to be initialized
677 */
678678 public static void initializeDefaultValues(IPreferenceStore store) {
679679 store.setDefault(AbstractDecoratedTextEditorPreferenceConstants.USE_ANNOTATIONS_PREFERENCE_PAGE, false);
680680 store.setDefault(AbstractDecoratedTextEditorPreferenceConstants.USE_QUICK_DIFF_PREFERENCE_PAGE, false);
6262 if (resource == null)
6363 return;
6464
65 TaskPropertiesDialog dialog = new TaskPropertiesDialog(getTextEditor().getSite().getShell());
66 dialog.setResource(resource);
67 dialog.setInitialAttributes(getInitialAttributes());
68 dialog.open();
65 TaskPropertiesDialog dialog = new TaskPropertiesDialog(getTextEditor().getSite().getShell());
66 dialog.setResource(resource);
67 dialog.setInitialAttributes(getInitialAttributes());
68 dialog.open();
6969 }
7070 }
7171
11 Bundle-ManifestVersion: 2
22 Bundle-Name: %Plugin.name
33 Bundle-SymbolicName: org.eclipse.ui.editors.tests;singleton:=true
4 Bundle-Version: 3.11.300.qualifier
4 Bundle-Version: 3.11.400.qualifier
55 Bundle-Vendor: %Plugin.providerName
66 Bundle-Localization: plugin
77 Export-Package: org.eclipse.ui.editors.tests
1313 <parent>
1414 <artifactId>tests-pom</artifactId>
1515 <groupId>eclipse.platform.text</groupId>
16 <version>4.11.0-SNAPSHOT</version>
16 <version>4.12.0-SNAPSHOT</version>
1717 <relativePath>../tests-pom/</relativePath>
1818 </parent>
1919 <groupId>org.eclipse.ui</groupId>
2020 <artifactId>org.eclipse.ui.editors.tests</artifactId>
21 <version>3.11.300-SNAPSHOT</version>
21 <version>3.11.400-SNAPSHOT</version>
2222 <packaging>eclipse-test-plugin</packaging>
2323 <properties>
2424 <testSuite>${project.artifactId}</testSuite>
3232 MarkerAnnotationOrderTest.class,
3333 ZoomTest.class,
3434 FileDocumentProviderTest.class,
35 TextFileDocumentProviderTest.class,
3536 StatusEditorTest.class
3637 })
3738 public class EditorsTestSuite {
2929
3030 import org.eclipse.core.internal.localstore.FileSystemResourceManager;
3131 import org.eclipse.core.internal.resources.File;
32 import org.eclipse.core.internal.resources.Workspace;
3233
3334 import org.eclipse.core.runtime.CoreException;
3435 import org.eclipse.core.runtime.ILog;
5556 import org.eclipse.ui.IEditorPart;
5657 import org.eclipse.ui.IWorkbench;
5758 import org.eclipse.ui.IWorkbenchPage;
59 import org.eclipse.ui.IWorkbenchWindow;
5860 import org.eclipse.ui.PlatformUI;
5961 import org.eclipse.ui.ide.IDE;
6062 import org.eclipse.ui.internal.dialogs.EventLoopProgressMonitor;
63 import org.eclipse.ui.intro.IIntroManager;
64 import org.eclipse.ui.intro.IIntroPart;
6165
6266 import org.eclipse.ui.editors.text.FileDocumentProvider;
6367
7377 private AtomicBoolean stoppedByTest;
7478 private AtomicBoolean stopLockingFlag;
7579 private LockJob lockJob;
80 private LockJob2 lockJob2;
7681 private FileDocumentProviderMock fileProvider;
7782 private FileSystemResourceManager fsManager;
7883 private IEditorPart editor;
8085
8186 @Before
8287 public void setUp() throws Exception {
88 closeIntro(PlatformUI.getWorkbench());
8389 IFolder folder = ResourceHelper.createFolder("FileDocumentProviderTestProject/test");
8490 file = (File) ResourceHelper.createFile(folder, "file.txt", "");
8591 assertTrue(file.exists());
8995 stoppedByTest = new AtomicBoolean(false);
9096 fileProvider = new FileDocumentProviderMock();
9197 lockJob = new LockJob("Locking workspace", file, stopLockingFlag, stoppedByTest);
98 lockJob2 = new LockJob2("Locking workspace", file, stopLockingFlag, stoppedByTest);
9299
93100 // We need the editor only to get the default editor status line manager
94101 IWorkbench workbench = PlatformUI.getWorkbench();
125132 public void tearDown() throws Exception {
126133 stopLockingFlag.set(true);
127134 lockJob.cancel();
135 lockJob2.cancel();
128136 if (editor != null) {
129137 page.closeEditor(editor, false);
130138 }
194202
195203 System.out.println("Busy wait terminated, UI thread is operable again!");
196204
205 assertFalse("Test deadlocked while waiting on resource lock", stoppedByTest.get());
206 assertTrue(stopLockingFlag.get());
207 }
208
209 @Test
210 public void testValidateStateForFileWhileWorkspaceIsLocked() throws Exception {
211 assertNotNull("Test must run in UI thread", Display.getCurrent());
212
213 // Start workspace job which will lock workspace operations on file
214 lockJob2.schedule();
215
216 Thread.sleep(100);
217
218 // Put an UI event in the queue which will stop the workspace lock job
219 // after a delay
220 Display.getCurrent().timerExec(600, new Runnable() {
221 @Override
222 public void run() {
223 stopLockingFlag.set(true);
224 System.out.println("UI event dispatched, lock removed");
225 }
226 });
227
228 // Original code will lock UI thread here because it will try to acquire
229 // workspace lock and no one will process UI events anymore
230 fileProvider.validateState(editor.getEditorInput(), editor.getSite().getShell());
231
232 System.out.println("Busy wait terminated, UI thread is operable again!");
197233 assertFalse("Test deadlocked while waiting on resource lock", stoppedByTest.get());
198234 assertTrue(stopLockingFlag.get());
199235 }
226262 ILog log = Platform.getLog(Platform.getBundle(PLUGIN_ID));
227263 log.log(new Status(IStatus.ERROR, PLUGIN_ID, IStatus.OK, message, ex));
228264 }
265
266 static void closeIntro(final IWorkbench wb) {
267 IWorkbenchWindow window = wb.getActiveWorkbenchWindow();
268 if (window != null) {
269 IIntroManager im = wb.getIntroManager();
270 IIntroPart intro = im.getIntro();
271 if (intro != null) {
272 im.closeIntro(intro);
273 }
274 }
275 }
229276 }
230277
231278 class FileDocumentProviderMock extends FileDocumentProvider {
252299 /** Emulates what SVN plugin jobs are doing */
253300 class LockJob extends WorkspaceJob {
254301
255 private final IResource resource;
256 private AtomicBoolean stopFlag;
257 private AtomicBoolean stoppedByTest;
302 final IResource resource;
303 AtomicBoolean stopFlag;
304 AtomicBoolean stoppedByTest;
258305
259306 public LockJob(String name, IResource resource, AtomicBoolean stopFlag, AtomicBoolean stoppedByTest) {
260307 super(name);
265312 this.resource = resource;
266313 }
267314
268 public IStatus run2(IProgressMonitor monitor) {
315 public IStatus run2() {
269316 long startTime = System.currentTimeMillis();
270317 // Wait maximum 5 minutes
271318 int maxWaitTime = 5 * 60 * 1000;
311358 @Override
312359 public void run(IProgressMonitor pm) throws CoreException {
313360 try {
314 run2(pm);
361 run2();
315362 } catch (Exception e) {
316363 // Re-throw as OperationCanceledException, which will be
317364 // caught and re-thrown as InterruptedException below.
327374 }
328375
329376 }
377
378 /** Emulates what AutoBuildJob is doing */
379 class LockJob2 extends Job {
380
381 final IResource resource;
382 AtomicBoolean stopFlag;
383 AtomicBoolean stoppedByTest;
384
385 public LockJob2(String name, IResource resource, AtomicBoolean stopFlag, AtomicBoolean stoppedByTest) {
386 super(name);
387 this.stopFlag = stopFlag;
388 this.stoppedByTest = stoppedByTest;
389 setUser(true);
390 setSystem(true);
391 this.resource = resource;
392 setRule(ResourcesPlugin.getWorkspace().getRoot());
393 }
394
395 @Override
396 public boolean belongsTo(Object family) {
397 return super.belongsTo(family) || LockJob2.class == family;
398 }
399
400 @Override
401 public IStatus run(IProgressMonitor monitor) {
402 Workspace workspace = (Workspace) ResourcesPlugin.getWorkspace();
403 try {
404 workspace.prepareOperation(getRule(), monitor);
405 workspace.beginOperation(true);
406 run2();
407 } catch (CoreException e) {
408 FileDocumentProviderTest.logError(e.getMessage(), e);
409 } finally {
410 try {
411 workspace.endOperation(getRule(), false);
412 } catch (CoreException e) {
413 FileDocumentProviderTest.logError(e.getMessage(), e);
414 }
415 }
416 return monitor.isCanceled() ? Status.CANCEL_STATUS : Status.OK_STATUS;
417 }
418
419 public IStatus run2() {
420 long startTime = System.currentTimeMillis();
421 // Wait maximum 5 minutes
422 int maxWaitTime = 5 * 60 * 1000;
423 long stopTime = startTime + maxWaitTime;
424
425 System.out.println("Starting the busy wait while holding lock on: " + resource.getFullPath());
426 try {
427 while (!stopFlag.get()) {
428 try {
429 if (System.currentTimeMillis() > stopTime) {
430 FileDocumentProviderTest.logError("Tiemout occured while waiting on test to finish",
431 new IllegalStateException());
432 stoppedByTest.set(true);
433 return Status.CANCEL_STATUS;
434 }
435 Thread.sleep(100);
436 } catch (InterruptedException e) {
437 stoppedByTest.set(true);
438 FileDocumentProviderTest.logError("Lock job was interrupted while waiting on test to finish", e);
439 e.printStackTrace();
440 return Status.CANCEL_STATUS;
441 }
442 }
443 } finally {
444 System.out.println("Lock task terminated");
445 }
446 return Status.OK_STATUS;
447 }
448 }
0 /*******************************************************************************
1 * Copyright (c) 2016 Andrey Loskutov.
2 *
3 * This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License 2.0
5 * which accompanies this distribution, and is available at
6 * https://www.eclipse.org/legal/epl-2.0/
7 *
8 * SPDX-License-Identifier: EPL-2.0
9 *
10 * Contributors:
11 * Andrey Loskutov <loskutov@gmx.de> - initial API and implementation
12 *******************************************************************************/
13 package org.eclipse.ui.editors.tests;
14
15 import static org.eclipse.ui.editors.tests.FileDocumentProviderTest.closeIntro;
16 import static org.junit.Assert.assertFalse;
17 import static org.junit.Assert.assertNotNull;
18 import static org.junit.Assert.assertTrue;
19
20 import java.nio.file.Files;
21 import java.nio.file.attribute.FileTime;
22 import java.util.Arrays;
23 import java.util.concurrent.atomic.AtomicBoolean;
24
25 import org.junit.After;
26 import org.junit.Before;
27 import org.junit.Test;
28
29 import org.eclipse.swt.widgets.Display;
30
31 import org.eclipse.core.internal.localstore.FileSystemResourceManager;
32 import org.eclipse.core.internal.resources.File;
33
34 import org.eclipse.core.runtime.IProgressMonitor;
35 import org.eclipse.core.runtime.IProgressMonitorWithBlocking;
36 import org.eclipse.core.runtime.NullProgressMonitor;
37 import org.eclipse.core.runtime.jobs.Job;
38
39 import org.eclipse.core.resources.IFolder;
40
41 import org.eclipse.core.filebuffers.tests.ResourceHelper;
42
43 import org.eclipse.jface.action.IStatusLineManager;
44
45 import org.eclipse.ui.IEditorPart;
46 import org.eclipse.ui.IWorkbench;
47 import org.eclipse.ui.IWorkbenchPage;
48 import org.eclipse.ui.PlatformUI;
49 import org.eclipse.ui.ide.IDE;
50 import org.eclipse.ui.internal.dialogs.EventLoopProgressMonitor;
51
52 import org.eclipse.ui.editors.text.TextFileDocumentProvider;
53
54 /**
55 * Test checking UI deadlock on modifying the TextFileDocumentProvider's
56 * underlined file.
57 */
58 public class TextFileDocumentProviderTest {
59
60 private File file;
61 private AtomicBoolean stoppedByTest;
62 private AtomicBoolean stopLockingFlag;
63 private LockJob lockJob;
64 private LockJob2 lockJob2;
65 private TextFileDocumentProvider fileProvider;
66 private FileSystemResourceManager fsManager;
67 private IEditorPart editor;
68 private IWorkbenchPage page;
69
70 @Before
71 public void setUp() throws Exception {
72 closeIntro(PlatformUI.getWorkbench());
73 IFolder folder = ResourceHelper.createFolder("FileDocumentProviderTestProject/test");
74 file = (File) ResourceHelper.createFile(folder, "file.txt", "");
75 assertTrue(file.exists());
76 fsManager = file.getLocalManager();
77 assertTrue(fsManager.fastIsSynchronized(file));
78 stopLockingFlag = new AtomicBoolean(false);
79 stoppedByTest = new AtomicBoolean(false);
80 fileProvider = new TextFileDocumentProvider();
81 lockJob = new LockJob("Locking workspace", file, stopLockingFlag, stoppedByTest);
82 lockJob2 = new LockJob2("Locking workspace", file, stopLockingFlag, stoppedByTest);
83
84 // We need the editor only to get the default editor status line manager
85 IWorkbench workbench = PlatformUI.getWorkbench();
86 page = workbench.getActiveWorkbenchWindow().getActivePage();
87 editor = IDE.openEditor(page, file);
88 TestUtil.runEventLoop();
89
90 IStatusLineManager statusLineManager = editor.getEditorSite().getActionBars().getStatusLineManager();
91 // This is default monitor which almost all editors are using
92 IProgressMonitor progressMonitor = statusLineManager.getProgressMonitor();
93 assertNotNull(progressMonitor);
94 assertFalse(progressMonitor instanceof NullProgressMonitor);
95 assertFalse(progressMonitor instanceof EventLoopProgressMonitor);
96 assertTrue(progressMonitor instanceof IProgressMonitorWithBlocking);
97
98 // Because this monitor is not EventLoopProgressMonitor, it will not
99 // process UI events while waiting on workspace lock
100 fileProvider.setProgressMonitor(progressMonitor);
101
102 TestUtil.waitForJobs(500, 5000);
103 Job[] jobs = Job.getJobManager().find(null);
104 String jobsList = Arrays.toString(jobs);
105 System.out.println("Still running jobs: " + jobsList);
106 if (!Job.getJobManager().isIdle()) {
107 jobs = Job.getJobManager().find(null);
108 for (Job job : jobs) {
109 System.out.println("Going to cancel: " + job.getName() + " / " + job);
110 job.cancel();
111 }
112 }
113 }
114
115 @After
116 public void tearDown() throws Exception {
117 stopLockingFlag.set(true);
118 lockJob.cancel();
119 lockJob2.cancel();
120 if (editor != null) {
121 page.closeEditor(editor, false);
122 }
123 ResourceHelper.deleteProject(file.getProject().getName());
124 TestUtil.runEventLoop();
125 TestUtil.cleanUp();
126 }
127
128 @Test
129 public void testSynchronizeInputWhileWorkspaceIsLocked1() throws Exception {
130 // See https://bugs.eclipse.org/bugs/show_bug.cgi?id=482354
131 assertNotNull("Test must run in UI thread", Display.getCurrent());
132 fileProvider.connect(editor.getEditorInput());
133
134 // Start workspace job which will lock workspace operations on file via
135 // rule
136 lockJob.schedule();
137
138 // touch the file of the editor
139 makeSureResourceIsOutOfDate();
140
141 // Put an UI event in the queue which will stop the workspace lock job
142 // after a delay so that we can verify the UI events are still
143 // dispatched after the call to refreshFile() below
144 Display.getCurrent().timerExec(500, new Runnable() {
145 @Override
146 public void run() {
147 stopLockingFlag.set(true);
148 System.out.println("UI event dispatched, lock removed");
149 }
150 });
151
152 // Original code will lock UI thread here because it will try to acquire
153 // resource lock and no one will process UI events anymore
154 fileProvider.synchronize(editor.getEditorInput());
155
156 System.out.println("Busy wait terminated, UI thread is operable again!");
157 assertFalse("Test deadlocked while waiting on resource lock", stoppedByTest.get());
158 assertTrue(stopLockingFlag.get());
159 }
160
161 @Test
162 public void testSynchronizeInputWhileWorkspaceIsLocked2() throws Exception {
163 // See https://bugs.eclipse.org/bugs/show_bug.cgi?id=482354
164 assertNotNull("Test must run in UI thread", Display.getCurrent());
165
166 fileProvider.connect(editor.getEditorInput());
167
168 // Start workspace job which will lock workspace operations on file via
169 // rule
170 lockJob.schedule();
171
172 // touch the file of the editor
173 makeSureResourceIsOutOfDate();
174
175 // Put an UI event in the queue which will stop the workspace lock job
176 // after a delay so that we can verify the UI events are still
177 // dispatched after the call to refreshFile() below
178 Display.getCurrent().timerExec(500, new Runnable() {
179 @Override
180 public void run() {
181 stopLockingFlag.set(true);
182 System.out.println("UI event dispatched, lock removed");
183 }
184 });
185
186 // Original code will lock UI thread here because it will try to acquire
187 // resource lock and no one will process UI events anymore
188 fileProvider.synchronize(editor.getEditorInput());
189
190 System.out.println("Busy wait terminated, UI thread is operable again!");
191 assertFalse("Test deadlocked while waiting on resource lock", stoppedByTest.get());
192 assertTrue(stopLockingFlag.get());
193 }
194
195 @Test
196 public void testValidateStateForFileWhileWorkspaceIsLocked() throws Exception {
197 assertNotNull("Test must run in UI thread", Display.getCurrent());
198
199 fileProvider.connect(editor.getEditorInput());
200
201 // Start workspace job which will lock workspace operations on file
202 lockJob2.schedule();
203
204 Thread.sleep(100);
205
206 // Put an UI event in the queue which will stop the workspace lock job
207 // after a delay
208 Display.getCurrent().timerExec(600, new Runnable() {
209 @Override
210 public void run() {
211 stopLockingFlag.set(true);
212 System.out.println("UI event dispatched, lock removed");
213 }
214 });
215
216 // Original code will lock UI thread here because it will try to acquire
217 // workspace lock and no one will process UI events anymore
218 fileProvider.validateState(editor.getEditorInput(), editor.getSite().getShell());
219
220 System.out.println("Busy wait terminated, UI thread is operable again!");
221 assertFalse("Test deadlocked while waiting on resource lock", stoppedByTest.get());
222 assertTrue(stopLockingFlag.get());
223 }
224
225 /*
226 * Set current time stamp via java.nio to make sure
227 * org.eclipse.core.internal.resources.File.refreshLocal(int,
228 * IProgressMonitor) will call super.refreshLocal(IResource.DEPTH_ZERO,
229 * monitor) and so lock the UI by trying to access resource locked by the
230 * job
231 */
232 private void makeSureResourceIsOutOfDate() throws Exception {
233 int count = 0;
234 Files.setLastModifiedTime(file.getLocation().toFile().toPath(),
235 FileTime.fromMillis(System.currentTimeMillis()));
236 // Give the file system a chance to have a *different* timestamp
237 Thread.sleep(100);
238 while (fsManager.fastIsSynchronized(file) && count < 1000) {
239 Files.setLastModifiedTime(file.getLocation().toFile().toPath(),
240 FileTime.fromMillis(System.currentTimeMillis()));
241 Thread.sleep(10);
242 count++;
243 }
244 System.out.println("Managed to update file after " + count + " attempts");
245 assertFalse(fsManager.fastIsSynchronized(file));
246 }
247
248 }
249
250
1313 <parent>
1414 <artifactId>eclipse.platform.text</artifactId>
1515 <groupId>eclipse.platform.text</groupId>
16 <version>4.11.0-SNAPSHOT</version>
16 <version>4.12.0-SNAPSHOT</version>
1717 </parent>
1818 <groupId>org.eclipse.ui</groupId>
1919 <artifactId>org.eclipse.ui.examples.javaeditor</artifactId>
11 Bundle-ManifestVersion: 2
22 Bundle-Name: %Bundle-Name
33 Bundle-SymbolicName: org.eclipse.ui.genericeditor;singleton:=true
4 Bundle-Version: 1.1.300.qualifier
4 Bundle-Version: 1.1.400.qualifier
55 Bundle-Vendor: %Bundle-Vendor
66 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
77 Require-Bundle: org.eclipse.ui.workbench.texteditor;bundle-version="3.10.0",
1313 org.eclipse.jface;bundle-version="3.12.0",
1414 org.eclipse.ui.ide;bundle-version="3.12.0",
1515 org.eclipse.core.resources;bundle-version="3.11.0",
16 org.eclipse.core.expressions;bundle-version="3.6.0"
16 org.eclipse.core.expressions;bundle-version="3.6.0",
17 org.eclipse.compare;resolution:=optional
1718 Export-Package: org.eclipse.ui.internal.genericeditor;x-internal:=true,
1819 org.eclipse.ui.internal.genericeditor.hover;x-internal:=true,
1920 org.eclipse.ui.internal.genericeditor.markers;x-internal:=true,
20 org.eclipse.ui.internal.genericeditor.preferences;x-internal:=true
21 org.eclipse.ui.internal.genericeditor.preferences;x-internal:=true,
22 org.eclipse.ui.internal.genericeditor.compare;x-internal:=true
2123 Bundle-Activator: org.eclipse.ui.internal.genericeditor.GenericEditorPlugin
2224 Bundle-Localization: plugin
2325 Bundle-ActivationPolicy: lazy
208208 <extension point="org.eclipse.core.runtime.preferences">
209209 <initializer class="org.eclipse.ui.internal.genericeditor.preferences.GenericEditorPluginPreferenceInitializer"/>
210210 </extension>
211 <extension
212 point="org.eclipse.compare.contentViewers">
213 <viewer
214 class="org.eclipse.ui.internal.genericeditor.compare.CompareViewerCreator"
215 id="org.eclipse.ui.genericeditor.compareViewer">
216 </viewer>
217 </extension>
218 <extension
219 point="org.eclipse.compare.contentMergeViewers">
220 <viewer
221 class="org.eclipse.ui.internal.genericeditor.compare.CompareViewerCreator"
222 id="org.eclipse.ui.genericeditor.compareViewer">
223 </viewer>
224 </extension>
211225 </plugin>
1313 <parent>
1414 <artifactId>eclipse.platform.text</artifactId>
1515 <groupId>eclipse.platform.text</groupId>
16 <version>4.11.0-SNAPSHOT</version>
16 <version>4.12.0-SNAPSHOT</version>
1717 </parent>
1818 <groupId>org.eclipse.ui</groupId>
1919 <artifactId>org.eclipse.ui.genericeditor</artifactId>
20 <version>1.1.300-SNAPSHOT</version>
20 <version>1.1.400-SNAPSHOT</version>
2121 <packaging>eclipse-plugin</packaging>
2222 </project>
8282 A core Expression that controls the enabled of the given auto edit strategies. The viewer, editor, and editor input are registered in the evaluation context as variable:
8383
8484 * &lt;with variable=&quot;viewer&quot;/&gt; : use it if your expression requires the viewer.
85 * &lt;with variable=&quot;editor&quot;/&gt; : use it if your expression requires the editor.
86 * &lt;with variable=&quot;editorInput&quot;/&gt; : use it if your expression requires the editor input.
85 * &lt;with variable=&quot;document&quot;/&gt; : use it if your expression requires the document.
86 * &lt;with variable=&quot;editor&quot;/&gt; : use it if your expression requires the editor (deprecated, not always set).
87 * &lt;with variable=&quot;editorInput&quot;/&gt; : use it if your expression requires the editor input (deprecated, not always set).
8788 </documentation>
8889 </annotation>
8990 <complexType>
8282 A core Expression that controls the enabled of the given character pair matcher. The viewer, editor, and editor input are registered in the evaluation context as variable:
8383
8484 * &lt;with variable=&quot;viewer&quot;/&gt; : use it if your expression requires the viewer.
85 * &lt;with variable=&quot;editor&quot;/&gt; : use it if your expression requires the editor.
86 * &lt;with variable=&quot;editorInput&quot;/&gt; : use it if your expression requires the editor input.
85 * &lt;with variable=&quot;document&quot;/&gt; : use it if your expression requires the document.
86 * &lt;with variable=&quot;editor&quot;/&gt; : use it if your expression requires the editor (deprecated, not always set).
87 * &lt;with variable=&quot;editorInput&quot;/&gt; : use it if your expression requires the editor input (deprecated, not always set).
8788 </documentation>
8889 </annotation>
8990 <complexType>
8282 A core Expression that controls the enabled of the given content assist processor. The viewer, editor, and editor input are registered in the evaluation context as variable:
8383
8484 * &lt;with variable=&quot;viewer&quot;/&gt; : use it if your expression requires the viewer.
85 * &lt;with variable=&quot;editor&quot;/&gt; : use it if your expression requires the editor.
86 * &lt;with variable=&quot;editorInput&quot;/&gt; : use it if your expression requires the editor input.
85 * &lt;with variable=&quot;document&quot;/&gt; : use it if your expression requires the document.
86 * &lt;with variable=&quot;editor&quot;/&gt; : use it if your expression requires the editor (deprecated, not always set).
87 * &lt;with variable=&quot;editorInput&quot;/&gt; : use it if your expression requires the editor input (deprecated, not always set).
8788 </documentation>
8889 </annotation>
8990 <complexType>
8484 A core Expression that controls the enabled of the given folding reconciler. The viewer, editor, and editor input are registered in the evaluation context as variable:
8585
8686 * &lt;with variable=&quot;viewer&quot;/&gt; : use it if your expression requires the viewer.
87 * &lt;with variable=&quot;editor&quot;/&gt; : use it if your expression requires the editor.
88 * &lt;with variable=&quot;editorInput&quot;/&gt; : use it if your expression requires the editor input.
87 * &lt;with variable=&quot;document&quot;/&gt; : use it if your expression requires the document.
88 * &lt;with variable=&quot;editor&quot;/&gt; : use it if your expression requires the editor (deprecated, not always set).
89 * &lt;with variable=&quot;editorInput&quot;/&gt; : use it if your expression requires the editor input (deprecated, not always set).
8990 </documentation>
9091 </annotation>
9192 <complexType>
8282 A core Expression that controls the enabled of the given highlight reconciler. The viewer, editor, and editor input are registered in the evaluation context as variable:
8383
8484 * &lt;with variable=&quot;viewer&quot;/&gt; : use it if your expression requires the viewer.
85 * &lt;with variable=&quot;editor&quot;/&gt; : use it if your expression requires the editor.
86 * &lt;with variable=&quot;editorInput&quot;/&gt; : use it if your expression requires the editor input.
85 * &lt;with variable=&quot;document&quot;/&gt; : use it if your expression requires the document.
86 * &lt;with variable=&quot;editor&quot;/&gt; : use it if your expression requires the editor (deprecated, not always set).
87 * &lt;with variable=&quot;editorInput&quot;/&gt; : use it if your expression requires the editor input (deprecated, not always set).
8788 </documentation>
8889 </annotation>
8990 <complexType>
111111 A core Expression that controls the enabled of the given hover provider. The viewer, editor, and editor input are registered in the evaluation context as variable:
112112
113113 * &lt;with variable=&quot;viewer&quot;/&gt; : use it if your expression requires the viewer.
114 * &lt;with variable=&quot;editor&quot;/&gt; : use it if your expression requires the editor.
115 * &lt;with variable=&quot;editorInput&quot;/&gt; : use it if your expression requires the editor input.
114 * &lt;with variable=&quot;document&quot;/&gt; : use it if your expression requires the document.
115 * &lt;with variable=&quot;editor&quot;/&gt; : use it if your expression requires the editor (deprecated, not always set).
116 * &lt;with variable=&quot;editorInput&quot;/&gt; : use it if your expression requires the editor input (deprecated, not always set).
116117 </documentation>
117118 </annotation>
118119 <complexType>
8282 A core Expression that controls the enabled of the given presentation reconciler. The viewer, editor, and editor input are registered in the evaluation context as variable:
8383
8484 * &lt;with variable=&quot;viewer&quot;/&gt; : use it if your expression requires the viewer.
85 * &lt;with variable=&quot;editor&quot;/&gt; : use it if your expression requires the editor.
86 * &lt;with variable=&quot;editorInput&quot;/&gt; : use it if your expression requires the editor input.
85 * &lt;with variable=&quot;document&quot;/&gt; : use it if your expression requires the document.
86 * &lt;with variable=&quot;editor&quot;/&gt; : use it if your expression requires the editor (deprecated, not always set).
87 * &lt;with variable=&quot;editorInput&quot;/&gt; : use it if your expression requires the editor input (deprecated, not always set).
8788 </documentation>
8889 </annotation>
8990 <complexType>
8282 A core Expression that controls the enabled of the given reconciler. The viewer, editor, and editor input are registered in the evaluation context as variable:
8383
8484 * &lt;with variable=&quot;viewer&quot;/&gt; : use it if your expression requires the viewer.
85 * &lt;with variable=&quot;editor&quot;/&gt; : use it if your expression requires the editor.
86 * &lt;with variable=&quot;editorInput&quot;/&gt; : use it if your expression requires the editor input.
85 * &lt;with variable=&quot;document&quot;/&gt; : use it if your expression requires the document.
86 * &lt;with variable=&quot;editor&quot;/&gt; : use it if your expression requires the editor (deprecated, not always set).
87 * &lt;with variable=&quot;editorInput&quot;/&gt; : use it if your expression requires the editor input (deprecated, not always set).
8788 </documentation>
8889 </annotation>
8990 <complexType>
0 /**
1 * Copyright (c) 2018 Angelo ZERR.
2 * All rights reserved. This program and the accompanying materials
3 * are made available under the terms of the Eclipse Public License v2.0
4 * which accompanies this distribution, and is available at
5 * http://www.eclipse.org/legal/epl-v20.html
6 *
7 * Contributors:
8 * Angelo Zerr <angelo.zerr@gmail.com> - Bug 538111 - [generic editor] Extension point for ICharacterPairMatcher
9 */
10 package org.eclipse.ui.internal.genericeditor;
11
12 import java.util.HashMap;
13 import java.util.HashSet;
14 import java.util.List;
15 import java.util.Map;
16 import java.util.Set;
17 import java.util.stream.Collectors;
18
19 import org.eclipse.core.runtime.IConfigurationElement;
20 import org.eclipse.core.runtime.IRegistryChangeEvent;
21 import org.eclipse.core.runtime.IRegistryChangeListener;
22 import org.eclipse.core.runtime.IStatus;
23 import org.eclipse.core.runtime.Platform;
24 import org.eclipse.core.runtime.Status;
25 import org.eclipse.core.runtime.content.IContentType;
26 import org.eclipse.jface.text.source.ICharacterPairMatcher;
27 import org.eclipse.jface.text.source.ISourceViewer;
28 import org.eclipse.ui.texteditor.ITextEditor;
29
30 /**
31 * A registry of character pair matchers provided by extension
32 * <code>org.eclipse.ui.genericeditor.characterPairMatchers</code>. Those
33 * extensions are specific to a given {@link IContentType}.
34 *
35 * @since 1.2
36 */
37 public class CharacterPairMatcherRegistry {
38
39 private static final String EXTENSION_POINT_ID = GenericEditorPlugin.BUNDLE_ID + ".characterPairMatchers"; //$NON-NLS-1$
40
41 private Map<IConfigurationElement, GenericContentTypeRelatedExtension<ICharacterPairMatcher>> extensions = new HashMap<>();
42 private boolean outOfSync = true;
43
44 /**
45 * Creates the registry and binds it to the extension point.
46 */
47 public CharacterPairMatcherRegistry() {
48 Platform.getExtensionRegistry().addRegistryChangeListener(new IRegistryChangeListener() {
49 @Override
50 public void registryChanged(IRegistryChangeEvent event) {
51 outOfSync = true;
52 }
53 }, EXTENSION_POINT_ID);
54 }
55
56 /**
57 * Get the contributed {@link IPresentationReconciliers}s that are relevant to
58 * hook on source viewer according to document content types.
59 *
60 * @param sourceViewer the source viewer we're hooking completion to.
61 * @param editor the text editor
62 * @param contentTypes the content types of the document we're editing.
63 * @return the list of {@link ICharacterPairMatcher} contributed for at least
64 * one of the content types.
65 */
66 public List<ICharacterPairMatcher> getCharacterPairMatchers(ISourceViewer sourceViewer, ITextEditor editor,
67 Set<IContentType> contentTypes) {
68 if (this.outOfSync) {
69 sync();
70 }
71 return this.extensions.values().stream().filter(ext -> contentTypes.contains(ext.targetContentType))
72 .filter(ext -> ext.matches(sourceViewer, editor))
73 .sorted(new ContentTypeSpecializationComparator<ICharacterPairMatcher>())
74 .map(GenericContentTypeRelatedExtension<ICharacterPairMatcher>::createDelegate)
75 .collect(Collectors.toList());
76 }
77
78 private void sync() {
79 Set<IConfigurationElement> toRemoveExtensions = new HashSet<>(this.extensions.keySet());
80 for (IConfigurationElement extension : Platform.getExtensionRegistry()
81 .getConfigurationElementsFor(EXTENSION_POINT_ID)) {
82 toRemoveExtensions.remove(extension);
83 if (!this.extensions.containsKey(extension)) {
84 try {
85 this.extensions.put(extension,
86 new GenericContentTypeRelatedExtension<ICharacterPairMatcher>(extension));
87 } catch (Exception ex) {
88 GenericEditorPlugin.getDefault().getLog()
89 .log(new Status(IStatus.ERROR, GenericEditorPlugin.BUNDLE_ID, ex.getMessage(), ex));
90 }
91 }
92 }
93 for (IConfigurationElement toRemove : toRemoveExtensions) {
94 this.extensions.remove(toRemove);
95 }
96 this.outOfSync = false;
97 }
98
99 }
0 /**
1 * Copyright (c) 2018 Angelo ZERR.
2 * All rights reserved. This program and the accompanying materials
3 * are made available under the terms of the Eclipse Public License v2.0
4 * which accompanies this distribution, and is available at
5 * http://www.eclipse.org/legal/epl-v20.html
6 *
7 * Contributors:
8 * Angelo Zerr <angelo.zerr@gmail.com> - Bug 538111 - [generic editor] Extension point for ICharacterPairMatcher
9 */
10 package org.eclipse.ui.internal.genericeditor;
11
12 import java.util.HashMap;
13 import java.util.HashSet;
14 import java.util.List;
15 import java.util.Map;
16 import java.util.Set;
17 import java.util.stream.Collectors;
18
19 import org.eclipse.core.runtime.IConfigurationElement;
20 import org.eclipse.core.runtime.IRegistryChangeEvent;
21 import org.eclipse.core.runtime.IRegistryChangeListener;
22 import org.eclipse.core.runtime.IStatus;
23 import org.eclipse.core.runtime.Platform;
24 import org.eclipse.core.runtime.Status;
25 import org.eclipse.core.runtime.content.IContentType;
26 import org.eclipse.jface.text.source.ICharacterPairMatcher;
27 import org.eclipse.jface.text.source.ISourceViewer;
28 import org.eclipse.ui.texteditor.ITextEditor;
29
30 /**
31 * A registry of character pair matchers provided by extension
32 * <code>org.eclipse.ui.genericeditor.characterPairMatchers</code>. Those
33 * extensions are specific to a given {@link IContentType}.
34 *
35 * @since 1.2
36 */
37 public class CharacterPairMatcherRegistry {
38
39 private static final String EXTENSION_POINT_ID = GenericEditorPlugin.BUNDLE_ID + ".characterPairMatchers"; //$NON-NLS-1$
40
41 private Map<IConfigurationElement, GenericContentTypeRelatedExtension<ICharacterPairMatcher>> extensions = new HashMap<>();
42 private boolean outOfSync = true;
43
44 /**
45 * Creates the registry and binds it to the extension point.
46 */
47 public CharacterPairMatcherRegistry() {
48 Platform.getExtensionRegistry().addRegistryChangeListener(new IRegistryChangeListener() {
49 @Override
50 public void registryChanged(IRegistryChangeEvent event) {
51 outOfSync = true;
52 }
53 }, EXTENSION_POINT_ID);
54 }
55
56 /**
57 * Get the contributed {@link IPresentationReconciliers}s that are relevant to
58 * hook on source viewer according to document content types.
59 *
60 * @param sourceViewer the source viewer we're hooking completion to.
61 * @param editor the text editor
62 * @param contentTypes the content types of the document we're editing.
63 * @return the list of {@link ICharacterPairMatcher} contributed for at least
64 * one of the content types.
65 */
66 public List<ICharacterPairMatcher> getCharacterPairMatchers(ISourceViewer sourceViewer, ITextEditor editor,
67 Set<IContentType> contentTypes) {
68 if (this.outOfSync) {
69 sync();
70 }
71 return this.extensions.values().stream().filter(ext -> contentTypes.contains(ext.targetContentType))
72 .filter(ext -> ext.matches(sourceViewer, editor))
73 .sorted(new ContentTypeSpecializationComparator<ICharacterPairMatcher>())
74 .map(GenericContentTypeRelatedExtension<ICharacterPairMatcher>::createDelegate)
75 .collect(Collectors.toList());
76 }
77
78 private void sync() {
79 Set<IConfigurationElement> toRemoveExtensions = new HashSet<>(this.extensions.keySet());
80 for (IConfigurationElement extension : Platform.getExtensionRegistry()
81 .getConfigurationElementsFor(EXTENSION_POINT_ID)) {
82 toRemoveExtensions.remove(extension);
83 if (!this.extensions.containsKey(extension)) {
84 try {
85 this.extensions.put(extension,
86 new GenericContentTypeRelatedExtension<ICharacterPairMatcher>(extension));
87 } catch (Exception ex) {
88 GenericEditorPlugin.getDefault().getLog()
89 .log(new Status(IStatus.ERROR, GenericEditorPlugin.BUNDLE_ID, ex.getMessage(), ex));
90 }
91 }
92 }
93 for (IConfigurationElement toRemove : toRemoveExtensions) {
94 this.extensions.remove(toRemove);
95 }
96 this.outOfSync = false;
97 }
98
99 }
2121 private DefaultWordHighlightStrategy fStrategy;
2222
2323 public DefaultWordHighlightReconciler() {
24 fStrategy = new DefaultWordHighlightStrategy();
25 this.setReconcilingStrategy(fStrategy, IDocument.DEFAULT_CONTENT_TYPE);
26 }
24 fStrategy = new DefaultWordHighlightStrategy();
25 this.setReconcilingStrategy(fStrategy, IDocument.DEFAULT_CONTENT_TYPE);
26 }
2727
2828 @Override
2929 public void install(ITextViewer textViewer) {
4545
4646 /**
4747 *
48 * This Reconciler Strategy is a default stategy which will be present if no
49 * other highlightReconcilers are registered for a given content-type. It splits
50 * the text into 'words' (which are defined as anything in-between
51 * non-alphanumeric characters) and searches the document highlighting all like
52 * words.
53 *
54 * E.g. if your file contains "t^he dog in the bog" and you leave your caret at
55 * ^ you will get both instances of 'the' highlighted.
48 * This Reconciler Strategy is a default stategy which will be present if no other highlightReconcilers are registered for a given content-type. It splits the text into 'words' (which are defined as
49 * anything in-between non-alphanumeric characters) and searches the document highlighting all like words.
50 *
51 * E.g. if your file contains "t^he dog in the bog" and you leave your caret at ^ you will get both instances of 'the' highlighted.
5652 *
5753 */
58 public class DefaultWordHighlightStrategy
59 implements IReconcilingStrategy, IReconcilingStrategyExtension, IPreferenceChangeListener {
54 public class DefaultWordHighlightStrategy implements IReconcilingStrategy, IReconcilingStrategyExtension, IPreferenceChangeListener {
6055
6156 private static final String ANNOTATION_TYPE = "org.eclipse.ui.genericeditor.text"; //$NON-NLS-1$
6257
8479 }
8580
8681 String text = document.get();
87 int offset = ((ITextViewerExtension5) sourceViewer).widgetOffset2ModelOffset(textSelection.getOffset());
82 int offset = textSelection.getOffset();
83 if (sourceViewer instanceof ITextViewerExtension5) {
84 offset = ((ITextViewerExtension5) sourceViewer).widgetOffset2ModelOffset(textSelection.getOffset());
85 }
8886
8987 String word = findCurrentWord(text, offset);
9088 if (word == null) {
9694 Map<Annotation, Position> annotationMap = new HashMap<>();
9795 while (m.find()) {
9896 if (m.group().equals(word)) {
99 annotationMap.put(
100 new Annotation(ANNOTATION_TYPE, false,
101 NLS.bind(Messages.DefaultWordHighlightStrategy_OccurrencesOf, word)),
102 new Position(m.start(), m.end() - m.start()));
97 annotationMap.put(new Annotation(ANNOTATION_TYPE, false, NLS.bind(Messages.DefaultWordHighlightStrategy_OccurrencesOf, word)), new Position(m.start(), m.end() - m.start()));
10398 }
10499 }
105100
153148 preferences.addPreferenceChangeListener(this);
154149 this.enabled = preferences.getBoolean(ToggleHighlight.TOGGLE_HIGHLIGHT_PREFERENCE, true);
155150 this.sourceViewer = (ISourceViewer) viewer;
156 ((IPostSelectionProvider) sourceViewer.getSelectionProvider())
157 .addPostSelectionChangedListener(editorSelectionChangedListener);
151 ((IPostSelectionProvider) sourceViewer.getSelectionProvider()).addPostSelectionChangedListener(editorSelectionChangedListener);
158152 }
159153
160154 public void uninstall() {
161155 if (sourceViewer != null) {
162 ((IPostSelectionProvider) sourceViewer.getSelectionProvider())
163 .removePostSelectionChangedListener(editorSelectionChangedListener);
156 ((IPostSelectionProvider) sourceViewer.getSelectionProvider()).removePostSelectionChangedListener(editorSelectionChangedListener);
164157 }
165158 IEclipsePreferences preferences = InstanceScope.INSTANCE.getNode(GenericEditorPlugin.BUNDLE_ID);
166159 preferences.removePreferenceChangeListener(this);
167160 }
168161
169 @Override
170 public void preferenceChange(PreferenceChangeEvent event) {
162 @Override public void preferenceChange(PreferenceChangeEvent event) {
171163 if (event.getKey().equals(ToggleHighlight.TOGGLE_HIGHLIGHT_PREFERENCE)) {
172164 this.enabled = Boolean.parseBoolean(event.getNewValue().toString());
173165 if (enabled) {
178170 }
179171 }
180172
181 @Override
182 public void initialReconcile() {
173 @Override public void initialReconcile() {
183174 if (sourceViewer != null) {
184175 sourceViewer.getTextWidget().getDisplay().asyncExec(() -> {
185176 if (sourceViewer != null && sourceViewer.getTextWidget() != null) {
217208 return annotationModel;
218209 }
219210
220 @Override
221 public void setDocument(IDocument document) {
211 @Override public void setDocument(IDocument document) {
222212 this.document = document;
223213 }
224214
225 @Override
226 public void reconcile(DirtyRegion dirtyRegion, IRegion subRegion) {
215 @Override public void reconcile(DirtyRegion dirtyRegion, IRegion subRegion) {
227216 // Do nothing
228217 }
229218
230 @Override
231 public void reconcile(IRegion partition) {
219 @Override public void reconcile(IRegion partition) {
232220 // Do nothing
233221 }
234222
235 @Override
236 public void setProgressMonitor(IProgressMonitor monitor) {
223 @Override public void setProgressMonitor(IProgressMonitor monitor) {
237224 // Not used
238225 }
239226 }
3333 import org.eclipse.ui.texteditor.SourceViewerDecorationSupport;
3434
3535 /**
36 * A generic code editor that is aimed at being extended by contributions.
37 * Behavior is supposed to be added via extensions, not by inheritance.
36 * A generic code editor that is aimed at being extended by contributions. Behavior is supposed to be added via extensions, not by inheritance.
3837 *
3938 * @since 1.0
4039 */
6059 /**
6160 * Initializes the key binding scopes of this generic code editor.
6261 */
63 @Override
64 protected void initializeKeyBindingScopes() {
62 @Override protected void initializeKeyBindingScopes() {
6563 setKeyBindingScopes(new String[] { CONTEXT_ID });
6664 }
6765
68 @Override
69 protected void doSetInput(IEditorInput input) throws CoreException {
66 @Override protected void doSetInput(IEditorInput input) throws CoreException {
7067 super.doSetInput(input);
7168 configuration.watchDocument(getDocumentProvider().getDocument(input));
7269 }
7370
74 @Override
75 protected ISourceViewer createSourceViewer(Composite parent, IVerticalRuler ruler, int styles) {
71 @Override protected ISourceViewer createSourceViewer(Composite parent, IVerticalRuler ruler, int styles) {
7672 fAnnotationAccess = getAnnotationAccess();
7773 fOverviewRuler = createOverviewRuler(getSharedColors());
7874
79 ProjectionViewer viewer = new ProjectionViewer(parent, ruler, getOverviewRuler(), isOverviewRulerVisible(),
80 styles);
75 ProjectionViewer viewer = new ProjectionViewer(parent, ruler, getOverviewRuler(), isOverviewRulerVisible(), styles);
8176 SourceViewerDecorationSupport support = getSourceViewerDecorationSupport(viewer);
8277 configureCharacterPairMatcher(viewer, support);
8378 return viewer;
8479 }
8580
86 @Override
87 public void createPartControl(Composite parent) {
81 @Override public void createPartControl(Composite parent) {
8882 super.createPartControl(parent);
8983 ProjectionViewer viewer = (ProjectionViewer) getSourceViewer();
9084
9286 viewer.doOperation(ProjectionViewer.TOGGLE);
9387 }
9488
95 @Override
96 protected void initializeEditor() {
89 @Override protected void initializeEditor() {
9790 super.initializeEditor();
98 setPreferenceStore(new ChainedPreferenceStore(new IPreferenceStore[] {
99 GenericEditorPreferenceConstants.getPreferenceStore(), EditorsUI.getPreferenceStore() }));
91 setPreferenceStore(new ChainedPreferenceStore(new IPreferenceStore[] { GenericEditorPreferenceConstants.getPreferenceStore(), EditorsUI.getPreferenceStore() }));
10092 }
10193
10294 /**
103 * Configure the {@link ICharacterPairMatcher} from the
104 * "org.eclipse.ui.genericeditor.characterPairMatchers" extension point.
95 * Configure the {@link ICharacterPairMatcher} from the "org.eclipse.ui.genericeditor.characterPairMatchers" extension point.
10596 *
106 * @param viewer the source viewer.
97 * @param viewer
98 * the source viewer.
10799 *
108 * @param support the source viewer decoration support.
100 * @param support
101 * the source viewer decoration support.
109102 */
110103 private void configureCharacterPairMatcher(ISourceViewer viewer, SourceViewerDecorationSupport support) {
111 List<ICharacterPairMatcher> matchers = GenericEditorPlugin.getDefault().getCharacterPairMatcherRegistry()
112 .getCharacterPairMatchers(viewer, this, configuration.getContentTypes());
104 List<ICharacterPairMatcher> matchers = GenericEditorPlugin.getDefault().getCharacterPairMatcherRegistry().getCharacterPairMatchers(viewer, this, configuration.getContentTypes(viewer));
113105 if (!matchers.isEmpty()) {
114106 ICharacterPairMatcher matcher = matchers.get(0);
115107 support.setCharacterPairMatcher(matcher);
116 support.setMatchingCharacterPainterPreferenceKeys(MATCHING_BRACKETS, MATCHING_BRACKETS_COLOR,
117 HIGHLIGHT_BRACKET_AT_CARET_LOCATION, ENCLOSING_BRACKETS);
108 support.setMatchingCharacterPainterPreferenceKeys(MATCHING_BRACKETS, MATCHING_BRACKETS_COLOR, HIGHLIGHT_BRACKET_AT_CARET_LOCATION, ENCLOSING_BRACKETS);
118109 }
119110 }
120111 }
1717 package org.eclipse.ui.internal.genericeditor;
1818
1919 import java.util.Arrays;
20 import java.util.Collections;
2021 import java.util.LinkedHashSet;
2122 import java.util.LinkedList;
2223 import java.util.List;
2425 import java.util.Queue;
2526 import java.util.Set;
2627
28 import org.eclipse.core.filebuffers.FileBuffers;
29 import org.eclipse.core.filebuffers.ITextFileBuffer;
2730 import org.eclipse.core.runtime.IAdaptable;
2831 import org.eclipse.core.runtime.Platform;
2932 import org.eclipse.core.runtime.content.IContentType;
4447 import org.eclipse.jface.text.reconciler.IReconciler;
4548 import org.eclipse.jface.text.source.ISourceViewer;
4649 import org.eclipse.swt.widgets.Shell;
47 import org.eclipse.ui.IEditorPart;
4850 import org.eclipse.ui.editors.text.TextSourceViewerConfiguration;
4951 import org.eclipse.ui.internal.editors.text.EditorsPlugin;
5052 import org.eclipse.ui.internal.genericeditor.folding.DefaultFoldingReconciler;
5456 import org.eclipse.ui.texteditor.spelling.SpellingCorrectionProcessor;
5557
5658 /**
57 * The configuration of the {@link ExtensionBasedTextEditor}. It registers the
58 * proxy composite for hover, completion, syntax highlighting, and then those
59 * proxy take care of resolving to the right extensions on-demand.
59 * The configuration of the {@link ExtensionBasedTextEditor}. It registers the proxy composite for hover, completion, syntax highlighting, and then those proxy take care of resolving to the right
60 * extensions on-demand.
6061 *
6162 * @since 1.0
6263 */
6364 @SuppressWarnings("restriction")
64 public final class ExtensionBasedTextViewerConfiguration extends TextSourceViewerConfiguration
65 implements IDocumentPartitioningListener {
65 public final class ExtensionBasedTextViewerConfiguration extends TextSourceViewerConfiguration implements IDocumentPartitioningListener {
6666
6767 private ITextEditor editor;
6868 private Set<IContentType> contentTypes;
7373
7474 /**
7575 *
76 * @param editor the editor we're creating.
77 * @param preferenceStore the preference store.
76 * @param editor
77 * the editor we're creating.
78 * @param preferenceStore
79 * the preference store.
7880 */
7981 public ExtensionBasedTextViewerConfiguration(ITextEditor editor, IPreferenceStore preferenceStore) {
8082 super(preferenceStore);
8183 this.editor = editor;
82 this.editor.addPropertyListener((source, propId) -> {
83 if (propId == IEditorPart.PROP_INPUT) {
84 watchDocument(editor.getDocumentProvider().getDocument(editor.getEditorInput()));
85 }
86 });
87 }
88
89 Set<IContentType> getContentTypes() {
84 }
85
86 Set<IContentType> getContentTypes(ISourceViewer viewer) {
9087 if (this.contentTypes == null) {
9188 this.contentTypes = new LinkedHashSet<>();
92 Queue<IContentType> types = new LinkedList<>(Arrays
93 .asList(Platform.getContentTypeManager().findContentTypesFor(editor.getEditorInput().getName())));
89 String fileName = null;
90 if (this.editor != null) {
91 fileName = editor.getEditorInput().getName();
92 } else {
93 IDocument document = viewer.getDocument();
94 if (document != null) {
95 ITextFileBuffer buffer = FileBuffers.getTextFileBufferManager().getTextFileBuffer(document);
96 if (buffer != null) {
97 fileName = buffer.getLocation().lastSegment();
98 }
99 }
100 }
101 if (fileName == null) {
102 return Collections.emptySet();
103 }
104 Queue<IContentType> types = new LinkedList<>(Arrays.asList(Platform.getContentTypeManager().findContentTypesFor(fileName)));
94105 while (!types.isEmpty()) {
95106 IContentType type = types.poll();
96107 this.contentTypes.add(type);
103114 return this.contentTypes;
104115 }
105116
106 @Override
107 public ITextHover getTextHover(ISourceViewer sourceViewer, String contentType) {
108 List<ITextHover> hovers = GenericEditorPlugin.getDefault().getHoverRegistry().getAvailableHovers(sourceViewer,
109 editor, getContentTypes());
117 @Override public ITextHover getTextHover(ISourceViewer sourceViewer, String contentType) {
118 List<ITextHover> hovers = GenericEditorPlugin.getDefault().getHoverRegistry().getAvailableHovers(sourceViewer, editor, getContentTypes(sourceViewer));
110119 if (hovers == null || hovers.isEmpty()) {
111120 return null;
112121 } else if (hovers.size() == 1) {
116125 }
117126 }
118127
119 @Override
120 public IContentAssistant getContentAssistant(ISourceViewer sourceViewer) {
128 @Override public IContentAssistant getContentAssistant(ISourceViewer sourceViewer) {
121129 ContentAssistProcessorRegistry registry = GenericEditorPlugin.getDefault().getContentAssistProcessorRegistry();
122130 contentAssistant = new ContentAssistant(true);
123131 contentAssistant.setContextInformationPopupOrientation(ContentAssistant.CONTEXT_INFO_BELOW);
125133 contentAssistant.setAutoActivationDelay(0);
126134 contentAssistant.enableColoredLabels(true);
127135 contentAssistant.enableAutoActivation(true);
128 this.processors = registry.getContentAssistProcessors(sourceViewer, editor, getContentTypes());
136 this.processors = registry.getContentAssistProcessors(sourceViewer, editor, getContentTypes(sourceViewer));
129137 if (this.processors.isEmpty()) {
130138 this.processors.add(new DefaultContentAssistProcessor());
131139 }
136144 associateTokenContentTypes(this.document);
137145 }
138146 contentAssistant.setInformationControlCreator(new AbstractReusableInformationControlCreator() {
139 @Override
140 protected IInformationControl doCreateInformationControl(Shell parent) {
147 @Override protected IInformationControl doCreateInformationControl(Shell parent) {
141148 return new DefaultInformationControl(parent);
142149 }
143150 });
151 watchDocument(sourceViewer.getDocument());
144152 return contentAssistant;
145153 }
146154
147 @Override
148 public IPresentationReconciler getPresentationReconciler(ISourceViewer sourceViewer) {
155 @Override public IPresentationReconciler getPresentationReconciler(ISourceViewer sourceViewer) {
149156 PresentationReconcilerRegistry registry = GenericEditorPlugin.getDefault().getPresentationReconcilerRegistry();
150 List<IPresentationReconciler> reconciliers = registry.getPresentationReconcilers(sourceViewer, editor,
151 getContentTypes());
157 List<IPresentationReconciler> reconciliers = registry.getPresentationReconcilers(sourceViewer, editor, getContentTypes(sourceViewer));
152158 if (!reconciliers.isEmpty()) {
153159 return reconciliers.get(0);
154160 }
162168 if (this.document != null) {
163169 this.document.removeDocumentPartitioningListener(this);
164170 }
165 this.document = document;
166 associateTokenContentTypes(document);
167 document.addDocumentPartitioningListener(this);
168 }
169
170 @Override
171 public void documentPartitioningChanged(IDocument document) {
171 if (document != null) {
172 this.document = document;
173 associateTokenContentTypes(document);
174 document.addDocumentPartitioningListener(this);
175 }
176 }
177
178 @Override public void documentPartitioningChanged(IDocument document) {
172179 associateTokenContentTypes(document);
173180 }
174181
183190 }
184191 }
185192
186 @Override
187 public IQuickAssistAssistant getQuickAssistAssistant(ISourceViewer sourceViewer) {
193 @Override public IQuickAssistAssistant getQuickAssistAssistant(ISourceViewer sourceViewer) {
188194 QuickAssistAssistant quickAssistAssistant = new QuickAssistAssistant();
189 CompositeQuickAssistProcessor processor = new CompositeQuickAssistProcessor(
190 Arrays.asList(new MarkerResoltionQuickAssistProcessor(), new SpellingCorrectionProcessor()));
195 CompositeQuickAssistProcessor processor = new CompositeQuickAssistProcessor(Arrays.asList(new MarkerResoltionQuickAssistProcessor(), new SpellingCorrectionProcessor()));
191196 quickAssistAssistant.setQuickAssistProcessor(processor);
192 quickAssistAssistant.setRestoreCompletionProposalSize(
193 EditorsPlugin.getDefault().getDialogSettingsSection("quick_assist_proposal_size")); //$NON-NLS-1$
194 quickAssistAssistant.setInformationControlCreator(
195 parent -> new DefaultInformationControl(parent, EditorsPlugin.getAdditionalInfoAffordanceString()));
197 quickAssistAssistant.setRestoreCompletionProposalSize(EditorsPlugin.getDefault().getDialogSettingsSection("quick_assist_proposal_size")); //$NON-NLS-1$
198 quickAssistAssistant.setInformationControlCreator(parent -> new DefaultInformationControl(parent, EditorsPlugin.getAdditionalInfoAffordanceString()));
196199 return quickAssistAssistant;
197200 }
198201
199 @Override
200 public IReconciler getReconciler(ISourceViewer sourceViewer) {
202 @Override public IReconciler getReconciler(ISourceViewer sourceViewer) {
201203 ReconcilerRegistry registry = GenericEditorPlugin.getDefault().getReconcilerRegistry();
202 List<IReconciler> reconcilers = registry.getReconcilers(sourceViewer, editor, getContentTypes());
204 List<IReconciler> reconcilers = registry.getReconcilers(sourceViewer, editor, getContentTypes(sourceViewer));
203205 // Fill with highlight reconcilers
204 List<IReconciler> highlightReconcilers = registry.getHighlightReconcilers(sourceViewer, editor,
205 getContentTypes());
206 List<IReconciler> highlightReconcilers = registry.getHighlightReconcilers(sourceViewer, editor, getContentTypes(sourceViewer));
206207 if (!highlightReconcilers.isEmpty()) {
207208 reconcilers.addAll(highlightReconcilers);
208209 } else {
209210 reconcilers.add(new DefaultWordHighlightReconciler());
210211 }
211212 // Fill with folding reconcilers
212 List<IReconciler> foldingReconcilers = registry.getFoldingReconcilers(sourceViewer, editor, getContentTypes());
213 List<IReconciler> foldingReconcilers = registry.getFoldingReconcilers(sourceViewer, editor, getContentTypes(sourceViewer));
213214 if (!foldingReconcilers.isEmpty()) {
214215 reconcilers.addAll(foldingReconcilers);
215216 } else {
222223 return null;
223224 }
224225
225 @Override
226 public IAutoEditStrategy[] getAutoEditStrategies(ISourceViewer sourceViewer, String contentType) {
226 @Override public IAutoEditStrategy[] getAutoEditStrategies(ISourceViewer sourceViewer, String contentType) {
227227 AutoEditStrategyRegistry registry = GenericEditorPlugin.getDefault().getAutoEditStrategyRegistry();
228 List<IAutoEditStrategy> editStrategies = registry.getAutoEditStrategies(sourceViewer, editor,
229 getContentTypes());
228 List<IAutoEditStrategy> editStrategies = registry.getAutoEditStrategies(sourceViewer, editor, getContentTypes(sourceViewer));
230229 if (!editStrategies.isEmpty()) {
231230 return editStrategies.toArray(new IAutoEditStrategy[editStrategies.size()]);
232231 }
233232 return super.getAutoEditStrategies(sourceViewer, contentType);
234233 }
235234
236 @Override
237 protected Map<String, IAdaptable> getHyperlinkDetectorTargets(ISourceViewer sourceViewer) {
235 @Override protected Map<String, IAdaptable> getHyperlinkDetectorTargets(ISourceViewer sourceViewer) {
238236 Map<String, IAdaptable> targets = super.getHyperlinkDetectorTargets(sourceViewer);
239237 targets.put("org.eclipse.ui.genericeditor.GenericEditor", editor); //$NON-NLS-1$
240238 return targets;
2727 import org.eclipse.ui.texteditor.ITextEditor;
2828
2929 /**
30 * This class wraps and proxies an instance of T provided through extensions
31 * and loads it lazily when it can contribute to the editor, then delegates all operations to
32 * actual instance.
30 * This class wraps and proxies an instance of T provided through extensions and loads it lazily when it can contribute to the editor, then delegates all operations to actual instance.
3331 *
34 * @param <T> the actual type to proxy, typically the one defined on the extension point.
32 * @param <T>
33 * the actual type to proxy, typically the one defined on the extension point.
3534 */
3635 public class GenericContentTypeRelatedExtension<T> {
3736 private static final String ID_ATTRIBUTE = "id"; //$NON-NLS-1$
4544
4645 public GenericContentTypeRelatedExtension(IConfigurationElement element) throws Exception {
4746 this.extension = element;
48 this.targetContentType = Platform.getContentTypeManager()
49 .getContentType(element.getAttribute(CONTENT_TYPE_ATTRIBUTE));
47 this.targetContentType = Platform.getContentTypeManager().getContentType(element.getAttribute(CONTENT_TYPE_ATTRIBUTE));
5048 this.enabledWhen = buildEnabledWhen(element);
5149 }
5250
53 @SuppressWarnings("unchecked")
54 public T createDelegate() {
51 @SuppressWarnings("unchecked") public T createDelegate() {
5552 try {
5653 return (T) extension.createExecutableExtension(CLASS_ATTRIBUTE);
5754 } catch (CoreException e) {
6158 }
6259
6360 /**
64 * Returns the expression {@link Expression} declared in the
65 * <code>enabledWhen</code> element.
61 * Returns the expression {@link Expression} declared in the <code>enabledWhen</code> element.
6662 *
67 * @param configElement the configuration element
68 * @return the expression {@link Expression} declared in the enabledWhen
69 * element.
70 * @throws CoreException when enabledWhen expression is not valid.
63 * @param configElement
64 * the configuration element
65 * @return the expression {@link Expression} declared in the enabledWhen element.
66 * @throws CoreException
67 * when enabledWhen expression is not valid.
7168 */
7269 private static Expression buildEnabledWhen(IConfigurationElement configElement) throws CoreException {
7370 final IConfigurationElement[] children = configElement.getChildren(ENABLED_WHEN_ATTRIBUTE);
7471 if (children.length > 0) {
7572 IConfigurationElement[] subChildren = children[0].getChildren();
7673 if (subChildren.length != 1) {
77 throw new CoreException(new Status(IStatus.ERROR, GenericEditorPlugin.BUNDLE_ID,
78 "One <enabledWhen> element is accepted. Disabling " //$NON-NLS-1$
79 + configElement.getAttribute(ID_ATTRIBUTE)));
74 throw new CoreException(new Status(IStatus.ERROR, GenericEditorPlugin.BUNDLE_ID, "One <enabledWhen> element is accepted. Disabling " //$NON-NLS-1$
75 + configElement.getAttribute(ID_ATTRIBUTE)));
8076 }
8177 final ElementHandler elementHandler = ElementHandler.getDefault();
8278 final ExpressionConverter converter = ExpressionConverter.getDefault();
8682 }
8783
8884 /**
89 * Returns true if the given viewer, editor matches the enabledWhen expression
90 * and false otherwise.
85 * Returns true if the given viewer, editor matches the enabledWhen expression and false otherwise.
9186 *
92 * @param viewer the viewer
93 * @param editor the editor
94 * @return true if the given viewer, editor matches the enabledWhen expression
95 * and false otherwise.
87 * @param viewer
88 * the viewer
89 * @param editor
90 * the editor
91 * @return true if the given viewer, editor matches the enabledWhen expression and false otherwise.
9692 */
9793 public boolean matches(ISourceViewer viewer, ITextEditor editor) {
9894 if (enabledWhen == null) {
9995 return true;
10096 }
101 EvaluationContext context = new EvaluationContext(null, editor);
97 EvaluationContext context = new EvaluationContext(null, editor != null ? editor : viewer);
10298 context.setAllowPluginActivation(true);
10399 context.addVariable("viewer", viewer); //$NON-NLS-1$
104 context.addVariable("editor", editor); //$NON-NLS-1$
105 context.addVariable("editorInput", editor.getEditorInput()); //$NON-NLS-1$
100 if (viewer.getDocument() != null) {
101 context.addVariable("document", viewer.getDocument()); //$NON-NLS-1$
102 }
103 if (editor != null) {
104 context.addVariable("editor", editor); //$NON-NLS-1$
105 context.addVariable("editorInput", editor.getEditorInput()); //$NON-NLS-1$
106 }
106107 try {
107108 return enabledWhen.evaluate(context) == EvaluationResult.TRUE;
108109 } catch (CoreException e) {
109 GenericEditorPlugin.getDefault().getLog().log(new Status(IStatus.ERROR, GenericEditorPlugin.BUNDLE_ID,
110 "Error while 'enabledWhen' evaluation", e)); //$NON-NLS-1$
110 GenericEditorPlugin.getDefault().getLog().log(new Status(IStatus.ERROR, GenericEditorPlugin.BUNDLE_ID, "Error while 'enabledWhen' evaluation", e)); //$NON-NLS-1$
111111 return false;
112112 }
113113 }
0 /*******************************************************************************
1 * Copyright (c) 2019 Red Hat Inc. and others.
2 *
3 * This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License 2.0
5 * which accompanies this distribution, and is available at
6 * https://www.eclipse.org/legal/epl-2.0/
7 *
8 * SPDX-License-Identifier: EPL-2.0
9 *
10 * Contributors:
11 * - Mickael Istria (Red Hat Inc.)
12 *******************************************************************************/
13 package org.eclipse.ui.internal.genericeditor.compare;
14
15 import org.eclipse.compare.CompareConfiguration;
16 import org.eclipse.compare.IViewerCreator;
17 import org.eclipse.jface.viewers.Viewer;
18 import org.eclipse.swt.widgets.Composite;
19
20 public class CompareViewerCreator implements IViewerCreator {
21
22 @Override public Viewer createViewer(Composite parent, CompareConfiguration compareConfiguration) {
23 return new GenericEditorMergeViewer(parent, compareConfiguration);
24 }
25
26 }
0 /*******************************************************************************
1 * Copyright (c) 2019 Red Hat Inc. and others.
2 *
3 * This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License 2.0
5 * which accompanies this distribution, and is available at
6 * https://www.eclipse.org/legal/epl-2.0/
7 *
8 * SPDX-License-Identifier: EPL-2.0
9 *
10 * Contributors:
11 * - Mickael Istria (Red Hat Inc.)
12 *******************************************************************************/
13 package org.eclipse.ui.internal.genericeditor.compare;
14
15 import org.eclipse.compare.CompareConfiguration;
16 import org.eclipse.compare.contentmergeviewer.TextMergeViewer;
17 import org.eclipse.jface.text.IDocument;
18 import org.eclipse.jface.text.ITextInputListener;
19 import org.eclipse.jface.text.TextViewer;
20 import org.eclipse.jface.text.source.ISourceViewer;
21 import org.eclipse.jface.text.source.SourceViewer;
22 import org.eclipse.swt.widgets.Composite;
23 import org.eclipse.ui.internal.genericeditor.ExtensionBasedTextViewerConfiguration;
24 import org.eclipse.ui.internal.genericeditor.GenericEditorPlugin;
25
26 public class GenericEditorMergeViewer extends TextMergeViewer {
27
28 public GenericEditorMergeViewer(Composite parent, CompareConfiguration configuration) {
29 super(parent, configuration);
30 }
31
32 @Override protected SourceViewer createSourceViewer(Composite parent, int textOrientation) {
33 SourceViewer res = super.createSourceViewer(parent, textOrientation);
34 res.addTextInputListener(new ITextInputListener() {
35 @Override public void inputDocumentChanged(IDocument oldInput, IDocument newInput) {
36 configureTextViewer(res);
37 }
38
39 @Override public void inputDocumentAboutToBeChanged(IDocument oldInput, IDocument newInput) {
40 // Nothing to do
41 }
42 });
43 return res;
44 }
45
46 @Override protected void configureTextViewer(TextViewer textViewer) {
47 if (textViewer.getDocument() != null && textViewer instanceof ISourceViewer) {
48 ((ISourceViewer) textViewer).configure(new ExtensionBasedTextViewerConfiguration(null, GenericEditorPlugin.getDefault().getPreferenceStore()));
49 }
50 }
51
52 }
2828 this.foldingStrategy = new IndentFoldingStrategy();
2929 }
3030
31 @Override
32 public void install(ITextViewer textViewer) {
31 @Override public void install(ITextViewer textViewer) {
3332 super.install(textViewer);
34 ProjectionViewer viewer = (ProjectionViewer) textViewer;
35 foldingStrategy.setViewer(viewer);
33 if (textViewer instanceof ProjectionViewer) {
34 ProjectionViewer viewer = (ProjectionViewer) textViewer;
35 foldingStrategy.setViewer(viewer);
36 }
3637 }
3738
38 @Override
39 public void uninstall() {
39 @Override public void uninstall() {
4040 super.uninstall();
41 foldingStrategy.uninstall();
41 if (foldingStrategy != null) {
42 foldingStrategy.uninstall();
43 }
4244 }
4345
44 @Override
45 protected void process(DirtyRegion dirtyRegion) {
46 @Override protected void process(DirtyRegion dirtyRegion) {
4647 foldingStrategy.reconcile(dirtyRegion, null);
4748 }
4849
49 @Override
50 protected void reconcilerDocumentChanged(IDocument newDocument) {
50 @Override protected void reconcilerDocumentChanged(IDocument newDocument) {
5151 foldingStrategy.setDocument(newDocument);
5252 }
5353
54 @Override
55 public IReconcilingStrategy getReconcilingStrategy(String contentType) {
54 @Override public IReconcilingStrategy getReconcilingStrategy(String contentType) {
5655 return foldingStrategy;
5756 }
5857
59 @Override
60 public void setProgressMonitor(IProgressMonitor monitor) {
58 @Override public void setProgressMonitor(IProgressMonitor monitor) {
6159 super.setProgressMonitor(monitor);
6260 foldingStrategy.setProgressMonitor(monitor);
6361 }
6462
65 @Override
66 protected void initialProcess() {
63 @Override protected void initialProcess() {
6764 super.initialProcess();
6865 foldingStrategy.initialReconcile();
6966 }
0 /*******************************************************************************
1 * Copyright (c) 2009, 2018 IBM Corporation and others.
2 *
3 * This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License 2.0
5 * which accompanies this distribution, and is available at
6 * https://www.eclipse.org/legal/epl-2.0/
7 *
8 * SPDX-License-Identifier: EPL-2.0
9 *
10 * Contributors:
11 * IBM Corporation - initial API and implementation
12 * Angelo Zerr <angelo.zerr@gmail.com> - adapt code org.eclipse.wst.sse.ui.internal.projection.AbstractStructuredFoldingStrategy to support generic indent folding strategy.
13 * [generic editor] Default Code folding for generic editor should use IndentFoldingStrategy - Bug 520659
14 */
15 package org.eclipse.ui.internal.genericeditor.folding;
16
17 import java.util.ArrayList;
18 import java.util.HashMap;
19 import java.util.Iterator;
20 import java.util.List;
21 import java.util.Map;
22
23 import org.eclipse.core.runtime.IProgressMonitor;
24 import org.eclipse.jface.text.BadLocationException;
25 import org.eclipse.jface.text.IDocument;
26 import org.eclipse.jface.text.IRegion;
27 import org.eclipse.jface.text.Position;
28 import org.eclipse.jface.text.reconciler.DirtyRegion;
29 import org.eclipse.jface.text.reconciler.IReconcilingStrategy;
30 import org.eclipse.jface.text.reconciler.IReconcilingStrategyExtension;
31 import org.eclipse.jface.text.source.Annotation;
32 import org.eclipse.jface.text.source.projection.IProjectionListener;
33 import org.eclipse.jface.text.source.projection.ProjectionAnnotation;
34 import org.eclipse.jface.text.source.projection.ProjectionAnnotationModel;
35 import org.eclipse.jface.text.source.projection.ProjectionViewer;
36 import org.eclipse.swt.graphics.FontMetrics;
37 import org.eclipse.swt.graphics.GC;
38 import org.eclipse.swt.graphics.Rectangle;
39 import org.eclipse.swt.widgets.Canvas;
40
41 /**
42 * Indent folding strategy to fold code by using indentation. The folding
43 * strategy must be associated with a viewer for it to function.
44 */
45 public class IndentFoldingStrategy implements IReconcilingStrategy, IReconcilingStrategyExtension, IProjectionListener {
46
47 private IDocument document;
48 private ProjectionViewer viewer;
49 private ProjectionAnnotationModel projectionAnnotationModel;
50 private final String lineStartsWithKeyword;
51
52 public IndentFoldingStrategy() {
53 this(null);
54 }
55
56 public IndentFoldingStrategy(String lineStartsWithKeyword) {
57 this.lineStartsWithKeyword = lineStartsWithKeyword;
58 }
59
60 /**
61 * A FoldingAnnotation is a {@link ProjectionAnnotation} it is folding and
62 * overriding the paint method (in a hacky type way) to prevent one line folding
63 * annotations to be drawn.
64 */
65 protected class FoldingAnnotation extends ProjectionAnnotation {
66 private boolean visible; /* workaround for BUG85874 */
67
68 /**
69 * Creates a new FoldingAnnotation.
70 *
71 * @param isCollapsed true if this annotation should be collapsed, false
72 * otherwise
73 */
74 public FoldingAnnotation(boolean isCollapsed) {
75 super(isCollapsed);
76 visible = false;
77 }
78
79 /**
80 * Does not paint hidden annotations. Annotations are hidden when they only span
81 * one line.
82 *
83 * @see ProjectionAnnotation#paint(org.eclipse.swt.graphics.GC,
84 * org.eclipse.swt.widgets.Canvas, org.eclipse.swt.graphics.Rectangle)
85 */
86 @Override
87 public void paint(GC gc, Canvas canvas, Rectangle rectangle) {
88 /* workaround for BUG85874 */
89 /*
90 * only need to check annotations that are expanded because hidden annotations
91 * should never have been given the chance to collapse.
92 */
93 if (!isCollapsed()) {
94 // working with rectangle, so line height
95 FontMetrics metrics = gc.getFontMetrics();
96 if (metrics != null) {
97 // do not draw annotations that only span one line and
98 // mark them as not visible
99 if ((rectangle.height / metrics.getHeight()) <= 1) {
100 visible = false;
101 return;
102 }
103 }
104 }
105 visible = true;
106 super.paint(gc, canvas, rectangle);
107 }
108
109 @Override
110 public void markCollapsed() {
111 /* workaround for BUG85874 */
112 // do not mark collapsed if annotation is not visible
113 if (visible)
114 super.markCollapsed();
115 }
116 }
117
118 /**
119 * The folding strategy must be associated with a viewer for it to function
120 *
121 * @param viewer the viewer to associate this folding strategy with
122 */
123 public void setViewer(ProjectionViewer viewer) {
124 if (this.viewer != null) {
125 this.viewer.removeProjectionListener(this);
126 }
127 this.viewer = viewer;
128 this.viewer.addProjectionListener(this);
129 this.projectionAnnotationModel = this.viewer.getProjectionAnnotationModel();
130 }
131
132 public void uninstall() {
133 setDocument(null);
134
135 if (viewer != null) {
136 viewer.removeProjectionListener(this);
137 viewer = null;
138 }
139
140 projectionDisabled();
141 }
142
143 @Override
144 public void setDocument(IDocument document) {
145 this.document = document;
146 }
147
148 @Override
149 public void projectionDisabled() {
150 projectionAnnotationModel = null;
151 }
152
153 @Override
154 public void projectionEnabled() {
155 if (viewer != null) {
156 projectionAnnotationModel = viewer.getProjectionAnnotationModel();
157 }
158 }
159
160 private class LineIndent {
161 public int line;
162 public final int indent;
163
164 public LineIndent(int line, int indent) {
165 this.line = line;
166 this.indent = indent;
167 }
168 }
169
170 @Override
171 public void reconcile(DirtyRegion dirtyRegion, IRegion subRegion) {
172 if (projectionAnnotationModel != null) {
173
174 // these are what are passed off to the annotation model to
175 // actually create and maintain the annotations
176 List<Annotation> modifications = new ArrayList<Annotation>();
177 List<FoldingAnnotation> deletions = new ArrayList<FoldingAnnotation>();
178 List<FoldingAnnotation> existing = new ArrayList<FoldingAnnotation>();
179 Map<Annotation, Position> additions = new HashMap<Annotation, Position>();
180
181 // find and mark all folding annotations with length 0 for deletion
182 markInvalidAnnotationsForDeletion(dirtyRegion, deletions, existing);
183
184 List<LineIndent> previousRegions = new ArrayList<LineIndent>();
185
186 int tabSize = 1;
187 int minimumRangeSize = 1;
188 try {
189
190 // Today we recompute annotation from the whole document each
191 // time.
192 // performance s good even with large document, but it should be
193 // better to loop for only DirtyRegion (and before/after)
194 // int offset = dirtyRegion.getOffset();
195 // int length = dirtyRegion.getLength();
196 // int startLine = 0; //document.getLineOfOffset(offset);
197 int endLine = document.getNumberOfLines() - 1; // startLine +
198 // document.getNumberOfLines(offset,
199 // length) - 1;
200
201 // sentinel, to make sure there's at least one entry
202 previousRegions.add(new LineIndent(endLine + 1, -1));
203
204 int lastLineWhichIsNotEmpty = 0;
205 int lineEmptyCount = 0;
206 Integer lastLineForKeyword = null;
207 int line = endLine;
208 for (line = endLine; line >= 0; line--) {
209 int lineOffset = document.getLineOffset(line);
210 String delim = document.getLineDelimiter(line);
211 int lineLength = document.getLineLength(line) - (delim != null ? delim.length() : 0);
212 String lineContent = document.get(lineOffset, lineLength);
213
214 LineState state = getLineState(lineContent, lastLineForKeyword);
215 switch (state) {
216 case StartWithKeyWord:
217 lineEmptyCount = 0;
218 lastLineWhichIsNotEmpty = line;
219 if (lastLineForKeyword == null) {
220 lastLineForKeyword = line;
221 }
222 break;
223 case EmptyLine:
224 lineEmptyCount++;
225 break;
226 default:
227 addAnnotationForKeyword(modifications, deletions, existing, additions,
228 line + 1 + lineEmptyCount, lastLineForKeyword);
229 lastLineForKeyword = null;
230 lineEmptyCount = 0;
231 lastLineWhichIsNotEmpty = line;
232 int indent = computeIndentLevel(lineContent, tabSize);
233 if (indent == -1) {
234 continue; // only whitespace
235 }
236
237 LineIndent previous = previousRegions.get(previousRegions.size() - 1);
238 if (previous.indent > indent) {
239 // discard all regions with larger indent
240 do {
241 previousRegions.remove(previousRegions.size() - 1);
242 previous = previousRegions.get(previousRegions.size() - 1);
243 } while (previous.indent > indent);
244
245 // new folding range
246 int endLineNumber = previous.line - 1;
247 if (endLineNumber - line >= minimumRangeSize) {
248 updateAnnotation(modifications, deletions, existing, additions, line, endLineNumber);
249 }
250 }
251 if (previous.indent == indent) {
252 previous.line = line;
253 } else { // previous.indent < indent
254 // new region with a bigger indent
255 previousRegions.add(new LineIndent(line, indent));
256 }
257 }
258 }
259 addAnnotationForKeyword(modifications, deletions, existing, additions, lastLineWhichIsNotEmpty,
260 lastLineForKeyword);
261 } catch (BadLocationException e) {
262 // should never done
263 e.printStackTrace();
264 }
265
266 // be sure projection has not been disabled
267 if (projectionAnnotationModel != null) {
268 if (existing.size() > 0) {
269 deletions.addAll(existing);
270 }
271 // send the calculated updates to the annotations to the
272 // annotation model
273 projectionAnnotationModel.modifyAnnotations(deletions.toArray(new Annotation[1]), additions,
274 modifications.toArray(new Annotation[0]));
275 }
276 }
277 }
278
279 private void addAnnotationForKeyword(List<Annotation> modifications, List<FoldingAnnotation> deletions,
280 List<FoldingAnnotation> existing, Map<Annotation, Position> additions, int startLine,
281 Integer lastLineForKeyword) throws BadLocationException {
282 if (lastLineForKeyword != null) {
283 updateAnnotation(modifications, deletions, existing, additions, startLine, lastLineForKeyword);
284 }
285 }
286
287 private enum LineState {
288 StartWithKeyWord, DontStartWithKeyWord, EmptyLine
289 }
290
291 /**
292 * Returns the line state for line which starts with a given keyword.
293 *
294 * @param lineContent line content.
295 * @param lastLineForKeyword last line for the given keyword.
296 * @return
297 */
298 private LineState getLineState(String lineContent, Integer lastLineForKeyword) {
299 if (lineStartsWithKeyword == null) {
300 // none keyword defined.
301 return LineState.DontStartWithKeyWord;
302 }
303 if (lineContent != null && lineContent.trim().startsWith(lineStartsWithKeyword)) {
304 // The line starts with the given keyword (ex: starts with "import")
305 return LineState.StartWithKeyWord;
306 }
307 if (lastLineForKeyword != null && (lineContent == null || lineContent.trim().length() == 0)) {
308 // a last line for keyword was defined, line is empty
309 return LineState.EmptyLine;
310 }
311 return LineState.DontStartWithKeyWord;
312 }
313
314 /**
315 * Compute indentation level of the given line by using the given tab size.
316 *
317 * @param line the line text.
318 * @param tabSize the tab size.
319 * @return the indentation level of the given line by using the given tab size.
320 */
321 private static int computeIndentLevel(String line, int tabSize) {
322 int i = 0;
323 int indent = 0;
324 while (i < line.length()) {
325 char ch = line.charAt(i);
326 if (ch == ' ') {
327 indent++;
328 } else if (ch == '\t') {
329 indent = indent - indent % tabSize + tabSize;
330 } else {
331 break;
332 }
333 i++;
334 }
335 if (i == line.length()) {
336 return -1; // line only consists of whitespace
337 }
338 return indent;
339 }
340
341 /**
342 * Given a {@link DirtyRegion} returns an {@link Iterator} of the already
343 * existing annotations in that region.
344 *
345 * @param dirtyRegion the {@link DirtyRegion} to check for existing annotations
346 * in
347 *
348 * @return an {@link Iterator} over the annotations in the given
349 * {@link DirtyRegion}. The iterator could have no annotations in it. Or
350 * <code>null</code> if projection has been disabled.
351 */
352 private Iterator<Annotation> getAnnotationIterator(DirtyRegion dirtyRegion) {
353 Iterator<Annotation> annoIter = null;
354 // be sure project has not been disabled
355 if (projectionAnnotationModel != null) {
356 // workaround for Platform Bug 299416
357 annoIter = projectionAnnotationModel.getAnnotationIterator(0, document.getLength(), false, false);
358 }
359 return annoIter;
360 }
361
362 /**
363 * Update annotations.
364 *
365 * @param modifications the folding annotations to update.
366 * @param deletions the folding annotations to delete.
367 * @param existing the existing folding annotations.
368 * @param additions annoation to add
369 * @param line the line index
370 * @param endLineNumber the end line number
371 * @throws BadLocationException
372 */
373 private void updateAnnotation(List<Annotation> modifications, List<FoldingAnnotation> deletions,
374 List<FoldingAnnotation> existing, Map<Annotation, Position> additions, int line, Integer endLineNumber)
375 throws BadLocationException {
376 int startOffset = document.getLineOffset(line);
377 int endOffset = document.getLineOffset(endLineNumber) + document.getLineLength(endLineNumber);
378 Position newPos = new Position(startOffset, endOffset - startOffset);
379 if (existing.size() > 0) {
380 FoldingAnnotation existingAnnotation = existing.remove(existing.size() - 1);
381 updateAnnotations(existingAnnotation, newPos, modifications, deletions);
382 } else {
383 additions.put(new FoldingAnnotation(false), newPos);
384 }
385 }
386
387 /**
388 * Update annotations.
389 *
390 * @param existingAnnotation the existing annotations that need to be updated
391 * based on the given dirtied IndexRegion
392 * @param newPos the new position that caused the annotations need
393 * for updating and null otherwise.
394 * @param modifications the list of annotations to be modified
395 * @param deletions the list of annotations to be deleted
396 */
397 protected void updateAnnotations(Annotation existingAnnotation, Position newPos, List<Annotation> modifications,
398 List<FoldingAnnotation> deletions) {
399 if (existingAnnotation instanceof FoldingAnnotation) {
400 FoldingAnnotation foldingAnnotation = (FoldingAnnotation) existingAnnotation;
401
402 // if a new position can be calculated then update the position of
403 // the annotation,
404 // else the annotation needs to be deleted
405 if (newPos != null && newPos.length > 0 && projectionAnnotationModel != null) {
406 Position oldPos = projectionAnnotationModel.getPosition(foldingAnnotation);
407 // only update the position if we have to
408 if (!newPos.equals(oldPos)) {
409 oldPos.setOffset(newPos.offset);
410 oldPos.setLength(newPos.length);
411 modifications.add(foldingAnnotation);
412 }
413 } else {
414 deletions.add(foldingAnnotation);
415 }
416 }
417 }
418
419 /**
420 * <p>
421 * Searches the given {@link DirtyRegion} for annotations that now have a length
422 * of 0. This is caused when something that was being folded has been deleted.
423 * These {@link FoldingAnnotation}s are then added to the {@link List} of
424 * {@link FoldingAnnotation}s to be deleted
425 * </p>
426 *
427 * @param dirtyRegion find the now invalid {@link FoldingAnnotation}s in this
428 * {@link DirtyRegion}
429 * @param deletions the current list of {@link FoldingAnnotation}s marked for
430 * deletion that the newly found invalid
431 * {@link FoldingAnnotation}s will be added to
432 */
433 protected void markInvalidAnnotationsForDeletion(DirtyRegion dirtyRegion, List<FoldingAnnotation> deletions,
434 List<FoldingAnnotation> existing) {
435 Iterator<Annotation> iter = getAnnotationIterator(dirtyRegion);
436 if (iter != null) {
437 while (iter.hasNext()) {
438 Annotation anno = iter.next();
439 if (anno instanceof FoldingAnnotation) {
440 FoldingAnnotation folding = (FoldingAnnotation) anno;
441 Position pos = projectionAnnotationModel.getPosition(anno);
442 if (pos.length == 0) {
443 deletions.add(folding);
444 } else {
445 existing.add(folding);
446 }
447 }
448 }
449 }
450 }
451
452 @Override
453 public void reconcile(IRegion partition) {
454 // not used, we use:
455 // reconcile(DirtyRegion dirtyRegion, IRegion subRegion)
456 }
457
458 @Override
459 public void setProgressMonitor(IProgressMonitor monitor) {
460 // Do nothing
461 }
462
463 @Override
464 public void initialReconcile() {
465 reconcile(new DirtyRegion(0, document.getLength(), DirtyRegion.INSERT, document.get()), null);
466 }
0 /*******************************************************************************
1 * Copyright (c) 2009, 2018 IBM Corporation and others.
2 *
3 * This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License 2.0
5 * which accompanies this distribution, and is available at
6 * https://www.eclipse.org/legal/epl-2.0/
7 *
8 * SPDX-License-Identifier: EPL-2.0
9 *
10 * Contributors:
11 * IBM Corporation - initial API and implementation
12 * Angelo Zerr <angelo.zerr@gmail.com> - adapt code org.eclipse.wst.sse.ui.internal.projection.AbstractStructuredFoldingStrategy to support generic indent folding strategy.
13 * [generic editor] Default Code folding for generic editor should use IndentFoldingStrategy - Bug 520659
14 */
15 package org.eclipse.ui.internal.genericeditor.folding;
16
17 import java.util.ArrayList;
18 import java.util.HashMap;
19 import java.util.Iterator;
20 import java.util.List;
21 import java.util.Map;
22
23 import org.eclipse.core.runtime.IProgressMonitor;
24 import org.eclipse.jface.text.BadLocationException;
25 import org.eclipse.jface.text.IDocument;
26 import org.eclipse.jface.text.IRegion;
27 import org.eclipse.jface.text.Position;
28 import org.eclipse.jface.text.reconciler.DirtyRegion;
29 import org.eclipse.jface.text.reconciler.IReconcilingStrategy;
30 import org.eclipse.jface.text.reconciler.IReconcilingStrategyExtension;
31 import org.eclipse.jface.text.source.Annotation;
32 import org.eclipse.jface.text.source.projection.IProjectionListener;
33 import org.eclipse.jface.text.source.projection.ProjectionAnnotation;
34 import org.eclipse.jface.text.source.projection.ProjectionAnnotationModel;
35 import org.eclipse.jface.text.source.projection.ProjectionViewer;
36 import org.eclipse.swt.graphics.FontMetrics;
37 import org.eclipse.swt.graphics.GC;
38 import org.eclipse.swt.graphics.Rectangle;
39 import org.eclipse.swt.widgets.Canvas;
40
41 /**
42 * Indent folding strategy to fold code by using indentation. The folding
43 * strategy must be associated with a viewer for it to function.
44 */
45 public class IndentFoldingStrategy implements IReconcilingStrategy, IReconcilingStrategyExtension, IProjectionListener {
46
47 private IDocument document;
48 private ProjectionViewer viewer;
49 private ProjectionAnnotationModel projectionAnnotationModel;
50 private final String lineStartsWithKeyword;
51
52 public IndentFoldingStrategy() {
53 this(null);
54 }
55
56 public IndentFoldingStrategy(String lineStartsWithKeyword) {
57 this.lineStartsWithKeyword = lineStartsWithKeyword;
58 }
59
60 /**
61 * A FoldingAnnotation is a {@link ProjectionAnnotation} it is folding and
62 * overriding the paint method (in a hacky type way) to prevent one line folding
63 * annotations to be drawn.
64 */
65 protected class FoldingAnnotation extends ProjectionAnnotation {
66 private boolean visible; /* workaround for BUG85874 */
67
68 /**
69 * Creates a new FoldingAnnotation.
70 *
71 * @param isCollapsed true if this annotation should be collapsed, false
72 * otherwise
73 */
74 public FoldingAnnotation(boolean isCollapsed) {
75 super(isCollapsed);
76 visible = false;
77 }
78
79 /**
80 * Does not paint hidden annotations. Annotations are hidden when they only span
81 * one line.
82 *
83 * @see ProjectionAnnotation#paint(org.eclipse.swt.graphics.GC,
84 * org.eclipse.swt.widgets.Canvas, org.eclipse.swt.graphics.Rectangle)
85 */
86 @Override
87 public void paint(GC gc, Canvas canvas, Rectangle rectangle) {
88 /* workaround for BUG85874 */
89 /*
90 * only need to check annotations that are expanded because hidden annotations
91 * should never have been given the chance to collapse.
92 */
93 if (!isCollapsed()) {
94 // working with rectangle, so line height
95 FontMetrics metrics = gc.getFontMetrics();
96 if (metrics != null) {
97 // do not draw annotations that only span one line and
98 // mark them as not visible
99 if ((rectangle.height / metrics.getHeight()) <= 1) {
100 visible = false;
101 return;
102 }
103 }
104 }
105 visible = true;
106 super.paint(gc, canvas, rectangle);
107 }
108
109 @Override
110 public void markCollapsed() {
111 /* workaround for BUG85874 */
112 // do not mark collapsed if annotation is not visible
113 if (visible)
114 super.markCollapsed();
115 }
116 }
117
118 /**
119 * The folding strategy must be associated with a viewer for it to function
120 *
121 * @param viewer the viewer to associate this folding strategy with
122 */
123 public void setViewer(ProjectionViewer viewer) {
124 if (this.viewer != null) {
125 this.viewer.removeProjectionListener(this);
126 }
127 this.viewer = viewer;
128 this.viewer.addProjectionListener(this);
129 this.projectionAnnotationModel = this.viewer.getProjectionAnnotationModel();
130 }
131
132 public void uninstall() {
133 setDocument(null);
134
135 if (viewer != null) {
136 viewer.removeProjectionListener(this);
137 viewer = null;
138 }
139
140 projectionDisabled();
141 }
142
143 @Override
144 public void setDocument(IDocument document) {
145 this.document = document;
146 }
147
148 @Override
149 public void projectionDisabled() {
150 projectionAnnotationModel = null;
151 }
152
153 @Override
154 public void projectionEnabled() {
155 if (viewer != null) {
156 projectionAnnotationModel = viewer.getProjectionAnnotationModel();
157 }
158 }
159
160 private class LineIndent {
161 public int line;
162 public final int indent;
163
164 public LineIndent(int line, int indent) {
165 this.line = line;
166 this.indent = indent;
167 }
168 }
169
170 @Override
171 public void reconcile(DirtyRegion dirtyRegion, IRegion subRegion) {
172 if (projectionAnnotationModel != null) {
173
174 // these are what are passed off to the annotation model to
175 // actually create and maintain the annotations
176 List<Annotation> modifications = new ArrayList<Annotation>();
177 List<FoldingAnnotation> deletions = new ArrayList<FoldingAnnotation>();
178 List<FoldingAnnotation> existing = new ArrayList<FoldingAnnotation>();
179 Map<Annotation, Position> additions = new HashMap<Annotation, Position>();
180
181 // find and mark all folding annotations with length 0 for deletion
182 markInvalidAnnotationsForDeletion(dirtyRegion, deletions, existing);
183
184 List<LineIndent> previousRegions = new ArrayList<LineIndent>();
185
186 int tabSize = 1;
187 int minimumRangeSize = 1;
188 try {
189
190 // Today we recompute annotation from the whole document each
191 // time.
192 // performance s good even with large document, but it should be
193 // better to loop for only DirtyRegion (and before/after)
194 // int offset = dirtyRegion.getOffset();
195 // int length = dirtyRegion.getLength();
196 // int startLine = 0; //document.getLineOfOffset(offset);
197 int endLine = document.getNumberOfLines() - 1; // startLine +
198 // document.getNumberOfLines(offset,
199 // length) - 1;
200
201 // sentinel, to make sure there's at least one entry
202 previousRegions.add(new LineIndent(endLine + 1, -1));
203
204 int lastLineWhichIsNotEmpty = 0;
205 int lineEmptyCount = 0;
206 Integer lastLineForKeyword = null;
207 int line = endLine;
208 for (line = endLine; line >= 0; line--) {
209 int lineOffset = document.getLineOffset(line);
210 String delim = document.getLineDelimiter(line);
211 int lineLength = document.getLineLength(line) - (delim != null ? delim.length() : 0);
212 String lineContent = document.get(lineOffset, lineLength);
213
214 LineState state = getLineState(lineContent, lastLineForKeyword);
215 switch (state) {
216 case StartWithKeyWord:
217 lineEmptyCount = 0;
218 lastLineWhichIsNotEmpty = line;
219 if (lastLineForKeyword == null) {
220 lastLineForKeyword = line;
221 }
222 break;
223 case EmptyLine:
224 lineEmptyCount++;
225 break;
226 default:
227 addAnnotationForKeyword(modifications, deletions, existing, additions,
228 line + 1 + lineEmptyCount, lastLineForKeyword);
229 lastLineForKeyword = null;
230 lineEmptyCount = 0;
231 lastLineWhichIsNotEmpty = line;
232 int indent = computeIndentLevel(lineContent, tabSize);
233 if (indent == -1) {
234 continue; // only whitespace
235 }
236
237 LineIndent previous = previousRegions.get(previousRegions.size() - 1);
238 if (previous.indent > indent) {
239 // discard all regions with larger indent
240 do {
241 previousRegions.remove(previousRegions.size() - 1);
242 previous = previousRegions.get(previousRegions.size() - 1);
243 } while (previous.indent > indent);
244
245 // new folding range
246 int endLineNumber = previous.line - 1;
247 if (endLineNumber - line >= minimumRangeSize) {
248 updateAnnotation(modifications, deletions, existing, additions, line, endLineNumber);
249 }
250 }
251 if (previous.indent == indent) {
252 previous.line = line;
253 } else { // previous.indent < indent
254 // new region with a bigger indent
255 previousRegions.add(new LineIndent(line, indent));
256 }
257 }
258 }
259 addAnnotationForKeyword(modifications, deletions, existing, additions, lastLineWhichIsNotEmpty,
260 lastLineForKeyword);
261 } catch (BadLocationException e) {
262 // should never done
263 e.printStackTrace();
264 }
265
266 // be sure projection has not been disabled
267 if (projectionAnnotationModel != null) {
268 if (existing.size() > 0) {
269 deletions.addAll(existing);
270 }
271 // send the calculated updates to the annotations to the
272 // annotation model
273 projectionAnnotationModel.modifyAnnotations(deletions.toArray(new Annotation[1]), additions,
274 modifications.toArray(new Annotation[0]));
275 }
276 }
277 }
278
279 private void addAnnotationForKeyword(List<Annotation> modifications, List<FoldingAnnotation> deletions,
280 List<FoldingAnnotation> existing, Map<Annotation, Position> additions, int startLine,
281 Integer lastLineForKeyword) throws BadLocationException {
282 if (lastLineForKeyword != null) {
283 updateAnnotation(modifications, deletions, existing, additions, startLine, lastLineForKeyword);
284 }
285 }
286
287 private enum LineState {
288 StartWithKeyWord, DontStartWithKeyWord, EmptyLine
289 }
290
291 /**
292 * Returns the line state for line which starts with a given keyword.
293 *
294 * @param lineContent line content.
295 * @param lastLineForKeyword last line for the given keyword.
296 * @return
297 */
298 private LineState getLineState(String lineContent, Integer lastLineForKeyword) {
299 if (lineStartsWithKeyword == null) {
300 // none keyword defined.
301 return LineState.DontStartWithKeyWord;
302 }
303 if (lineContent != null && lineContent.trim().startsWith(lineStartsWithKeyword)) {
304 // The line starts with the given keyword (ex: starts with "import")
305 return LineState.StartWithKeyWord;
306 }
307 if (lastLineForKeyword != null && (lineContent == null || lineContent.trim().length() == 0)) {
308 // a last line for keyword was defined, line is empty
309 return LineState.EmptyLine;
310 }
311 return LineState.DontStartWithKeyWord;
312 }
313
314 /**
315 * Compute indentation level of the given line by using the given tab size.
316 *
317 * @param line the line text.
318 * @param tabSize the tab size.
319 * @return the indentation level of the given line by using the given tab size.
320 */
321 private static int computeIndentLevel(String line, int tabSize) {
322 int i = 0;
323 int indent = 0;
324 while (i < line.length()) {
325 char ch = line.charAt(i);
326 if (ch == ' ') {
327 indent++;
328 } else if (ch == '\t') {
329 indent = indent - indent % tabSize + tabSize;
330 } else {
331 break;
332 }
333 i++;
334 }
335 if (i == line.length()) {
336 return -1; // line only consists of whitespace
337 }
338 return indent;
339 }
340
341 /**
342 * Given a {@link DirtyRegion} returns an {@link Iterator} of the already
343 * existing annotations in that region.
344 *
345 * @param dirtyRegion the {@link DirtyRegion} to check for existing annotations
346 * in
347 *
348 * @return an {@link Iterator} over the annotations in the given
349 * {@link DirtyRegion}. The iterator could have no annotations in it. Or
350 * <code>null</code> if projection has been disabled.
351 */
352 private Iterator<Annotation> getAnnotationIterator(DirtyRegion dirtyRegion) {
353 Iterator<Annotation> annoIter = null;
354 // be sure project has not been disabled
355 if (projectionAnnotationModel != null) {
356 // workaround for Platform Bug 299416
357 annoIter = projectionAnnotationModel.getAnnotationIterator(0, document.getLength(), false, false);
358 }
359 return annoIter;
360 }
361
362 /**
363 * Update annotations.
364 *
365 * @param modifications the folding annotations to update.
366 * @param deletions the folding annotations to delete.
367 * @param existing the existing folding annotations.
368 * @param additions annoation to add
369 * @param line the line index
370 * @param endLineNumber the end line number
371 * @throws BadLocationException
372 */
373 private void updateAnnotation(List<Annotation> modifications, List<FoldingAnnotation> deletions,
374 List<FoldingAnnotation> existing, Map<Annotation, Position> additions, int line, Integer endLineNumber)
375 throws BadLocationException {
376 int startOffset = document.getLineOffset(line);
377 int endOffset = document.getLineOffset(endLineNumber) + document.getLineLength(endLineNumber);
378 Position newPos = new Position(startOffset, endOffset - startOffset);
379 if (existing.size() > 0) {
380 FoldingAnnotation existingAnnotation = existing.remove(existing.size() - 1);
381 updateAnnotations(existingAnnotation, newPos, modifications, deletions);
382 } else {
383 additions.put(new FoldingAnnotation(false), newPos);
384 }
385 }
386
387 /**
388 * Update annotations.
389 *
390 * @param existingAnnotation the existing annotations that need to be updated
391 * based on the given dirtied IndexRegion
392 * @param newPos the new position that caused the annotations need
393 * for updating and null otherwise.
394 * @param modifications the list of annotations to be modified
395 * @param deletions the list of annotations to be deleted
396 */
397 protected void updateAnnotations(Annotation existingAnnotation, Position newPos, List<Annotation> modifications,
398 List<FoldingAnnotation> deletions) {
399 if (existingAnnotation instanceof FoldingAnnotation) {
400 FoldingAnnotation foldingAnnotation = (FoldingAnnotation) existingAnnotation;
401
402 // if a new position can be calculated then update the position of
403 // the annotation,
404 // else the annotation needs to be deleted
405 if (newPos != null && newPos.length > 0 && projectionAnnotationModel != null) {
406 Position oldPos = projectionAnnotationModel.getPosition(foldingAnnotation);
407 // only update the position if we have to
408 if (!newPos.equals(oldPos)) {
409 oldPos.setOffset(newPos.offset);
410 oldPos.setLength(newPos.length);
411 modifications.add(foldingAnnotation);
412 }
413 } else {
414 deletions.add(foldingAnnotation);
415 }
416 }
417 }
418
419 /**
420 * <p>
421 * Searches the given {@link DirtyRegion} for annotations that now have a length
422 * of 0. This is caused when something that was being folded has been deleted.
423 * These {@link FoldingAnnotation}s are then added to the {@link List} of
424 * {@link FoldingAnnotation}s to be deleted
425 * </p>
426 *
427 * @param dirtyRegion find the now invalid {@link FoldingAnnotation}s in this
428 * {@link DirtyRegion}
429 * @param deletions the current list of {@link FoldingAnnotation}s marked for
430 * deletion that the newly found invalid
431 * {@link FoldingAnnotation}s will be added to
432 */
433 protected void markInvalidAnnotationsForDeletion(DirtyRegion dirtyRegion, List<FoldingAnnotation> deletions,
434 List<FoldingAnnotation> existing) {
435 Iterator<Annotation> iter = getAnnotationIterator(dirtyRegion);
436 if (iter != null) {
437 while (iter.hasNext()) {
438 Annotation anno = iter.next();
439 if (anno instanceof FoldingAnnotation) {
440 FoldingAnnotation folding = (FoldingAnnotation) anno;
441 Position pos = projectionAnnotationModel.getPosition(anno);
442 if (pos.length == 0) {
443 deletions.add(folding);
444 } else {
445 existing.add(folding);
446 }
447 }
448 }
449 }
450 }
451
452 @Override
453 public void reconcile(IRegion partition) {
454 // not used, we use:
455 // reconcile(DirtyRegion dirtyRegion, IRegion subRegion)
456 }
457
458 @Override
459 public void setProgressMonitor(IProgressMonitor monitor) {
460 // Do nothing
461 }
462
463 @Override
464 public void initialReconcile() {
465 reconcile(new DirtyRegion(0, document.getLength(), DirtyRegion.INSERT, document.get()), null);
466 }
467467 }
1313 package org.eclipse.ui.internal.genericeditor.markers;
1414
1515 import java.util.ArrayList;
16 import java.util.Collections;
1617 import java.util.List;
1718
1819 import org.eclipse.core.resources.IMarker;
3738 if (!(annotation instanceof MarkerAnnotation)) {
3839 return false;
3940 }
40 AnnotationPreference preference= EditorsUI.getAnnotationPreferenceLookup().getAnnotationPreference(annotation);
41 AnnotationPreference preference = EditorsUI.getAnnotationPreferenceLookup().getAnnotationPreference(annotation);
4142 if (preference == null) {
4243 return false;
4344 }
44 String key= preference.getTextPreferenceKey();
45 String key = preference.getTextPreferenceKey();
4546 if (key != null) {
4647 if (!EditorsUI.getPreferenceStore().getBoolean(key))
4748 return false;
4849 } else {
49 key= preference.getHighlightPreferenceKey();
50 key = preference.getHighlightPreferenceKey();
5051 if (key == null || !EditorsUI.getPreferenceStore().getBoolean(key))
5152 return false;
5253 }
5354 return true;
5455 }
5556
56
57 @Override
58 public String getHoverInfo(ITextViewer textViewer, IRegion hoverRegion) {
57 @Override public String getHoverInfo(ITextViewer textViewer, IRegion hoverRegion) {
5958 Object hoverInfo = getHoverInfo2(textViewer, hoverRegion);
6059 if (hoverInfo == null) {
6160 return null;
6362 return hoverInfo.toString();
6463 }
6564
66 @Override
67 public IRegion getHoverRegion(ITextViewer textViewer, int offset) {
65 @Override public IRegion getHoverRegion(ITextViewer textViewer, int offset) {
6866 if (!(textViewer instanceof ISourceViewerExtension2)) {
6967 return null;
7068 }
71 ISourceViewerExtension2 viewer = (ISourceViewerExtension2)textViewer;
69 ISourceViewerExtension2 viewer = (ISourceViewerExtension2) textViewer;
7270 List<MarkerAnnotation> annotations = findMarkerAnnotations(viewer, new Region(offset, 0));
7371 if (annotations.isEmpty()) {
7472 return null;
8583 return new Region(highestOffsetStart, Math.max(0, lowestOffsetEnd - highestOffsetStart));
8684 }
8785
88 @Override
89 public List<IMarker> getHoverInfo2(ITextViewer textViewer, IRegion hoverRegion) {
86 @Override public List<IMarker> getHoverInfo2(ITextViewer textViewer, IRegion hoverRegion) {
9087 if (!(textViewer instanceof ISourceViewerExtension2)) {
9188 return null;
9289 }
93 List<MarkerAnnotation> annotations = findMarkerAnnotations((ISourceViewerExtension2)textViewer, hoverRegion);
90 List<MarkerAnnotation> annotations = findMarkerAnnotations((ISourceViewerExtension2) textViewer, hoverRegion);
9491 if (annotations.isEmpty()) {
9592 return null;
9693 }
10097 }
10198 return markers;
10299 }
103
100
104101 private static List<MarkerAnnotation> findMarkerAnnotations(ISourceViewerExtension2 viewer, IRegion region) {
105102 List<MarkerAnnotation> res = new ArrayList<>();
106103 IAnnotationModel annotationModel = viewer.getVisualAnnotationModel();
104 if (annotationModel == null) {
105 return Collections.emptyList();
106 }
107107 annotationModel.getAnnotationIterator().forEachRemaining(annotation -> {
108108 if (isIncluded(annotation)) {
109109 Position position = annotationModel.getPosition(annotation);
110110 if (region.getOffset() >= position.getOffset() && region.getOffset() + region.getLength() <= position.getOffset() + position.getLength()) {
111 res.add((MarkerAnnotation)annotation);
111 res.add((MarkerAnnotation) annotation);
112112 }
113113 }
114114 });
115115 return res;
116116 }
117117
118 @Override
119 public IInformationControlCreator getHoverControlCreator() {
118 @Override public IInformationControlCreator getHoverControlCreator() {
120119 return new MarkerHoverControlCreator();
121120 }
122121
0 /**
1 * Copyright (c) 2018 Angelo ZERR.
2 * All rights reserved. This program and the accompanying materials
3 * are made available under the terms of the Eclipse Public License v2.0
4 * which accompanies this distribution, and is available at
5 * http://www.eclipse.org/legal/epl-v20.html
6 *
7 * Contributors:
8 * Angelo Zerr <angelo.zerr@gmail.com> - Bug 538111 - [generic editor] Extension point for ICharacterPairMatcher
9 */
10 package org.eclipse.ui.internal.genericeditor.preferences;
11
12 import org.eclipse.core.runtime.preferences.AbstractPreferenceInitializer;
13 import org.eclipse.jface.preference.IPreferenceStore;
14 import org.eclipse.jface.preference.PreferenceConverter;
15 import org.eclipse.jface.resource.ColorRegistry;
16 import org.eclipse.swt.graphics.RGB;
17 import org.eclipse.ui.PlatformUI;
18
19 /**
20 * Preference initializer for Generic Editor plug-in.
21 *
22 * @since 1.2
23 */
24 public class GenericEditorPluginPreferenceInitializer extends AbstractPreferenceInitializer {
25
26 @Override
27 public void initializeDefaultPreferences() {
28 IPreferenceStore store = GenericEditorPreferenceConstants.getPreferenceStore();
29 GenericEditorPreferenceConstants.initializeDefaultValues(store);
30 }
31
32 public static void setThemeBasedPreferences(IPreferenceStore store, boolean fireEvent) {
33 ColorRegistry registry = null;
34 if (PlatformUI.isWorkbenchRunning())
35 registry = PlatformUI.getWorkbench().getThemeManager().getCurrentTheme().getColorRegistry();
36
37 setDefault(store, GenericEditorPreferenceConstants.EDITOR_MATCHING_BRACKETS_COLOR,
38 findRGB(registry, IGenericEditorThemeConstants.EDITOR_MATCHING_BRACKETS_COLOR, new RGB(127, 0, 85)),
39 fireEvent);
40
41 }
42
43 /**
44 * Sets the default value and fires a property change event if necessary.
45 *
46 * @param store the preference store
47 * @param key the preference key
48 * @param newValue the new value
49 * @param fireEvent <code>false</code> if no event should be fired
50 * @since 1.2
51 */
52 private static void setDefault(IPreferenceStore store, String key, RGB newValue, boolean fireEvent) {
53 if (!fireEvent) {
54 PreferenceConverter.setDefault(store, key, newValue);
55 return;
56 }
57
58 RGB oldValue = null;
59 if (store.isDefault(key))
60 oldValue = PreferenceConverter.getDefaultColor(store, key);
61
62 PreferenceConverter.setDefault(store, key, newValue);
63
64 if (oldValue != null && !oldValue.equals(newValue))
65 store.firePropertyChangeEvent(key, oldValue, newValue);
66 }
67
68 /**
69 * Returns the RGB for the given key in the given color registry.
70 *
71 * @param registry the color registry
72 * @param key the key for the constant in the registry
73 * @param defaultRGB the default RGB if no entry is found
74 * @return RGB the RGB
75 * @since 1.2
76 */
77 private static RGB findRGB(ColorRegistry registry, String key, RGB defaultRGB) {
78 if (registry == null)
79 return defaultRGB;
80
81 RGB rgb = registry.getRGB(key);
82 if (rgb != null)
83 return rgb;
84
85 return defaultRGB;
86 }
87
88 }
0 /**
1 * Copyright (c) 2018 Angelo ZERR.
2 * All rights reserved. This program and the accompanying materials
3 * are made available under the terms of the Eclipse Public License v2.0
4 * which accompanies this distribution, and is available at
5 * http://www.eclipse.org/legal/epl-v20.html
6 *
7 * Contributors:
8 * Angelo Zerr <angelo.zerr@gmail.com> - Bug 538111 - [generic editor] Extension point for ICharacterPairMatcher
9 */
10 package org.eclipse.ui.internal.genericeditor.preferences;
11
12 import org.eclipse.core.runtime.preferences.AbstractPreferenceInitializer;
13 import org.eclipse.jface.preference.IPreferenceStore;
14 import org.eclipse.jface.preference.PreferenceConverter;
15 import org.eclipse.jface.resource.ColorRegistry;
16 import org.eclipse.swt.graphics.RGB;
17 import org.eclipse.ui.PlatformUI;
18
19 /**
20 * Preference initializer for Generic Editor plug-in.
21 *
22 * @since 1.2
23 */
24 public class GenericEditorPluginPreferenceInitializer extends AbstractPreferenceInitializer {
25
26 @Override
27 public void initializeDefaultPreferences() {
28 IPreferenceStore store = GenericEditorPreferenceConstants.getPreferenceStore();
29 GenericEditorPreferenceConstants.initializeDefaultValues(store);
30 }
31
32 public static void setThemeBasedPreferences(IPreferenceStore store, boolean fireEvent) {
33 ColorRegistry registry = null;
34 if (PlatformUI.isWorkbenchRunning())
35 registry = PlatformUI.getWorkbench().getThemeManager().getCurrentTheme().getColorRegistry();
36
37 setDefault(store, GenericEditorPreferenceConstants.EDITOR_MATCHING_BRACKETS_COLOR,
38 findRGB(registry, IGenericEditorThemeConstants.EDITOR_MATCHING_BRACKETS_COLOR, new RGB(127, 0, 85)),
39 fireEvent);
40
41 }
42
43 /**
44 * Sets the default value and fires a property change event if necessary.
45 *
46 * @param store the preference store
47 * @param key the preference key
48 * @param newValue the new value
49 * @param fireEvent <code>false</code> if no event should be fired
50 * @since 1.2
51 */
52 private static void setDefault(IPreferenceStore store, String key, RGB newValue, boolean fireEvent) {
53 if (!fireEvent) {
54 PreferenceConverter.setDefault(store, key, newValue);
55 return;
56 }
57
58 RGB oldValue = null;
59 if (store.isDefault(key))
60 oldValue = PreferenceConverter.getDefaultColor(store, key);
61
62 PreferenceConverter.setDefault(store, key, newValue);
63
64 if (oldValue != null && !oldValue.equals(newValue))
65 store.firePropertyChangeEvent(key, oldValue, newValue);
66 }
67
68 /**
69 * Returns the RGB for the given key in the given color registry.
70 *
71 * @param registry the color registry
72 * @param key the key for the constant in the registry
73 * @param defaultRGB the default RGB if no entry is found
74 * @return RGB the RGB
75 * @since 1.2
76 */
77 private static RGB findRGB(ColorRegistry registry, String key, RGB defaultRGB) {
78 if (registry == null)
79 return defaultRGB;
80
81 RGB rgb = registry.getRGB(key);
82 if (rgb != null)
83 return rgb;
84
85 return defaultRGB;
86 }
87
88 }
0 /**
1 * Copyright (c) 2018 Angelo ZERR.
2 * All rights reserved. This program and the accompanying materials
3 * are made available under the terms of the Eclipse Public License v2.0
4 * which accompanies this distribution, and is available at
5 * http://www.eclipse.org/legal/epl-v20.html
6 *
7 * Contributors:
8 * Angelo Zerr <angelo.zerr@gmail.com> - Bug 538111 - [generic editor] Extension point for ICharacterPairMatcher
9 */
10 package org.eclipse.ui.internal.genericeditor.preferences;
11
12 import org.eclipse.jface.preference.IPreferenceStore;
13 import org.eclipse.ui.internal.genericeditor.GenericEditorPlugin;
14
15 /**
16 * Preference constants used in the Generic Editor preference store. Clients
17 * should only read the Generic Editor preference store using these values.
18 * Clients are not allowed to modify the preference store programmatically.
19 * <p>
20 * This class it is not intended to be instantiated or subclassed by clients.
21 * </p>
22 *
23 * @since 1.2
24 *
25 * @noinstantiate This class is not intended to be instantiated by clients.
26 * @noextend This class is not intended to be subclassed by clients.
27 */
28 public class GenericEditorPreferenceConstants {
29
30 private GenericEditorPreferenceConstants() {
31
32 }
33
34 /**
35 * A named preference that controls whether bracket matching highlighting is
36 * turned on or off.
37 * <p>
38 * Value is of type <code>Boolean</code>.
39 * </p>
40 *
41 * @since 1.2
42 */
43 public final static String EDITOR_MATCHING_BRACKETS = "matchingBrackets"; //$NON-NLS-1$
44
45 /**
46 * A named preference that holds the color used to highlight matching brackets.
47 * <p>
48 * Value is of type <code>String</code>. A RGB color value encoded as a string
49 * using class <code>PreferenceConverter</code>
50 * </p>
51 *
52 * @see org.eclipse.jface.resource.StringConverter
53 * @see org.eclipse.jface.preference.PreferenceConverter
54 *
55 * @since 1.2
56 */
57 public final static String EDITOR_MATCHING_BRACKETS_COLOR = "matchingBracketsColor"; //$NON-NLS-1$
58
59 /**
60 * A named preference that controls whether bracket at caret location is
61 * highlighted or not.
62 * <p>
63 * Value is of type <code>Boolean</code>.
64 * </p>
65 *
66 * @since 1.2
67 */
68 public final static String EDITOR_HIGHLIGHT_BRACKET_AT_CARET_LOCATION = "highlightBracketAtCaretLocation"; //$NON-NLS-1$
69
70 /**
71 * A named preference that controls whether enclosing bracket matching
72 * highlighting is turned on or off.
73 * <p>
74 * Value is of type <code>Boolean</code>.
75 * </p>
76 *
77 * @since 1.2
78 */
79 public final static String EDITOR_ENCLOSING_BRACKETS = "enclosingBrackets"; //$NON-NLS-1$
80
81 /**
82 * Returns the Generic Editor preference store.
83 *
84 * @return the Generic Editor preference store
85 */
86 public static IPreferenceStore getPreferenceStore() {
87 return GenericEditorPlugin.getDefault().getPreferenceStore();
88 }
89
90 /**
91 * Initializes the given preference store with the default values.
92 *
93 * @param store the preference store to be initialized
94 *
95 * @since 1.2
96 */
97 public static void initializeDefaultValues(IPreferenceStore store) {
98 store.setDefault(GenericEditorPreferenceConstants.EDITOR_MATCHING_BRACKETS, true);
99 store.setDefault(GenericEditorPreferenceConstants.EDITOR_HIGHLIGHT_BRACKET_AT_CARET_LOCATION, false);
100 store.setDefault(GenericEditorPreferenceConstants.EDITOR_ENCLOSING_BRACKETS, false);
101 // Colors that are set by the current theme
102 GenericEditorPluginPreferenceInitializer.setThemeBasedPreferences(store, false);
103 }
104
105 }
0 /**
1 * Copyright (c) 2018 Angelo ZERR.
2 * All rights reserved. This program and the accompanying materials
3 * are made available under the terms of the Eclipse Public License v2.0
4 * which accompanies this distribution, and is available at
5 * http://www.eclipse.org/legal/epl-v20.html
6 *
7 * Contributors:
8 * Angelo Zerr <angelo.zerr@gmail.com> - Bug 538111 - [generic editor] Extension point for ICharacterPairMatcher
9 */
10 package org.eclipse.ui.internal.genericeditor.preferences;
11
12 import org.eclipse.jface.preference.IPreferenceStore;
13 import org.eclipse.ui.internal.genericeditor.GenericEditorPlugin;
14
15 /**
16 * Preference constants used in the Generic Editor preference store. Clients
17 * should only read the Generic Editor preference store using these values.
18 * Clients are not allowed to modify the preference store programmatically.
19 * <p>
20 * This class it is not intended to be instantiated or subclassed by clients.
21 * </p>
22 *
23 * @since 1.2
24 *
25 * @noinstantiate This class is not intended to be instantiated by clients.
26 * @noextend This class is not intended to be subclassed by clients.
27 */
28 public class GenericEditorPreferenceConstants {
29
30 private GenericEditorPreferenceConstants() {
31
32 }
33
34 /**
35 * A named preference that controls whether bracket matching highlighting is
36 * turned on or off.
37 * <p>
38 * Value is of type <code>Boolean</code>.
39 * </p>
40 *
41 * @since 1.2
42 */
43 public final static String EDITOR_MATCHING_BRACKETS = "matchingBrackets"; //$NON-NLS-1$
44
45 /**
46 * A named preference that holds the color used to highlight matching brackets.
47 * <p>
48 * Value is of type <code>String</code>. A RGB color value encoded as a string
49 * using class <code>PreferenceConverter</code>
50 * </p>
51 *
52 * @see org.eclipse.jface.resource.StringConverter
53 * @see org.eclipse.jface.preference.PreferenceConverter
54 *
55 * @since 1.2
56 */
57 public final static String EDITOR_MATCHING_BRACKETS_COLOR = "matchingBracketsColor"; //$NON-NLS-1$
58
59 /**
60 * A named preference that controls whether bracket at caret location is
61 * highlighted or not.
62 * <p>
63 * Value is of type <code>Boolean</code>.
64 * </p>
65 *
66 * @since 1.2
67 */
68 public final static String EDITOR_HIGHLIGHT_BRACKET_AT_CARET_LOCATION = "highlightBracketAtCaretLocation"; //$NON-NLS-1$
69
70 /**
71 * A named preference that controls whether enclosing bracket matching
72 * highlighting is turned on or off.
73 * <p>
74 * Value is of type <code>Boolean</code>.
75 * </p>
76 *
77 * @since 1.2
78 */
79 public final static String EDITOR_ENCLOSING_BRACKETS = "enclosingBrackets"; //$NON-NLS-1$
80
81 /**
82 * Returns the Generic Editor preference store.
83 *
84 * @return the Generic Editor preference store
85 */
86 public static IPreferenceStore getPreferenceStore() {
87 return GenericEditorPlugin.getDefault().getPreferenceStore();
88 }
89
90 /**
91 * Initializes the given preference store with the default values.
92 *
93 * @param store the preference store to be initialized
94 *
95 * @since 1.2
96 */
97 public static void initializeDefaultValues(IPreferenceStore store) {
98 store.setDefault(GenericEditorPreferenceConstants.EDITOR_MATCHING_BRACKETS, true);
99 store.setDefault(GenericEditorPreferenceConstants.EDITOR_HIGHLIGHT_BRACKET_AT_CARET_LOCATION, false);
100 store.setDefault(GenericEditorPreferenceConstants.EDITOR_ENCLOSING_BRACKETS, false);
101 // Colors that are set by the current theme
102 GenericEditorPluginPreferenceInitializer.setThemeBasedPreferences(store, false);
103 }
104
105 }
0 /**
1 * Copyright (c) 2018 Angelo ZERR.
2 * All rights reserved. This program and the accompanying materials
3 * are made available under the terms of the Eclipse Public License v2.0
4 * which accompanies this distribution, and is available at
5 * http://www.eclipse.org/legal/epl-v20.html
6 *
7 * Contributors:
8 * Angelo Zerr <angelo.zerr@gmail.com> - Bug 538111 - [generic editor] Extension point for ICharacterPairMatcher
9 */
10 package org.eclipse.ui.internal.genericeditor.preferences;
11
12 import org.eclipse.ui.internal.genericeditor.GenericEditorPlugin;
13
14 /**
15 * Defines the constants used in the <code>org.eclipse.ui.themes</code>
16 * extension contributed by this plug-in.
17 *
18 * @since 1.2
19 */
20 public interface IGenericEditorThemeConstants {
21
22 String ID_PREFIX = GenericEditorPlugin.BUNDLE_ID + "."; //$NON-NLS-1$
23
24 /**
25 * Theme constant for the color used to highlight matching brackets.
26 */
27 public final String EDITOR_MATCHING_BRACKETS_COLOR = ID_PREFIX
28 + GenericEditorPreferenceConstants.EDITOR_MATCHING_BRACKETS_COLOR;
29
30 }
0 /**
1 * Copyright (c) 2018 Angelo ZERR.
2 * All rights reserved. This program and the accompanying materials
3 * are made available under the terms of the Eclipse Public License v2.0
4 * which accompanies this distribution, and is available at
5 * http://www.eclipse.org/legal/epl-v20.html
6 *
7 * Contributors:
8 * Angelo Zerr <angelo.zerr@gmail.com> - Bug 538111 - [generic editor] Extension point for ICharacterPairMatcher
9 */
10 package org.eclipse.ui.internal.genericeditor.preferences;
11
12 import org.eclipse.ui.internal.genericeditor.GenericEditorPlugin;
13
14 /**
15 * Defines the constants used in the <code>org.eclipse.ui.themes</code>
16 * extension contributed by this plug-in.
17 *
18 * @since 1.2
19 */
20 public interface IGenericEditorThemeConstants {
21
22 String ID_PREFIX = GenericEditorPlugin.BUNDLE_ID + "."; //$NON-NLS-1$
23
24 /**
25 * Theme constant for the color used to highlight matching brackets.
26 */
27 public final String EDITOR_MATCHING_BRACKETS_COLOR = ID_PREFIX
28 + GenericEditorPreferenceConstants.EDITOR_MATCHING_BRACKETS_COLOR;
29
30 }
11 Bundle-ManifestVersion: 2
22 Bundle-Name: Examples for Generic Editor
33 Bundle-SymbolicName: org.eclipse.ui.genericeditor.examples;singleton:=true
4 Bundle-Version: 1.1.200.qualifier
4 Bundle-Version: 1.1.300.qualifier
55 Bundle-Vendor: Eclipse.org
66 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
77 Require-Bundle: org.eclipse.ui.genericeditor;bundle-version="1.0.0",
1313 <parent>
1414 <artifactId>eclipse.platform.text</artifactId>
1515 <groupId>eclipse.platform.text</groupId>
16 <version>4.11.0-SNAPSHOT</version>
16 <version>4.12.0-SNAPSHOT</version>
1717 </parent>
1818 <groupId>org.eclipse.ui</groupId>
1919 <artifactId>org.eclipse.ui.genericeditor.examples</artifactId>
20 <version>1.1.200-SNAPSHOT</version>
20 <version>1.1.300-SNAPSHOT</version>
2121 <packaging>eclipse-plugin</packaging>
2222 </project>
2525
2626 public class BlueTagsPresentationReconciler extends PresentationReconciler {
2727
28 private final TextAttribute tagAttribute = new TextAttribute(Display.getCurrent().getSystemColor(SWT.COLOR_BLUE));
29 private final TextAttribute headerAttribute = new TextAttribute(Display.getCurrent().getSystemColor(SWT.COLOR_DARK_GRAY));
28 private final TextAttribute tagAttribute = new TextAttribute(Display.getCurrent().getSystemColor(SWT.COLOR_BLUE));
29 private final TextAttribute headerAttribute = new TextAttribute(Display.getCurrent().getSystemColor(SWT.COLOR_DARK_GRAY));
3030
31 public BlueTagsPresentationReconciler() {
32 RuleBasedScanner scanner= new RuleBasedScanner();
33 IRule[] rules = new IRule[2];
34 rules[1]= new SingleLineRule("<", ">", new Token(tagAttribute));
35 rules[0]= new SingleLineRule("<?", "?>", new Token(headerAttribute));
36 scanner.setRules(rules);
37 DefaultDamagerRepairer dr= new DefaultDamagerRepairer(scanner);
38 this.setDamager(dr, IDocument.DEFAULT_CONTENT_TYPE);
39 this.setRepairer(dr, IDocument.DEFAULT_CONTENT_TYPE);
40 }
31 public BlueTagsPresentationReconciler() {
32 RuleBasedScanner scanner= new RuleBasedScanner();
33 IRule[] rules = new IRule[2];
34 rules[1]= new SingleLineRule("<", ">", new Token(tagAttribute));
35 rules[0]= new SingleLineRule("<?", "?>", new Token(headerAttribute));
36 scanner.setRules(rules);
37 DefaultDamagerRepairer dr= new DefaultDamagerRepairer(scanner);
38 this.setDamager(dr, IDocument.DEFAULT_CONTENT_TYPE);
39 this.setRepairer(dr, IDocument.DEFAULT_CONTENT_TYPE);
40 }
4141 }
2222 private FoldingStrategy fStrategy;
2323
2424 public FoldingReconciler() {
25 fStrategy = new FoldingStrategy();
26 this.setReconcilingStrategy(fStrategy, IDocument.DEFAULT_CONTENT_TYPE);
27 }
25 fStrategy = new FoldingStrategy();
26 this.setReconcilingStrategy(fStrategy, IDocument.DEFAULT_CONTENT_TYPE);
27 }
2828
29 @Override
30 public void install(ITextViewer textViewer) {
31 super.install(textViewer);
32 ProjectionViewer pViewer =(ProjectionViewer)textViewer;
33 fStrategy.setProjectionViewer(pViewer);
34 }
29 @Override
30 public void install(ITextViewer textViewer) {
31 super.install(textViewer);
32 ProjectionViewer pViewer =(ProjectionViewer)textViewer;
33 fStrategy.setProjectionViewer(pViewer);
34 }
3535 }
2121 private HighlightStrategy fStrategy;
2222
2323 public HighlightReconciler() {
24 fStrategy = new HighlightStrategy();
25 this.setReconcilingStrategy(fStrategy, IDocument.DEFAULT_CONTENT_TYPE);
26 }
24 fStrategy = new HighlightStrategy();
25 this.setReconcilingStrategy(fStrategy, IDocument.DEFAULT_CONTENT_TYPE);
26 }
2727
2828 @Override
2929 public void install(ITextViewer textViewer) {
2222 import org.eclipse.jface.text.Region;
2323 public class NatureLabelHoverProvider implements ITextHover {
2424
25 public NatureLabelHoverProvider() {
26 }
25 public NatureLabelHoverProvider() {
26 }
2727
28 @Override
29 public String getHoverInfo(ITextViewer textViewer, IRegion hoverRegion) {
28 @Override
29 public String getHoverInfo(ITextViewer textViewer, IRegion hoverRegion) {
3030
31 String contents= textViewer.getDocument().get();
32 int offset= hoverRegion.getOffset();
33 int endIndex= contents.indexOf("</nature>", offset);
34 if (endIndex==-1) return "";
35 int startIndex= contents.substring(0, offset).lastIndexOf("<nature>");
36 if (startIndex==-1) return "";
37 String selection = contents.substring(startIndex+"<nature>".length(), endIndex);
31 String contents= textViewer.getDocument().get();
32 int offset= hoverRegion.getOffset();
33 int endIndex= contents.indexOf("</nature>", offset);
34 if (endIndex==-1) return "";
35 int startIndex= contents.substring(0, offset).lastIndexOf("<nature>");
36 if (startIndex==-1) return "";
37 String selection = contents.substring(startIndex+"<nature>".length(), endIndex);
3838
39 IWorkspace workspace = ResourcesPlugin.getWorkspace();
40 IProjectNatureDescriptor[] natureDescriptors= workspace.getNatureDescriptors();
41 for (int i= 0; i < natureDescriptors.length; i++) {
42 if (natureDescriptors[i].getNatureId().equals(selection))
43 return natureDescriptors[i].getLabel();
44 }
45 return null;
46 }
39 IWorkspace workspace = ResourcesPlugin.getWorkspace();
40 IProjectNatureDescriptor[] natureDescriptors= workspace.getNatureDescriptors();
41 for (int i= 0; i < natureDescriptors.length; i++) {
42 if (natureDescriptors[i].getNatureId().equals(selection))
43 return natureDescriptors[i].getLabel();
44 }
45 return null;
46 }
4747
48 @Override
49 public IRegion getHoverRegion(ITextViewer textViewer, int offset) {
50 return new Region(offset, 0);
51 }
48 @Override
49 public IRegion getHoverRegion(ITextViewer textViewer, int offset) {
50 return new Region(offset, 0);
51 }
5252 }
2929 // TODO Auto-generated constructor stub
3030 }
3131
32 @Override
33 public ICompletionProposal[] computeCompletionProposals(ITextViewer viewer, int offset) {
34 String text = viewer.getDocument().get();
35 String natureTag= "<nature>";
36 String projectReferenceTag="<project>";
37 IWorkspace workspace = ResourcesPlugin.getWorkspace();
38 int natureTagLength = natureTag.length();
32 @Override
33 public ICompletionProposal[] computeCompletionProposals(ITextViewer viewer, int offset) {
34 String text = viewer.getDocument().get();
35 String natureTag= "<nature>";
36 String projectReferenceTag="<project>";
37 IWorkspace workspace = ResourcesPlugin.getWorkspace();
38 int natureTagLength = natureTag.length();
3939 if (text.length() >= natureTagLength && offset >= natureTagLength && text.substring(offset - natureTagLength, offset).equals(natureTag)) {
40 IProjectNatureDescriptor[] natureDescriptors= workspace.getNatureDescriptors();
41 ICompletionProposal[] proposals = new ICompletionProposal[natureDescriptors.length];
42 for (int i= 0; i < natureDescriptors.length; i++) {
43 IProjectNatureDescriptor descriptor= natureDescriptors[i];
44 proposals[i] = new CompletionProposal(descriptor.getNatureId(), offset, 0, descriptor.getNatureId().length());
45 }
46 return proposals;
47 }
48 int projectReferenceTagLength = projectReferenceTag.length();
40 IProjectNatureDescriptor[] natureDescriptors= workspace.getNatureDescriptors();
41 ICompletionProposal[] proposals = new ICompletionProposal[natureDescriptors.length];
42 for (int i= 0; i < natureDescriptors.length; i++) {
43 IProjectNatureDescriptor descriptor= natureDescriptors[i];
44 proposals[i] = new CompletionProposal(descriptor.getNatureId(), offset, 0, descriptor.getNatureId().length());
45 }
46 return proposals;
47 }
48 int projectReferenceTagLength = projectReferenceTag.length();
4949 if (text.length() >= projectReferenceTagLength && offset >= projectReferenceTagLength && text.substring(offset - projectReferenceTagLength, offset).equals(projectReferenceTag)) {
50 IProject[] projects= workspace.getRoot().getProjects();
51 //TODO - filter out the project this file is in
52 ICompletionProposal[] proposals = new ICompletionProposal[projects.length];
53 for (int i= 0; i < projects.length; i++) {
54 proposals[i]=new CompletionProposal(projects[i].getName(), offset, 0, projects[i].getName().length());
55 }
56 return proposals;
57 }
58 return new ICompletionProposal[0];
59 }
50 IProject[] projects= workspace.getRoot().getProjects();
51 //TODO - filter out the project this file is in
52 ICompletionProposal[] proposals = new ICompletionProposal[projects.length];
53 for (int i= 0; i < projects.length; i++) {
54 proposals[i]=new CompletionProposal(projects[i].getName(), offset, 0, projects[i].getName().length());
55 }
56 return proposals;
57 }
58 return new ICompletionProposal[0];
59 }
6060
61 @Override
62 public IContextInformation[] computeContextInformation(ITextViewer viewer, int offset) {
63 return null;
64 }
61 @Override
62 public IContextInformation[] computeContextInformation(ITextViewer viewer, int offset) {
63 return null;
64 }
6565
66 @Override
67 public char[] getCompletionProposalAutoActivationCharacters() {
68 return null;
69 }
66 @Override
67 public char[] getCompletionProposalAutoActivationCharacters() {
68 return null;
69 }
7070
71 @Override
72 public char[] getContextInformationAutoActivationCharacters() {
73 return null;
74 }
71 @Override
72 public char[] getContextInformationAutoActivationCharacters() {
73 return null;
74 }
7575
76 @Override
77 public String getErrorMessage() {
78 return null;
79 }
76 @Override
77 public String getErrorMessage() {
78 return null;
79 }
8080
81 @Override
82 public IContextInformationValidator getContextInformationValidator() {
83 return null;
84 }
81 @Override
82 public IContextInformationValidator getContextInformationValidator() {
83 return null;
84 }
8585
8686 }
0 /**
1 * Copyright (c) 2018 Angelo ZERR.
2 * All rights reserved. This program and the accompanying materials
3 * are made available under the terms of the Eclipse Public License v2.0
4 * which accompanies this distribution, and is available at
5 * http://www.eclipse.org/legal/epl-v20.html
6 *
7 * Contributors:
8 * Angelo Zerr <angelo.zerr@gmail.com> - Bug 538111 - [generic editor] Extension point for ICharacterPairMatcher
9 */
10 package org.eclipse.ui.genericeditor.examples.dotproject;
11
12 import org.eclipse.jface.text.source.DefaultCharacterPairMatcher;
13
14 public class TagCharacterPairMatcher extends DefaultCharacterPairMatcher {
15
16 public TagCharacterPairMatcher() {
17 super(new char[] { '<', '>', '"', '"' });
18 }
19
20 }
0 /**
1 * Copyright (c) 2018 Angelo ZERR.
2 * All rights reserved. This program and the accompanying materials
3 * are made available under the terms of the Eclipse Public License v2.0
4 * which accompanies this distribution, and is available at
5 * http://www.eclipse.org/legal/epl-v20.html
6 *
7 * Contributors:
8 * Angelo Zerr <angelo.zerr@gmail.com> - Bug 538111 - [generic editor] Extension point for ICharacterPairMatcher
9 */
10 package org.eclipse.ui.genericeditor.examples.dotproject;
11
12 import org.eclipse.jface.text.source.DefaultCharacterPairMatcher;
13
14 public class TagCharacterPairMatcher extends DefaultCharacterPairMatcher {
15
16 public TagCharacterPairMatcher() {
17 super(new char[] { '<', '>', '"', '"' });
18 }
19
20 }
0 /**
1 * Copyright (c) 2017 Angelo ZERR.
0 /**
1 * Copyright (c) 2017 Angelo ZERR.
22 *
3 * This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License 2.0
5 * which accompanies this distribution, and is available at
3 * This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License 2.0
5 * which accompanies this distribution, and is available at
66 * https://www.eclipse.org/legal/epl-2.0/
77 *
8 * SPDX-License-Identifier: EPL-2.0
9 *
10 * Contributors:
11 * Angelo Zerr <angelo.zerr@gmail.com> - [CodeMining] Provide extension point for CodeMining - Bug 528419
12 */
13 package org.eclipse.ui.genericeditor.examples.dotproject.codemining;
14
15 import java.util.concurrent.CompletableFuture;
16
17 import org.eclipse.core.resources.IProject;
18 import org.eclipse.core.resources.ResourcesPlugin;
19 import org.eclipse.core.runtime.IProgressMonitor;
20 import org.eclipse.jface.text.BadLocationException;
21 import org.eclipse.jface.text.IDocument;
22 import org.eclipse.jface.text.ITextViewer;
23 import org.eclipse.jface.text.codemining.ICodeMiningProvider;
24 import org.eclipse.jface.text.codemining.LineHeaderCodeMining;
25
26 /**
27 * Project reference mining.
28 */
29 public class ProjectReferenceCodeMining extends LineHeaderCodeMining {
30
31 private final String projectName;
32
33 public ProjectReferenceCodeMining(String projectName, int beforeLineNumber, IDocument document,
34 ICodeMiningProvider provider) throws BadLocationException {
35 super(beforeLineNumber, document, provider);
36 this.projectName = projectName;
37 }
38
39 @Override
40 protected CompletableFuture<Void> doResolve(ITextViewer viewer, IProgressMonitor monitor) {
41 return CompletableFuture.runAsync(() -> {
42 IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(projectName);
43 int refCount = project != null ? project.getReferencingProjects().length : 0;
44 super.setLabel(refCount + (refCount > 1 ? " references" : " reference"));
45 });
46 }
47
48 }
8 * SPDX-License-Identifier: EPL-2.0
9 *
10 * Contributors:
11 * Angelo Zerr <angelo.zerr@gmail.com> - [CodeMining] Provide extension point for CodeMining - Bug 528419
12 */
13 package org.eclipse.ui.genericeditor.examples.dotproject.codemining;
14
15 import java.util.concurrent.CompletableFuture;
16
17 import org.eclipse.core.resources.IProject;
18 import org.eclipse.core.resources.ResourcesPlugin;
19 import org.eclipse.core.runtime.IProgressMonitor;
20 import org.eclipse.jface.text.BadLocationException;
21 import org.eclipse.jface.text.IDocument;
22 import org.eclipse.jface.text.ITextViewer;
23 import org.eclipse.jface.text.codemining.ICodeMiningProvider;
24 import org.eclipse.jface.text.codemining.LineHeaderCodeMining;
25
26 /**
27 * Project reference mining.
28 */
29 public class ProjectReferenceCodeMining extends LineHeaderCodeMining {
30
31 private final String projectName;
32
33 public ProjectReferenceCodeMining(String projectName, int beforeLineNumber, IDocument document,
34 ICodeMiningProvider provider) throws BadLocationException {
35 super(beforeLineNumber, document, provider);
36 this.projectName = projectName;
37 }
38
39 @Override
40 protected CompletableFuture<Void> doResolve(ITextViewer viewer, IProgressMonitor monitor) {
41 return CompletableFuture.runAsync(() -> {
42 IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(projectName);
43 int refCount = project != null ? project.getReferencingProjects().length : 0;
44 super.setLabel(refCount + (refCount > 1 ? " references" : " reference"));
45 });
46 }
47
48 }
0 /**
1 * Copyright (c) 2017 Angelo ZERR.
0 /**
1 * Copyright (c) 2017 Angelo ZERR.
22 *
3 * This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License 2.0
5 * which accompanies this distribution, and is available at
3 * This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License 2.0
5 * which accompanies this distribution, and is available at
66 * https://www.eclipse.org/legal/epl-2.0/
77 *
8 * SPDX-License-Identifier: EPL-2.0
9 *
10 * Contributors:
11 * Angelo Zerr <angelo.zerr@gmail.com> - [CodeMining] Provide extension point for CodeMining - Bug 528419
12 */
13 package org.eclipse.ui.genericeditor.examples.dotproject.codemining;
14
15 import java.util.ArrayList;
16 import java.util.List;
17 import java.util.concurrent.CompletableFuture;
18
19 import org.eclipse.core.runtime.IProgressMonitor;
20 import org.eclipse.jface.text.BadLocationException;
21 import org.eclipse.jface.text.IDocument;
22 import org.eclipse.jface.text.ITextViewer;
23 import org.eclipse.jface.text.codemining.AbstractCodeMiningProvider;
24 import org.eclipse.jface.text.codemining.ICodeMining;
25
26 /**
27 * Project reference minings provider.
28 */
29 public class ProjectReferencesCodeMiningProvider extends AbstractCodeMiningProvider {
30
31 @Override
32 public CompletableFuture<List<? extends ICodeMining>> provideCodeMinings(ITextViewer viewer,
33 IProgressMonitor monitor) {
34 return CompletableFuture.supplyAsync(() -> {
35 IDocument document = viewer.getDocument();
36 List<ICodeMining> minings = new ArrayList<>();
37 int lineCount = document.getNumberOfLines();
38 for (int i = 0; i < lineCount; i++) {
39 // check if request was canceled.
40 monitor.isCanceled();
41 String line = getLineText(document, i).trim();
42 int startIndex = line.indexOf("<name>");
43 if (startIndex != -1) {
44 // It's the first name, we consider we are in <projectDescription></name>
45 startIndex += "<name>".length();
46 int endIndex = line.indexOf("</name>");
47 if (endIndex > startIndex) {
48 // Check if parent element is projectDescription
49 String projectName = line.substring(startIndex, endIndex);
50 if (projectName.length() > 0) {
51 try {
52 minings.add(new ProjectReferenceCodeMining(projectName, i, document, this));
53 } catch (BadLocationException e) {
54 e.printStackTrace();
55 }
56 }
57 }
58 // stop the compute of minings to avoid process other name like
59 // <buildCommand><name>
60 break;
61 }
62 }
63 return minings;
64 });
65 }
66
67 private static String getLineText(IDocument document, int line) {
68 try {
69 int lo = document.getLineOffset(line);
70 int ll = document.getLineLength(line);
71 return document.get(lo, ll);
72 } catch (Exception e) {
73 e.printStackTrace();
74 return null;
75 }
76 }
77 }
8 * SPDX-License-Identifier: EPL-2.0
9 *
10 * Contributors:
11 * Angelo Zerr <angelo.zerr@gmail.com> - [CodeMining] Provide extension point for CodeMining - Bug 528419
12 */
13 package org.eclipse.ui.genericeditor.examples.dotproject.codemining;
14
15 import java.util.ArrayList;
16 import java.util.List;
17 import java.util.concurrent.CompletableFuture;
18
19 import org.eclipse.core.runtime.IProgressMonitor;
20 import org.eclipse.jface.text.BadLocationException;
21 import org.eclipse.jface.text.IDocument;
22 import org.eclipse.jface.text.ITextViewer;
23 import org.eclipse.jface.text.codemining.AbstractCodeMiningProvider;
24 import org.eclipse.jface.text.codemining.ICodeMining;
25
26 /**
27 * Project reference minings provider.
28 */
29 public class ProjectReferencesCodeMiningProvider extends AbstractCodeMiningProvider {
30
31 @Override
32 public CompletableFuture<List<? extends ICodeMining>> provideCodeMinings(ITextViewer viewer,
33 IProgressMonitor monitor) {
34 return CompletableFuture.supplyAsync(() -> {
35 IDocument document = viewer.getDocument();
36 List<ICodeMining> minings = new ArrayList<>();
37 int lineCount = document.getNumberOfLines();
38 for (int i = 0; i < lineCount; i++) {
39 // check if request was canceled.
40 monitor.isCanceled();
41 String line = getLineText(document, i).trim();
42 int startIndex = line.indexOf("<name>");
43 if (startIndex != -1) {
44 // It's the first name, we consider we are in <projectDescription></name>
45 startIndex += "<name>".length();
46 int endIndex = line.indexOf("</name>");
47 if (endIndex > startIndex) {
48 // Check if parent element is projectDescription
49 String projectName = line.substring(startIndex, endIndex);
50 if (projectName.length() > 0) {
51 try {
52 minings.add(new ProjectReferenceCodeMining(projectName, i, document, this));
53 } catch (BadLocationException e) {
54 e.printStackTrace();
55 }
56 }
57 }
58 // stop the compute of minings to avoid process other name like
59 // <buildCommand><name>
60 break;
61 }
62 }
63 return minings;
64 });
65 }
66
67 private static String getLineText(IDocument document, int line) {
68 try {
69 int lo = document.getLineOffset(line);
70 int ll = document.getLineLength(line);
71 return document.get(lo, ll);
72 } catch (Exception e) {
73 e.printStackTrace();
74 return null;
75 }
76 }
77 }
11 Bundle-ManifestVersion: 2
22 Bundle-Name: %Plugin.name
33 Bundle-SymbolicName: org.eclipse.ui.genericeditor.tests;singleton:=true
4 Bundle-Version: 1.1.200.qualifier
4 Bundle-Version: 1.1.300.qualifier
55 Bundle-Vendor: %Plugin.providerName
66 Bundle-Localization: plugin
77 Export-Package: org.eclipse.ui.genericeditor.tests,
1313 <parent>
1414 <artifactId>tests-pom</artifactId>
1515 <groupId>eclipse.platform.text</groupId>
16 <version>4.11.0-SNAPSHOT</version>
16 <version>4.12.0-SNAPSHOT</version>
1717 <relativePath>../tests-pom/</relativePath>
1818 </parent>
1919 <groupId>org.eclipse.ui</groupId>
2020 <artifactId>org.eclipse.ui.genericeditor.tests</artifactId>
21 <version>1.1.200-SNAPSHOT</version>
21 <version>1.1.300-SNAPSHOT</version>
2222 <packaging>eclipse-test-plugin</packaging>
2323 <properties>
2424 <testSuite>${project.artifactId}</testSuite>
2222 private FoldingStrategy fStrategy;
2323
2424 public FoldingReconciler() {
25 fStrategy = new FoldingStrategy();
26 this.setReconcilingStrategy(fStrategy, IDocument.DEFAULT_CONTENT_TYPE);
27 }
25 fStrategy = new FoldingStrategy();
26 this.setReconcilingStrategy(fStrategy, IDocument.DEFAULT_CONTENT_TYPE);
27 }
2828
29 @Override
30 public void install(ITextViewer textViewer) {
31 super.install(textViewer);
32 ProjectionViewer pViewer =(ProjectionViewer)textViewer;
33 fStrategy.setProjectionViewer(pViewer);
34 }
29 @Override
30 public void install(ITextViewer textViewer) {
31 super.install(textViewer);
32 ProjectionViewer pViewer =(ProjectionViewer)textViewer;
33 fStrategy.setProjectionViewer(pViewer);
34 }
3535 }
2121 private HighlightStrategy fStrategy;
2222
2323 public HighlightReconciler() {
24 fStrategy = new HighlightStrategy();
25 this.setReconcilingStrategy(fStrategy, IDocument.DEFAULT_CONTENT_TYPE);
26 }
24 fStrategy = new HighlightStrategy();
25 this.setReconcilingStrategy(fStrategy, IDocument.DEFAULT_CONTENT_TYPE);
26 }
2727
2828 @Override
2929 public void install(ITextViewer textViewer) {
1717
1818 public class TheReconcilerFirst extends Reconciler{
1919 public TheReconcilerFirst() {
20 this.setReconcilingStrategy(new ReconcilerStrategyFirst(), IDocument.DEFAULT_CONTENT_TYPE);
20 this.setReconcilingStrategy(new ReconcilerStrategyFirst(), IDocument.DEFAULT_CONTENT_TYPE);
2121 }
2222 }
1717
1818 public class TheReconcilerSecond extends Reconciler{
1919 public TheReconcilerSecond() {
20 this.setReconcilingStrategy(new ReconcilerStrategySecond(), IDocument.DEFAULT_CONTENT_TYPE);
20 this.setReconcilingStrategy(new ReconcilerStrategySecond(), IDocument.DEFAULT_CONTENT_TYPE);
2121 }
2222 }
00 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
11 <component id="org.eclipse.ui.workbench.texteditor" version="2">
2 <resource path="META-INF/MANIFEST.MF">
3 <filter comment="Filter for bug 515570 - [api] org.eclipse.ui.editorActions should allow modifiers" id="926941240">
4 <message_arguments>
5 <message_argument value="3.12.0"/>
6 <message_argument value="3.11.300"/>
7 </message_arguments>
8 </filter>
9 </resource>
210 <resource path="src/org/eclipse/ui/texteditor/ITextEditorActionConstants.java" type="org.eclipse.ui.texteditor.ITextEditorActionConstants">
311 <filter id="571473929">
412 <message_arguments>
11 Bundle-ManifestVersion: 2
22 Bundle-Name: %pluginName
33 Bundle-SymbolicName: org.eclipse.ui.workbench.texteditor; singleton:=true
4 Bundle-Version: 3.11.300.qualifier
4 Bundle-Version: 3.12.0.qualifier
55 Bundle-Activator: org.eclipse.ui.internal.texteditor.TextEditorPlugin
66 Bundle-ActivationPolicy: lazy
77 Bundle-Vendor: %providerName
12981298 </fontValue>
12991299 <fontValue
13001300 os="macosx"
1301 value="Monaco-regular-11">
1301 value="Menlo-regular-12">
13021302 </fontValue>
13031303 </fontDefinition>
13041304 <colorDefinition
00 <?xml version="1.0" encoding="UTF-8"?>
11 <!--
2 Copyright (c) 2012, 2018 Eclipse Foundation and others.
2 Copyright (c) 2012, 2019 Eclipse Foundation and others.
33 All rights reserved. This program and the accompanying materials
44 are made available under the terms of the Eclipse Distribution License v1.0
55 which accompanies this distribution, and is available at
1313 <parent>
1414 <artifactId>eclipse.platform.text</artifactId>
1515 <groupId>eclipse.platform.text</groupId>
16 <version>4.11.0-SNAPSHOT</version>
16 <version>4.12.0-SNAPSHOT</version>
1717 </parent>
1818 <groupId>org.eclipse.ui</groupId>
1919 <artifactId>org.eclipse.ui.workbench.texteditor</artifactId>
20 <version>3.11.300-SNAPSHOT</version>
20 <version>3.12.0-SNAPSHOT</version>
2121 <packaging>eclipse-plugin</packaging>
2222 </project>
161161
162162 /**
163163 * Search for possible completions in the backward direction. If there
164 * is a possible completion that begins before <code>firstPosition</code>
165 * but ends after that position, it will not be included in the results.
164 * is a possible completion that begins before <code>firstPosition</code>
165 * but ends after that position, it will not be included in the results.
166166 *
167167 * @param document the document to be scanned
168168 * @param prefix the completion prefix
169169 * @param firstPosition the caret position
170170 * @return a {@link List} of possible completions ({@link String}s)
171171 * from the caret position to the beginning of the document.
172 * The empty suggestion is not included in the results.
172 * The empty suggestion is not included in the results.
173173 * @throws BadLocationException if any error occurs
174174 */
175175 public List<String> getCompletionsBackwards(IDocument document, CharSequence prefix, int firstPosition) throws BadLocationException {
14151415 fRightDocument= document;
14161416 fRightDocument.addDocumentListener(this);
14171417 if (document instanceof IDocumentExtension4) {
1418 IDocumentExtension4 ext= (IDocumentExtension4) document;
1419 ext.addDocumentRewriteSessionListener(fSessionListener);
1420 }
1418 IDocumentExtension4 ext= (IDocumentExtension4) document;
1419 ext.addDocumentRewriteSessionListener(fSessionListener);
1420 }
14211421 initialize();
14221422 }
14231423 }
14531453 if (fRightDocument != null) {
14541454 fRightDocument.removeDocumentListener(this);
14551455 if (fRightDocument instanceof IDocumentExtension4) {
1456 IDocumentExtension4 ext= (IDocumentExtension4) fRightDocument;
1457 ext.removeDocumentRewriteSessionListener(fSessionListener);
1458 }
1456 IDocumentExtension4 ext= (IDocumentExtension4) fRightDocument;
1457 ext.removeDocumentRewriteSessionListener(fSessionListener);
1458 }
14591459 }
14601460 fRightDocument= null;
14611461 fRightEquivalent= null;
14851485 List<QuickDiffRangeDifference> differences= fDifferences; // atomic
14861486 synchronized (differences) {
14871487 copy= new ArrayList<>(differences);
1488 }
1488 }
14891489 final Iterator<QuickDiffRangeDifference> iter= copy.iterator();
14901490 return new Iterator<Annotation>() {
14911491
2424 }
2525
2626 private int hash(CharSequence seq){
27 int hash = 5381;
28 int len= seq.length();
29 for (int i= 0; i < len; i++) {
30 char ch= seq.charAt(i);
31 hash = ((hash << 5) + hash) + ch; /* hash * 33 + ch */
32 }
27 int hash = 5381;
28 int len= seq.length();
29 for (int i= 0; i < len; i++) {
30 char ch= seq.charAt(i);
31 hash = ((hash << 5) + hash) + ch; /* hash * 33 + ch */
32 }
3333
34 return hash;
35 }
34 return hash;
35 }
3636
3737 }
00 /*******************************************************************************
1 * Copyright (c) 2000, 2018 IBM Corporation and others.
1 * Copyright (c) 2000, 2019 IBM Corporation and others.
22 *
33 * This program and the accompanying materials
44 * are made available under the terms of the Eclipse Public License 2.0
18591859 return false;
18601860
18611861 return getInformationPresenter().openFocusedAnnotationHover(annotationHover, line);
1862 }
1862 }
18631863
18641864 /**
18651865 * Returns the information presenter (creates it if necessary).
29742974 private long fMouseUpDelta= 0;
29752975
29762976 private void triggerAction(String actionID, MouseEvent e) {
2977 IAction action= getAction(actionID);
2977 // ActionId can be prefixed with modifiers
2978 StringBuffer newActionId = new StringBuffer(""); //$NON-NLS-1$
2979 if ((e.stateMask & SWT.MOD1) > 0) {
2980 newActionId.append("M1+"); //$NON-NLS-1$
2981 }
2982 if ((e.stateMask & SWT.MOD2) > 0) {
2983 newActionId.append("M2+"); //$NON-NLS-1$
2984 }
2985 if ((e.stateMask & SWT.MOD3) > 0) {
2986 newActionId.append("M3+"); //$NON-NLS-1$
2987 }
2988 newActionId.append(actionID);
2989 IAction action = getAction(newActionId.toString());
2990 // If action does not exist with specified
2991 // modifiers+actionId, try to retrieve action with only
2992 // actionId
2993 if (action == null) {
2994 action = getAction(actionID);
2995 }
29782996 if (action != null) {
29792997 if (action instanceof IUpdate)
29802998 ((IUpdate) action).update();
31553173 } catch (InvocationTargetException x) {
31563174 Throwable t= x.getTargetException();
31573175 if (t instanceof CoreException) {
3158 /*
3159 /* XXX: Remove unpacking of CoreException once the following bug is
3160 * fixed: https://bugs.eclipse.org/bugs/show_bug.cgi?id=81640
3161 */
3162 CoreException e= (CoreException)t;
3163 IStatus status= e.getStatus();
3164 if (status.getException() != null)
3165 throw new PartInitException(status);
3166 throw new PartInitException(new Status(status.getSeverity(), status.getPlugin(), status.getCode(), status.getMessage(), t));
3167 }
3176 /*
3177 /* XXX: Remove unpacking of CoreException once the following bug is
3178 * fixed: https://bugs.eclipse.org/bugs/show_bug.cgi?id=81640
3179 */
3180 CoreException e= (CoreException)t;
3181 IStatus status= e.getStatus();
3182 if (status.getException() != null)
3183 throw new PartInitException(status);
3184 throw new PartInitException(new Status(status.getSeverity(), status.getPlugin(), status.getCode(), status.getMessage(), t));
3185 }
31683186 throw new PartInitException(new Status(IStatus.ERROR, TextEditorPlugin.PLUGIN_ID, IStatus.OK, EditorMessages.Editor_error_init, t));
31693187 }
31703188 }
36663684 }
36673685
36683686 /**
3669 * Tells whether the editor input should be included when adding object
3670 * contributions to this editor's context menu.
3671 * <p>
3672 * This implementation always returns <code>true</code>.
3673 * </p>
3674 *
3687 * Tells whether the editor input should be included when adding object
3688 * contributions to this editor's context menu.
3689 * <p>
3690 * This implementation always returns <code>true</code>.
3691 * </p>
3692 *
36753693 * @return <code>true</code> if the editor input should be considered
3676 * @since 3.2
3694 * @since 3.2
36773695 */
36783696 protected boolean isEditorInputIncludedInContextMenu() {
36793697 return true;
60316049 * @param newGroup the new group
60326050 */
60336051 protected final void addGroup(IMenuManager menu, String existingGroup, String newGroup) {
6034 IMenuManager subMenu= menu.findMenuUsingPath(existingGroup);
6035 if (subMenu != null)
6036 subMenu.add(new Separator(newGroup));
6037 else
6038 menu.appendToGroup(existingGroup, new Separator(newGroup));
6052 IMenuManager subMenu= menu.findMenuUsingPath(existingGroup);
6053 if (subMenu != null)
6054 subMenu.add(new Separator(newGroup));
6055 else
6056 menu.appendToGroup(existingGroup, new Separator(newGroup));
60396057 }
60406058
60416059 /**
65776595 styledText.setCaret(fNonDefaultCaret);
65786596 fNonDefaultCaretImage= fNonDefaultCaret.getImage();
65796597 } else if (fInitialCaret != styledText.getCaret())
6580 styledText.setCaret(fInitialCaret);
6598 styledText.setCaret(fInitialCaret);
65816599 }
65826600
65836601 private void disposeNonDefaultCaret() {
846846 }
847847
848848 /**
849 * Sets the preference key for go to previous navigation enablement.
850 *
851 * @param isGoToPreviousNavigationTargetKey the preference key
849 * Sets the preference key for go to previous navigation enablement.
850 *
851 * @param isGoToPreviousNavigationTargetKey the preference key
852852 * @since 3.0
853853 */
854854 public void setIsGoToPreviousNavigationTargetKey(String isGoToPreviousNavigationTargetKey) {
291291 * @since 3.2
292292 */
293293 private void addOrInsert(IContributionManager menu, IContributionItem item) {
294 String id= item.getId();
294 String id= item.getId();
295295 if (menu.find(id) == null)
296 menu.add(item);
297 else
298 menu.insertAfter(id, item);
299 }
296 menu.add(item);
297 else
298 menu.insertAfter(id, item);
299 }
300300
301301 @Override
302302 public void contributeToStatusLine(IStatusLineManager statusLineManager) {
131131 Set<Bundle> fBundleSet= new HashSet<>(length);
132132
133133 for (int i= 0; i < length; i++) {
134 IConfigurationElement configElement= getConfigurationElement(elements[i]);
134 IConfigurationElement configElement= getConfigurationElement(elements[i]);
135135 Bundle bundle= Platform.getBundle(configElement.getContributor().getName());
136136 fDescriptorMapping.put(elements[i], bundle.getSymbolicName());
137137 fBundleSet.add(bundle);
147147
148148 String requires = bundle.getHeaders().get(Constants.REQUIRE_BUNDLE);
149149 ManifestElement[] manifestElements;
150 try {
151 manifestElements = ManifestElement.parseHeader(Constants.REQUIRE_BUNDLE, requires);
152 } catch (BundleException e) {
153 String uid= getExtensionPointUniqueIdentifier(bundle);
154 String message= "ConfigurationElementSorter for '" + uid + "': getting required plug-ins for '" + bundle.getSymbolicName() + "' failed"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
155 Status status= new Status(IStatus.ERROR, TextEditorPlugin.PLUGIN_ID, IStatus.OK, message, e);
156 TextEditorPlugin.getDefault().getLog().log(status);
157 continue;
158 }
159
160 if (manifestElements == null)
161 continue;
150 try {
151 manifestElements = ManifestElement.parseHeader(Constants.REQUIRE_BUNDLE, requires);
152 } catch (BundleException e) {
153 String uid= getExtensionPointUniqueIdentifier(bundle);
154 String message= "ConfigurationElementSorter for '" + uid + "': getting required plug-ins for '" + bundle.getSymbolicName() + "' failed"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
155 Status status= new Status(IStatus.ERROR, TextEditorPlugin.PLUGIN_ID, IStatus.OK, message, e);
156 TextEditorPlugin.getDefault().getLog().log(status);
157 continue;
158 }
159
160 if (manifestElements == null)
161 continue;
162162
163163 int i= 0;
164164 while (i < manifestElements.length && !toTest.isEmpty()) {
193193 while (iter.hasNext()) {
194194 Entry<Object, String> entry= iter.next();
195195 if (bundleName.equals(entry.getValue())) {
196 IExtension extension = getConfigurationElement(entry.getKey()).getDeclaringExtension();
196 IExtension extension = getConfigurationElement(entry.getKey()).getDeclaringExtension();
197197 return extension.getExtensionPointUniqueIdentifier();
198198 }
199199 }
289289 Assert.isLegal(target != null && shell != null);
290290 fTarget= target;
291291 fShell= shell;
292 update();
292 update();
293293 }
294294
295295 /**
339339 */
340340 String TOGGLE_INSERT_MODE_ACTION= PREFIX + "toggle_insert_mode" + ACTION_POSTFIX; //$NON-NLS-1$;;
341341
342 /**
343 * Help context id for the word completion action.
344 * Value: <code>"org.eclipse.ui.hippie_completion_action_context"</code>
345 * @since 3.1
346 */
347 String HIPPIE_COMPLETION_ACTION= PREFIX + "hippie_completion" + ACTION_POSTFIX; //$NON-NLS-1$
348
349 /**
350 * Help context id for the content assist action.
351 * Value: <code>"org.eclipse.ui.content_assist_action_context"</code>
352 * @since 3.5
353 */
354 String CONTENT_ASSIST_ACTION= PREFIX + "content_assist" + ACTION_POSTFIX; //$NON-NLS-1$
355
356 /**
357 * Help context id for the content assist context information action.
358 * Value: <code>"org.eclipse.ui.content_assist_context_information_action_context"</code>
359 * @since 3.5
360 */
361 String CONTENT_ASSIST_CONTEXT_INFORMATION_ACTION= PREFIX + "content_assist_context_information" + ACTION_POSTFIX; //$NON-NLS-1$
362
363 /**
364 * Help context id for the quick assist action.
365 * Value: <code>"org.eclipse.ui.quick_assist_action_context"</code>
366 * @since 3.2
367 */
368 String QUICK_ASSIST_ACTION= PREFIX + "quick_assist" + ACTION_POSTFIX; //$NON-NLS-1$
369
370 /**
371 * Help context id for the recenter action.
372 * Value: <code>"org.eclipse.ui.recenter_action_context"</code>
373 * @since 3.3
374 */
375 String RECENTER_ACTION= PREFIX + "recenter" + ACTION_POSTFIX; //$NON-NLS-1$
376
377 /**
378 * Help context id for the show whitespace characters action.
379 * Value: <code>"org.eclipse.ui.show_whitespace_characters_action_context"</code>
380 * @since 3.3
381 */
342 /**
343 * Help context id for the word completion action.
344 * Value: <code>"org.eclipse.ui.hippie_completion_action_context"</code>
345 * @since 3.1
346 */
347 String HIPPIE_COMPLETION_ACTION= PREFIX + "hippie_completion" + ACTION_POSTFIX; //$NON-NLS-1$
348
349 /**
350 * Help context id for the content assist action.
351 * Value: <code>"org.eclipse.ui.content_assist_action_context"</code>
352 * @since 3.5
353 */
354 String CONTENT_ASSIST_ACTION= PREFIX + "content_assist" + ACTION_POSTFIX; //$NON-NLS-1$
355
356 /**
357 * Help context id for the content assist context information action.
358 * Value: <code>"org.eclipse.ui.content_assist_context_information_action_context"</code>
359 * @since 3.5
360 */
361 String CONTENT_ASSIST_CONTEXT_INFORMATION_ACTION= PREFIX + "content_assist_context_information" + ACTION_POSTFIX; //$NON-NLS-1$
362
363 /**
364 * Help context id for the quick assist action.
365 * Value: <code>"org.eclipse.ui.quick_assist_action_context"</code>
366 * @since 3.2
367 */
368 String QUICK_ASSIST_ACTION= PREFIX + "quick_assist" + ACTION_POSTFIX; //$NON-NLS-1$
369
370 /**
371 * Help context id for the recenter action.
372 * Value: <code>"org.eclipse.ui.recenter_action_context"</code>
373 * @since 3.3
374 */
375 String RECENTER_ACTION= PREFIX + "recenter" + ACTION_POSTFIX; //$NON-NLS-1$
376
377 /**
378 * Help context id for the show whitespace characters action.
379 * Value: <code>"org.eclipse.ui.show_whitespace_characters_action_context"</code>
380 * @since 3.3
381 */
382382 String SHOW_WHITESPACE_CHARACTERS_ACTION= PREFIX + "show_whitepsace_characters" + ACTION_POSTFIX; //$NON-NLS-1$
383383
384384 /**
148148 fText.setText(info);
149149 }
150150
151 /**
151 /**
152152 * Handles the property change.
153153 *
154154 * @param event the property change event object describing which property changed and how
6363 * (described in <code>ResourceAction</code> constructor), or
6464 * <code>null</code> if none
6565 * @param style one of <code>IAction.AS_PUSH_BUTTON</code>, <code>IAction.AS_CHECK_BOX</code>,
66 * and <code>IAction.AS_RADIO_BUTTON</code>.
66 * and <code>IAction.AS_RADIO_BUTTON</code>.
6767 *
6868 * @see ResourceAction#ResourceAction(ResourceBundle, String, int)
6969 * @see IAction#AS_CHECK_BOX
108108 * (described in <code>ResourceAction</code> constructor), or <code>null</code> if none
109109 * @param actionId the action id
110110 * @param style one of <code>IAction.AS_PUSH_BUTTON</code>, <code>IAction.AS_CHECK_BOX</code>,
111 * and <code>IAction.AS_RADIO_BUTTON</code>.
111 * and <code>IAction.AS_RADIO_BUTTON</code>.
112112 *
113113 * @see ResourceAction#ResourceAction(ResourceBundle, String, int)
114114 * @see IAction#AS_CHECK_BOX
182182
183183 setEnabled(false);
184184 if (getStyle() == AS_CHECK_BOX || getStyle() == AS_RADIO_BUTTON)
185 setChecked(false);
185 setChecked(false);
186186 setText(fDefaultText);
187187 setToolTipText(""); //$NON-NLS-1$
188188
190190
191191 setEnabled(fAction.isEnabled());
192192 if (fAction.getStyle() == AS_CHECK_BOX || fAction.getStyle() == AS_RADIO_BUTTON)
193 super.setChecked(fAction.isChecked());
193 super.setChecked(fAction.isChecked());
194194 setText(fAction.getText());
195195 setToolTipText(fAction.getToolTipText());
196196 fAction.addPropertyChangeListener(fListener);
506506
507507 /*
508508 * @see AbstractTextEditor#handlePreferenceStoreChanged(PropertyChangeEvent)
509 */
509 */
510510 protected void handlePreferenceStoreChanged(PropertyChangeEvent event) {
511511
512512 String p= event.getProperty();
187187
188188 @Override
189189 protected void layout(Composite composite, boolean flushCache) {
190 Rectangle area= composite.getClientArea();
191 Table table= getTable(composite);
192 int tableWidth= table.getSize().x;
193 int trim= computeTrim(area, table, tableWidth);
194 int width= Math.max(0, area.width - trim);
195
196 if (width > 1)
197 layoutTable(table, width, area, tableWidth < area.width);
198
199 if( composite.getData(RECALCULATE_LAYOUT) == null ) {
200 composite.setData(RECALCULATE_LAYOUT, Boolean.FALSE);
201 composite.layout();
202 }
190 Rectangle area= composite.getClientArea();
191 Table table= getTable(composite);
192 int tableWidth= table.getSize().x;
193 int trim= computeTrim(area, table, tableWidth);
194 int width= Math.max(0, area.width - trim);
195
196 if (width > 1)
197 layoutTable(table, width, area, tableWidth < area.width);
198
199 if( composite.getData(RECALCULATE_LAYOUT) == null ) {
200 composite.setData(RECALCULATE_LAYOUT, Boolean.FALSE);
201 composite.layout();
202 }
203203 }
204204
205205 private int computeTrim(Rectangle area, Table table, int tableWidth) {
206206 Point preferredSize= computeTableSize(table, area.width, area.height);
207 int trim;
208 if (tableWidth > 1) {
209 trim= tableWidth - table.getClientArea().width;
210 } else {
211 // initially, the table has no extend and no client area - use the border with
212 // plus some padding as educated guess
213 trim= 2 * table.getBorderWidth() + 1 ;
214 }
215 if (preferredSize.y > area.height) {
216 // Subtract the scrollbar width from the total column width
217 // if a vertical scrollbar will be required, but is not currently showing
218 // (in which case it is already subtracted above)
219 ScrollBar vBar= table.getVerticalBar();
220 if (!vBar.isVisible()) {
221 Point vBarSize= vBar.getSize();
222 trim += vBarSize.x;
223 }
224 }
207 int trim;
208 if (tableWidth > 1) {
209 trim= tableWidth - table.getClientArea().width;
210 } else {
211 // initially, the table has no extend and no client area - use the border with
212 // plus some padding as educated guess
213 trim= 2 * table.getBorderWidth() + 1 ;
214 }
215 if (preferredSize.y > area.height) {
216 // Subtract the scrollbar width from the total column width
217 // if a vertical scrollbar will be required, but is not currently showing
218 // (in which case it is already subtracted above)
219 ScrollBar vBar= table.getVerticalBar();
220 if (!vBar.isVisible()) {
221 Point vBarSize= vBar.getSize();
222 trim += vBarSize.x;
223 }
224 }
225225 return trim;
226226 }
227227
831831 layout.marginWidth= 0;
832832 parent.setLayout(layout);
833833
834 Composite innerParent= new Composite(parent, SWT.NONE);
835 GridLayout innerLayout= new GridLayout();
836 innerLayout.numColumns= 2;
837 innerLayout.marginHeight= 0;
838 innerLayout.marginWidth= 0;
839 innerParent.setLayout(innerLayout);
840 GridData gd= new GridData(GridData.FILL_BOTH);
841 gd.horizontalSpan= 2;
842 innerParent.setLayoutData(gd);
843
844 Composite tableComposite= new Composite(innerParent, SWT.NONE);
845 GridData data= new GridData(GridData.FILL_BOTH);
846 data.widthHint= 360;
847 data.heightHint= convertHeightInCharsToPixels(10);
848 tableComposite.setLayoutData(data);
849
850 ColumnLayout columnLayout= new ColumnLayout();
851 tableComposite.setLayout(columnLayout);
834 Composite innerParent= new Composite(parent, SWT.NONE);
835 GridLayout innerLayout= new GridLayout();
836 innerLayout.numColumns= 2;
837 innerLayout.marginHeight= 0;
838 innerLayout.marginWidth= 0;
839 innerParent.setLayout(innerLayout);
840 GridData gd= new GridData(GridData.FILL_BOTH);
841 gd.horizontalSpan= 2;
842 innerParent.setLayoutData(gd);
843
844 Composite tableComposite= new Composite(innerParent, SWT.NONE);
845 GridData data= new GridData(GridData.FILL_BOTH);
846 data.widthHint= 360;
847 data.heightHint= convertHeightInCharsToPixels(10);
848 tableComposite.setLayoutData(data);
849
850 ColumnLayout columnLayout= new ColumnLayout();
851 tableComposite.setLayout(columnLayout);
852852 Table table= new Table(tableComposite, SWT.CHECK | SWT.BORDER | SWT.MULTI | SWT.FULL_SELECTION | SWT.H_SCROLL | SWT.V_SCROLL);
853853
854854 table.setHeaderVisible(true);
958958 if (isShowFormatterSetting()) {
959959 fFormatButton= new Button(parent, SWT.CHECK);
960960 fFormatButton.setText(TemplatesMessages.TemplatePreferencePage_use_code_formatter);
961 GridData gd1= new GridData();
962 gd1.horizontalSpan= 2;
963 fFormatButton.setLayoutData(gd1);
964 fFormatButton.setSelection(getPreferenceStore().getBoolean(getFormatterPreferenceKey()));
961 GridData gd1= new GridData();
962 gd1.horizontalSpan= 2;
963 fFormatButton.setLayoutData(gd1);
964 fFormatButton.setSelection(getPreferenceStore().getBoolean(getFormatterPreferenceKey()));
965965 }
966966
967967 fTableViewer.setInput(fTemplateStore);
6868
6969 @Override
7070 protected Object nativeToJava(TransferData transferData) {
71 Object result= super.nativeToJava(transferData);
72 if (!(result instanceof byte[]) || !TYPE_NAME.equals(new String((byte[]) result)))
73 return null ;
71 Object result= super.nativeToJava(transferData);
72 if (!(result instanceof byte[]) || !TYPE_NAME.equals(new String((byte[]) result)))
73 return null ;
7474 return fObject ;
7575 }
7676 }
11 Bundle-ManifestVersion: 2
22 Bundle-Name: %Plugin.name
33 Bundle-SymbolicName: org.eclipse.ui.workbench.texteditor.tests
4 Bundle-Version: 3.12.200.qualifier
4 Bundle-Version: 3.12.300.qualifier
55 Bundle-Vendor: %Plugin.providerName
66 Bundle-Localization: plugin
77 Export-Package:
1313 <parent>
1414 <artifactId>tests-pom</artifactId>
1515 <groupId>eclipse.platform.text</groupId>
16 <version>4.11.0-SNAPSHOT</version>
16 <version>4.12.0-SNAPSHOT</version>
1717 <relativePath>../tests-pom/</relativePath>
1818 </parent>
1919 <groupId>org.eclipse.ui</groupId>
2020 <artifactId>org.eclipse.ui.workbench.texteditor.tests</artifactId>
21 <version>3.12.200-SNAPSHOT</version>
21 <version>3.12.300-SNAPSHOT</version>
2222 <packaging>eclipse-test-plugin</packaging>
2323 <properties>
2424 <testSuite>${project.artifactId}</testSuite>
160160 list= fEngine.getCompletionsBackwards(documents[0],
161161 "pri", documents[0].get().indexOf("println") + 1);
162162 assertEquals(list.size(), 1);
163 assertEquals(list.get(0), "nt");
163 assertEquals(list.get(0), "nt");
164164
165165 list= fEngine.getCompletionsBackwards(documents[0],
166166 "pa", 2);
191191 }
192192
193193 @Test
194 public void testSearchBackwards3() {
195 try {
196 List<String> list= fEngine.getCompletionsBackwards(documents[1],
197 "test", documents[1].getLength());
198 assertEquals("Number of backwards suggestions does not match", 2, list.size());
199 list= fEngine.getCompletionsBackwards(documents[1],
200 "tests", documents[1].getLength());
201 assertEquals("Number of backwards suggestions does not match", 1, list.size());
202
203 list= fEngine.getCompletionsBackwards(documents[1],
204 "test", documents[1].getLength() - 1);
205 assertEquals("Number of backwards suggestions does not match", 1, list.size());
206 } catch (BadLocationException e) {
207 assertTrue("Got out of document bounds", false);
208 }
209 }
194 public void testSearchBackwards3() {
195 try {
196 List<String> list= fEngine.getCompletionsBackwards(documents[1],
197 "test", documents[1].getLength());
198 assertEquals("Number of backwards suggestions does not match", 2, list.size());
199 list= fEngine.getCompletionsBackwards(documents[1],
200 "tests", documents[1].getLength());
201 assertEquals("Number of backwards suggestions does not match", 1, list.size());
202
203 list= fEngine.getCompletionsBackwards(documents[1],
204 "test", documents[1].getLength() - 1);
205 assertEquals("Number of backwards suggestions does not match", 1, list.size());
206 } catch (BadLocationException e) {
207 assertTrue("Got out of document bounds", false);
208 }
209 }
210210
211211 @Test
212212 public void testSearch() {
5353
5454 Display display= Display.getDefault();
5555
56 Event event= new Event();
57 event.type= SWT.KeyDown;
58 event.keyCode= SWT.CTRL;
59 System.out.println("* CTRL " + display.post(event));
60 event.keyCode= SWT.SHIFT;
61 System.out.println("* SHIFT " + display.post(event));
62 event.character= SWT.ESC;
63 event.keyCode= SWT.ESC;
64 System.out.println("* ESC " + display.post(event));
65
66 event.type= SWT.KeyUp;
67 System.out.println("* ESC up " + display.post(event));
68 event.character= 0;
69 event.keyCode= SWT.SHIFT;
70 System.out.println("* SHIFT up " + display.post(event));
71 event.keyCode= SWT.CTRL;
72 System.out.println("* CTRL up " + display.post(event));
73
74 runEventQueue();
75 takeScreenshot(ScreenshotTest.class, testName.getMethodName() + 2, System.out);
76
77 event.type= SWT.KeyDown;
78 event.character= SWT.ESC;
79 event.keyCode= SWT.ESC;
80 System.out.println("* ESC " + display.post(event));
81 event.type= SWT.KeyUp;
82 System.out.println("* ESC up " + display.post(event));
83
84 runEventQueue();
85 takeScreenshot(ScreenshotTest.class, testName.getMethodName() + 3, System.out);
56 Event event= new Event();
57 event.type= SWT.KeyDown;
58 event.keyCode= SWT.CTRL;
59 System.out.println("* CTRL " + display.post(event));
60 event.keyCode= SWT.SHIFT;
61 System.out.println("* SHIFT " + display.post(event));
62 event.character= SWT.ESC;
63 event.keyCode= SWT.ESC;
64 System.out.println("* ESC " + display.post(event));
65
66 event.type= SWT.KeyUp;
67 System.out.println("* ESC up " + display.post(event));
68 event.character= 0;
69 event.keyCode= SWT.SHIFT;
70 System.out.println("* SHIFT up " + display.post(event));
71 event.keyCode= SWT.CTRL;
72 System.out.println("* CTRL up " + display.post(event));
73
74 runEventQueue();
75 takeScreenshot(ScreenshotTest.class, testName.getMethodName() + 2, System.out);
76
77 event.type= SWT.KeyDown;
78 event.character= SWT.ESC;
79 event.keyCode= SWT.ESC;
80 System.out.println("* ESC " + display.post(event));
81 event.type= SWT.KeyUp;
82 System.out.println("* ESC up " + display.post(event));
83
84 runEventQueue();
85 takeScreenshot(ScreenshotTest.class, testName.getMethodName() + 3, System.out);
8686 }
8787
8888 /**
8989 * Takes a screenshot and dumps other debugging information to the given stream.
9090 *
91 * <p>
92 * Workaround for missing {@link junit.framework.TestCase#getName()} in JUnit 4:
93 * </p>
94 *
95 * <pre>
96 * &#64;Rule
97 * public TestName testName = new TestName();
98 * </pre>
91 * <p>
92 * Workaround for missing {@link junit.framework.TestCase#getName()} in JUnit 4:
93 * </p>
94 *
95 * <pre>
96 * &#64;Rule
97 * public TestName testName = new TestName();
98 * </pre>
9999 *
100100 * @param testClass test class that takes the screenshot
101101 * @param name screenshot identifier (e.g. test name)
1414 <parent>
1515 <groupId>org.eclipse</groupId>
1616 <artifactId>eclipse-platform-parent</artifactId>
17 <version>4.11.0-SNAPSHOT</version>
17 <version>4.12.0-SNAPSHOT</version>
1818 <relativePath>../eclipse-platform-parent</relativePath>
1919 </parent>
2020
2121 <groupId>eclipse.platform.text</groupId>
2222 <artifactId>eclipse.platform.text</artifactId>
23 <version>4.11.0-SNAPSHOT</version>
23 <version>4.12.0-SNAPSHOT</version>
2424 <packaging>pom</packaging>
2525
2626 <properties>
1313 <parent>
1414 <artifactId>eclipse.platform.text</artifactId>
1515 <groupId>eclipse.platform.text</groupId>
16 <version>4.11.0-SNAPSHOT</version>
16 <version>4.12.0-SNAPSHOT</version>
1717 </parent>
1818 <artifactId>tests-pom</artifactId>
19 <version>4.11.0-SNAPSHOT</version>
19 <version>4.12.0-SNAPSHOT</version>
2020 <packaging>pom</packaging>
2121 <properties>
2222 <code.ignoredWarnings>${tests.ignoredWarnings}</code.ignoredWarnings>