New upstream version 4.14
Emmanuel Bourg
4 years ago
0 | <?xml version="1.0" encoding="UTF-8"?> | |
1 | <extensions> | |
2 | <extension> | |
3 | <groupId>org.eclipse.tycho.extras</groupId> | |
4 | <artifactId>tycho-pomless</artifactId> | |
5 | <version>1.5.1</version> | |
6 | </extension> | |
7 | </extensions>⏎ |
0 | <?xml version="1.0" encoding="UTF-8"?> | |
1 | <projectDescription> | |
2 | <name>eclipse.platform.text</name> | |
3 | <comment></comment> | |
4 | <projects> | |
5 | </projects> | |
6 | <buildSpec> | |
7 | </buildSpec> | |
8 | <natures> | |
9 | </natures> | |
10 | </projectDescription> | |
0 | <?xml version="1.0" encoding="UTF-8"?> | |
1 | <projectDescription> | |
2 | <name>eclipse.platform.text</name> | |
3 | <comment></comment> | |
4 | <projects> | |
5 | </projects> | |
6 | <buildSpec> | |
7 | </buildSpec> | |
8 | <natures> | |
9 | </natures> | |
10 | </projectDescription> |
1 | 1 | Bundle-ManifestVersion: 2 |
2 | 2 | Bundle-Name: %pluginName |
3 | 3 | Bundle-SymbolicName: org.eclipse.core.filebuffers; singleton:=true |
4 | Bundle-Version: 3.6.700.qualifier | |
4 | Bundle-Version: 3.6.800.qualifier | |
5 | 5 | Bundle-Activator: org.eclipse.core.internal.filebuffers.FileBuffersPlugin |
6 | 6 | Bundle-ActivationPolicy: lazy |
7 | 7 | Bundle-Vendor: %providerName |
0 | <?xml version="1.0" encoding="UTF-8"?> | |
1 | <!-- | |
2 | Copyright (c) 2012, 2014 Eclipse Foundation and others. | |
3 | All rights reserved. This program and the accompanying materials | |
4 | are made available under the terms of the Eclipse Distribution License v1.0 | |
5 | which accompanies this distribution, and is available at | |
6 | http://www.eclipse.org/org/documents/edl-v10.php | |
7 | ||
8 | Contributors: | |
9 | Igor Fedorenko - initial implementation | |
10 | --> | |
11 | <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | |
12 | <modelVersion>4.0.0</modelVersion> | |
13 | <parent> | |
14 | <artifactId>eclipse.platform.text</artifactId> | |
15 | <groupId>eclipse.platform.text</groupId> | |
16 | <version>4.13.0-SNAPSHOT</version> | |
17 | </parent> | |
18 | <groupId>org.eclipse.core</groupId> | |
19 | <artifactId>org.eclipse.core.filebuffers</artifactId> | |
20 | <version>3.6.700-SNAPSHOT</version> | |
21 | <packaging>eclipse-plugin</packaging> | |
22 | </project> |
+1
-4
125 | 125 | |
126 | 126 | try { |
127 | 127 | commitFileBufferContent(monitor, overwrite); |
128 | } catch (CoreException x) { | |
129 | fManager.fireStateChangeFailed(this); | |
130 | throw x; | |
131 | } catch (RuntimeException x) { | |
128 | } catch (CoreException | RuntimeException x) { | |
132 | 129 | fManager.fireStateChangeFailed(this); |
133 | 130 | throw x; |
134 | 131 | } |
+1
-3
352 | 352 | if (fEncoding == null) |
353 | 353 | fEncoding= description.getCharset(); |
354 | 354 | } |
355 | } catch (CoreException e) { | |
356 | // do nothing | |
357 | } catch (IOException e) { | |
355 | } catch (CoreException | IOException e) { | |
358 | 356 | // do nothing |
359 | 357 | } |
360 | 358 |
+1
-1
31 | 31 | |
32 | 32 | /** |
33 | 33 | * This is a special {@link ExtensionsRegistry} that is |
34 | * optimized for <code>IFile<code>s.. | |
34 | * optimized for <code>IFile</code>s.. | |
35 | 35 | * |
36 | 36 | * @since 3.3 |
37 | 37 | */ |
+1
-4
314 | 314 | |
315 | 315 | try { |
316 | 316 | commitFileBufferContent(monitor, overwrite); |
317 | } catch (CoreException x) { | |
318 | fManager.fireStateChangeFailed(this); | |
319 | throw x; | |
320 | } catch (RuntimeException x) { | |
317 | } catch (CoreException | RuntimeException x) { | |
321 | 318 | fManager.fireStateChangeFailed(this); |
322 | 319 | throw x; |
323 | 320 | } |
+1
-3
275 | 275 | if (type != null) |
276 | 276 | return type.isKindOf(TEXT_CONTENT_TYPE); |
277 | 277 | } |
278 | } catch (CoreException ex) { | |
279 | // ignore: API specification tells return true if content type can't be determined | |
280 | } catch (IOException ex) { | |
278 | } catch (CoreException | IOException ex) { | |
281 | 279 | // ignore: API specification tells return true if content type can't be determined |
282 | 280 | } |
283 | 281 |
1 | 1 | Bundle-ManifestVersion: 2 |
2 | 2 | Bundle-Name: %Plugin.name |
3 | 3 | Bundle-SymbolicName: org.eclipse.core.filebuffers.tests;singleton:=true |
4 | Bundle-Version: 3.11.400.qualifier | |
4 | Bundle-Version: 3.11.500.qualifier | |
5 | 5 | Bundle-Activator: org.eclipse.core.filebuffers.tests.FileBuffersTestPlugin |
6 | 6 | Bundle-ActivationPolicy: lazy |
7 | 7 | Bundle-Vendor: %Plugin.providerName |
8 | 8 | Bundle-Localization: plugin |
9 | Export-Package: org.eclipse.core.filebuffers.tests | |
9 | Export-Package: org.eclipse.core.filebuffers.tests;x-internal:=true | |
10 | 10 | Require-Bundle: |
11 | 11 | org.eclipse.core.runtime;bundle-version="[3.5.0,4.0.0)", |
12 | 12 | org.eclipse.core.filesystem;bundle-version="[1.2.0,2.0.0)", |
13 | 13 | <parent> |
14 | 14 | <artifactId>tests-pom</artifactId> |
15 | 15 | <groupId>eclipse.platform.text</groupId> |
16 | <version>4.13.0-SNAPSHOT</version> | |
16 | <version>4.14.0-SNAPSHOT</version> | |
17 | 17 | <relativePath>../tests-pom/</relativePath> |
18 | 18 | </parent> |
19 | 19 | <groupId>org.eclipse.core</groupId> |
20 | 20 | <artifactId>org.eclipse.core.filebuffers.tests</artifactId> |
21 | <version>3.11.400-SNAPSHOT</version> | |
21 | <version>3.11.500-SNAPSHOT</version> | |
22 | 22 | <packaging>eclipse-test-plugin</packaging> |
23 | 23 | <properties> |
24 | 24 | <testSuite>${project.artifactId}</testSuite> |
+1
-1
93 | 93 | |
94 | 94 | @Override |
95 | 95 | protected boolean modifyUnderlyingFile() throws Exception { |
96 | FileTool.write(fExternalFile.getAbsolutePath(), new StringBuffer("Changed content of linked file")); | |
96 | FileTool.write(fExternalFile.getAbsolutePath(), "Changed content of linked file"); | |
97 | 97 | fExternalFile.setLastModified(1000); |
98 | 98 | IFile iFile= FileBuffers.getWorkspaceFileAtLocation(getPath()); |
99 | 99 | iFile.refreshLocal(IResource.DEPTH_INFINITE, null); |
+2
-26
16 | 16 | import java.io.File; |
17 | 17 | import java.io.FileInputStream; |
18 | 18 | import java.io.FileOutputStream; |
19 | import java.io.FileReader; | |
20 | 19 | import java.io.FileWriter; |
21 | 20 | import java.io.IOException; |
22 | 21 | import java.io.InputStream; |
23 | 22 | import java.io.OutputStream; |
24 | import java.io.Reader; | |
25 | 23 | import java.io.Writer; |
26 | 24 | import java.net.URL; |
27 | 25 | import java.util.Enumeration; |
167 | 165 | return stateLocation.toFile(); |
168 | 166 | } |
169 | 167 | |
170 | public static StringBuffer read(String fileName) throws IOException { | |
171 | return read(new FileReader(fileName)); | |
172 | } | |
173 | ||
174 | public static StringBuffer read(Reader reader) throws IOException { | |
175 | StringBuffer s= new StringBuffer(); | |
176 | try { | |
177 | char[] charBuffer= new char[8196]; | |
178 | int chars= reader.read(charBuffer); | |
179 | while (chars != -1) { | |
180 | s.append(charBuffer, 0, chars); | |
181 | chars= reader.read(charBuffer); | |
182 | } | |
183 | } finally { | |
184 | try { | |
185 | reader.close(); | |
186 | } catch (IOException e) { | |
187 | } | |
188 | } | |
189 | return s; | |
190 | } | |
191 | ||
192 | public static void write(String fileName, StringBuffer content) throws IOException { | |
168 | public static void write(String fileName, String content) throws IOException { | |
193 | 169 | try (Writer writer= new FileWriter(fileName)) { |
194 | writer.write(content.toString()); | |
170 | writer.write(content); | |
195 | 171 | } |
196 | 172 | } |
197 | 173 |
+3
-2
0 | 0 | /******************************************************************************* |
1 | * Copyright (c) 2000, 2008 IBM Corporation and others. | |
1 | * Copyright (c) 2000, 2019 IBM Corporation and others. | |
2 | 2 | * |
3 | 3 | * This program and the accompanying materials |
4 | 4 | * are made available under the terms of the Eclipse Public License 2.0 |
12 | 12 | *******************************************************************************/ |
13 | 13 | package org.eclipse.core.filebuffers.tests; |
14 | 14 | |
15 | import java.io.ByteArrayInputStream; | |
15 | 16 | import java.io.File; |
16 | 17 | import java.io.InputStream; |
17 | 18 | |
106 | 107 | private static IFile createFile(IFile file, String contents) throws CoreException { |
107 | 108 | if (contents == null) |
108 | 109 | contents= ""; |
109 | InputStream inputStream= new java.io.StringBufferInputStream(contents); | |
110 | InputStream inputStream= new ByteArrayInputStream(contents.getBytes()); | |
110 | 111 | file.create(inputStream, true, NULL_MONITOR); |
111 | 112 | return file; |
112 | 113 | } |
0 | 0 | <?xml version="1.0" encoding="UTF-8" standalone="no"?> |
1 | 1 | <component id="org.eclipse.jface.text" version="2"> |
2 | <resource path="META-INF/MANIFEST.MF"> | |
3 | <filter comment="Version wrongly bumped again in Bug 483846 - [typing] Spaces only mode: backspace key to remove many spaces " id="931135546"> | |
4 | <message_arguments> | |
5 | <message_argument value="3.16.100"/> | |
6 | <message_argument value="3.15.300"/> | |
7 | </message_arguments> | |
8 | </filter> | |
9 | </resource> | |
10 | <resource path="src/org/eclipse/jface/text/ITextViewer.java" type="org.eclipse.jface.text.ITextViewer"> | |
11 | <filter comment="Method introduction unlikely to collide with existing implementations." id="404000815"> | |
12 | <message_arguments> | |
13 | <message_argument value="org.eclipse.jface.text.ITextViewer"/> | |
14 | <message_argument value="getLastKnownSelection()"/> | |
15 | </message_arguments> | |
16 | </filter> | |
17 | </resource> | |
2 | 18 | <resource path="src/org/eclipse/jface/text/TextViewer.java" type="org.eclipse.jface.text.TextViewer"> |
3 | 19 | <filter id="572522506"> |
4 | 20 | <message_arguments> |
1 | 1 | Bundle-ManifestVersion: 2 |
2 | 2 | Bundle-Name: %pluginName |
3 | 3 | Bundle-SymbolicName: org.eclipse.jface.text |
4 | Bundle-Version: 3.15.300.qualifier | |
4 | Bundle-Version: 3.16.100.qualifier | |
5 | 5 | Bundle-Vendor: %providerName |
6 | 6 | Bundle-Localization: plugin |
7 | 7 | Export-Package: |
34 | 34 | Require-Bundle: |
35 | 35 | org.eclipse.core.runtime;bundle-version="[3.5.0,4.0.0)", |
36 | 36 | org.eclipse.text;bundle-version="[3.8.0,4.0.0)";visibility:=reexport, |
37 | org.eclipse.swt;bundle-version="[3.107.0,4.0.0)", | |
37 | org.eclipse.swt;bundle-version="[3.110.100,4.0.0)", | |
38 | 38 | org.eclipse.jface;bundle-version="[3.15.0,4.0.0)" |
39 | 39 | Bundle-RequiredExecutionEnvironment: JavaSE-1.8 |
40 | 40 | Import-Package: com.ibm.icu.text |
0 | <?xml version="1.0" encoding="UTF-8"?> | |
1 | <!-- | |
2 | Copyright (c) 2012, 2017 Eclipse Foundation and others. | |
3 | All rights reserved. This program and the accompanying materials | |
4 | are made available under the terms of the Eclipse Distribution License v1.0 | |
5 | which accompanies this distribution, and is available at | |
6 | http://www.eclipse.org/org/documents/edl-v10.php | |
7 | ||
8 | Contributors: | |
9 | Igor Fedorenko - initial implementation | |
10 | --> | |
11 | <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | |
12 | <modelVersion>4.0.0</modelVersion> | |
13 | <parent> | |
14 | <artifactId>eclipse.platform.text</artifactId> | |
15 | <groupId>eclipse.platform.text</groupId> | |
16 | <version>4.13.0-SNAPSHOT</version> | |
17 | </parent> | |
18 | <groupId>org.eclipse.jface</groupId> | |
19 | <artifactId>org.eclipse.jface.text</artifactId> | |
20 | <version>3.15.300-SNAPSHOT</version> | |
21 | <packaging>eclipse-plugin</packaging> | |
22 | </project> |
+21
-14
158 | 158 | if (position.getOffset() > -1 && position.getLength() > -1) { |
159 | 159 | try { |
160 | 160 | int startLine= document.getLineOfOffset(position.getOffset()); |
161 | int endLine= document.getLineOfOffset(position.getOffset() + position.getLength()); | |
162 | if (startLine <= line && line < endLine) { | |
163 | if (annotation.isCollapsed()) { | |
164 | int captionOffset; | |
165 | if (position instanceof IProjectionPosition) | |
166 | captionOffset= ((IProjectionPosition) position).computeCaptionOffset(document); | |
167 | else | |
168 | captionOffset= 0; | |
169 | ||
170 | int captionLine= document.getLineOfOffset(position.getOffset() + captionOffset); | |
171 | if (startLine <= captionLine && captionLine < endLine) | |
172 | return Math.abs(line - captionLine); | |
173 | } | |
174 | return line - startLine; | |
161 | if (startLine <= line) { | |
162 | int end= position.getOffset() + position.getLength(); | |
163 | // Bug 347628: this method expects that the offset after the position range is the | |
164 | // offset of the first line after this projected line range. In other words position | |
165 | // comprise the whole projected range including the last lines delimiter. If position | |
166 | // ends at document end the next offset is not the next line because there is no more content. | |
167 | int endLine= end != document.getLength() ? document.getLineOfOffset(end) : document.getNumberOfLines(); | |
168 | if (line < endLine) { | |
169 | if (annotation.isCollapsed()) { | |
170 | int captionOffset; | |
171 | if (position instanceof IProjectionPosition) | |
172 | captionOffset= ((IProjectionPosition) position).computeCaptionOffset(document); | |
173 | else | |
174 | captionOffset= 0; | |
175 | ||
176 | int captionLine= document.getLineOfOffset(position.getOffset() + captionOffset); | |
177 | if (startLine <= captionLine && captionLine < endLine) | |
178 | return Math.abs(line - captionLine); | |
179 | } | |
180 | return line - startLine; | |
181 | } | |
175 | 182 | } |
176 | 183 | } catch (BadLocationException x) { |
177 | 184 | } |
+13
-15
38 | 38 | import org.eclipse.jface.text.ITextSelection; |
39 | 39 | import org.eclipse.jface.text.ITextViewer; |
40 | 40 | import org.eclipse.jface.text.ITextViewerExtension; |
41 | import org.eclipse.jface.text.MultiStringMatcher; | |
42 | import org.eclipse.jface.text.MultiStringMatcher.Match; | |
41 | 43 | import org.eclipse.jface.text.Region; |
42 | 44 | import org.eclipse.jface.text.TextSelection; |
43 | 45 | import org.eclipse.jface.text.TextUtilities; |
243 | 245 | int visualEndColumn= computeVisualColumn(endLine, endColumn); |
244 | 246 | root= new MultiTextEdit(); |
245 | 247 | String[] delimiters= fDocument.getLegalLineDelimiters(); |
248 | MultiStringMatcher delimiterMatcher= MultiStringMatcher.create(delimiters); | |
246 | 249 | |
247 | 250 | int lastDelim= 0; |
248 | 251 | for (int line= startLine; line <= endLine; line++) { |
250 | 253 | if (lastDelim == -1) { |
251 | 254 | string= ""; //$NON-NLS-1$ |
252 | 255 | } else { |
253 | int[] index= TextUtilities.indexOf(delimiters, replacement, lastDelim); | |
254 | if (index[0] == -1) { | |
256 | Match m= delimiterMatcher.indexOf(replacement, lastDelim); | |
257 | if (m == null) { | |
255 | 258 | string= replacement.substring(lastDelim); |
256 | 259 | lastDelim= -1; |
257 | 260 | } else { |
258 | string= replacement.substring(lastDelim, index[0]); | |
259 | lastDelim= index[0] + delimiters[index[1]].length(); | |
261 | string= replacement.substring(lastDelim, m.getOffset()); | |
262 | lastDelim= m.getOffset() + m.getText().length(); | |
260 | 263 | } |
261 | 264 | } |
262 | 265 | TextEdit replace= createReplaceEdit(line, visualStartColumn, visualEndColumn, string, delete); |
265 | 268 | while (lastDelim != -1) { |
266 | 269 | // more stuff to insert |
267 | 270 | String string; |
268 | int[] index= TextUtilities.indexOf(delimiters, replacement, lastDelim); | |
269 | if (index[0] == -1) { | |
271 | Match m= delimiterMatcher.indexOf(replacement, lastDelim); | |
272 | if (m == null) { | |
270 | 273 | string= replacement.substring(lastDelim); |
271 | 274 | lastDelim= -1; |
272 | 275 | } else { |
273 | string= replacement.substring(lastDelim, index[0]); | |
274 | lastDelim= index[0] + delimiters[index[1]].length(); | |
276 | string= replacement.substring(lastDelim, m.getOffset()); | |
277 | lastDelim= m.getOffset() + m.getText().length(); | |
275 | 278 | } |
276 | 279 | endLine++; |
277 | 280 | TextEdit edit; |
378 | 381 | @Override |
379 | 382 | ISelection makeReplaceSelection(ISelection selection, String replacement) throws BadLocationException { |
380 | 383 | IBlockTextSelection bts= (IBlockTextSelection)selection; |
381 | String[] delimiters= fDocument.getLegalLineDelimiters(); | |
382 | int[] index= TextUtilities.indexOf(delimiters, replacement, 0); | |
383 | int length; | |
384 | if (index[0] == -1) | |
385 | length= replacement.length(); | |
386 | else | |
387 | length= index[0]; | |
384 | Match m= MultiStringMatcher.indexOf(replacement, 0, fDocument.getLegalLineDelimiters()); | |
385 | int length= m != null ? m.getOffset() : replacement.length(); | |
388 | 386 | |
389 | 387 | int startLine= bts.getStartLine(); |
390 | 388 | int column= bts.getStartColumn() + length; |
+1
-1
63 | 63 | * </p> |
64 | 64 | * <p> |
65 | 65 | * Current problems: |
66 | * </p> | |
66 | 67 | * <ul> |
67 | 68 | * <li>the size computation is too small</li> |
68 | 69 | * <li>focusLost event is not sent - see https://bugs.eclipse.org/bugs/show_bug.cgi?id=84532</li> |
69 | 70 | * </ul> |
70 | * </p> | |
71 | 71 | * |
72 | 72 | * @since 3.2 |
73 | 73 | */ |
+3
-3
1085 | 1085 | * <li>CONTEXT_SELECTOR |
1086 | 1086 | * <li>PROPOSAL_SELECTOR |
1087 | 1087 | * <li>CONTEXT_INFO_POPUP |
1088 | * <ul> | |
1088 | * </ul> | |
1089 | 1089 | * @param type the listener type for which to acquire |
1090 | 1090 | * @return <code>true</code> if the widget token could be acquired |
1091 | 1091 | * @since 2.0 |
1113 | 1113 | * <li>CONTEXT_SELECTOR |
1114 | 1114 | * <li>PROPOSAL_SELECTOR |
1115 | 1115 | * <li>CONTEXT_INFO_POPUP |
1116 | * <ul> | |
1116 | * </ul> | |
1117 | 1117 | * Returns whether the listener could be added successfully. A listener |
1118 | 1118 | * can not be added if the widget token could not be acquired. |
1119 | 1119 | * |
1168 | 1168 | * <li>CONTEXT_SELECTOR |
1169 | 1169 | * <li>PROPOSAL_SELECTOR |
1170 | 1170 | * <li>CONTEXT_INFO_POPUP |
1171 | * <ul> | |
1171 | * </ul> | |
1172 | 1172 | * |
1173 | 1173 | * @param type the listener type |
1174 | 1174 | * @since 2.0 |
231 | 231 | * |
232 | 232 | * @param remaining the number of lines to remain in the receiver, must be in [1, {@link #length() length}) |
233 | 233 | * @return the split off range |
234 | * @throws LineIndexOutOfBoundsException if <code>remaining</code>>= {@link #length()} or <code>remaining</code><t;= 0 | |
234 | * @throws LineIndexOutOfBoundsException if <code>remaining</code>>= {@link #length()} or <code>remaining</code><= 0 | |
235 | 235 | */ |
236 | 236 | public Range split(int remaining) throws LineIndexOutOfBoundsException { |
237 | 237 | if (!(remaining < length())) // assert before modification |
+1
-20
588 | 588 | * @since 3.3 |
589 | 589 | */ |
590 | 590 | private int fLastWidth= -1; |
591 | /** | |
592 | * The zoom level for the current painting operation. Workaround for bug 516293. | |
593 | * @since 3.12 | |
594 | */ | |
595 | private int fZoom= 100; | |
596 | 591 | |
597 | 592 | /** |
598 | 593 | * Creates a new revision painter for a vertical ruler column. |
660 | 655 | */ |
661 | 656 | public void setParentRuler(CompositeRuler parentRuler) { |
662 | 657 | fParentRuler= parentRuler; |
663 | } | |
664 | ||
665 | /** | |
666 | * Sets the zoom level for the current painting operation. Workaround for bug 516293. | |
667 | * | |
668 | * @param zoom the zoom to set | |
669 | * @since 3.12 | |
670 | */ | |
671 | public void setZoom(int zoom) { | |
672 | fZoom= zoom; | |
673 | } | |
674 | ||
675 | private int autoScaleUp(int value) { | |
676 | return value * fZoom / 100; | |
677 | 658 | } |
678 | 659 | |
679 | 660 | /** |
1072 | 1053 | int y1= fWidget.getLinePixel(range.getStartLine()); |
1073 | 1054 | int y2= fWidget.getLinePixel(range.getStartLine() + range.getNumberOfLines()); |
1074 | 1055 | |
1075 | return new Rectangle(0, autoScaleUp(y1), autoScaleUp(getWidth()), autoScaleUp(y2 - y1 - 1)); | |
1056 | return new Rectangle(0, y1, getWidth(), y2 - y1 - 1); | |
1076 | 1057 | } |
1077 | 1058 | |
1078 | 1059 | /** |
82 | 82 | private final AnnotationListener fAnnotationListener= new AnnotationListener(); |
83 | 83 | /** The shared color provider, possibly <code>null</code>. */ |
84 | 84 | private final ISharedTextColors fSharedColors; |
85 | /** | |
86 | * The zoom level for the current painting operation. Workaround for bug 516293. | |
87 | * @since 3.12 | |
88 | */ | |
89 | private int fZoom= 100; | |
90 | 85 | |
91 | 86 | /** |
92 | 87 | * Creates a new diff painter for a vertical ruler column. |
137 | 132 | */ |
138 | 133 | public void setBackground(Color background) { |
139 | 134 | fBackground= background; |
140 | } | |
141 | ||
142 | /** | |
143 | * Sets the zoom level for the current painting operation. Workaround for bug 516293. | |
144 | * | |
145 | * @param zoom the zoom to set | |
146 | * @since 3.12 | |
147 | */ | |
148 | public void setZoom(int zoom) { | |
149 | fZoom= zoom; | |
150 | } | |
151 | ||
152 | private int autoScaleUp(int value) { | |
153 | return value * fZoom / 100; | |
154 | 135 | } |
155 | 136 | |
156 | 137 | /** |
240 | 221 | // draw background color if special |
241 | 222 | if (hasSpecialColor(info)) { |
242 | 223 | gc.setBackground(getColor(info)); |
243 | gc.fillRectangle(0, autoScaleUp(y), autoScaleUp(width), autoScaleUp(lineHeight)); | |
224 | gc.fillRectangle(0, y, width, lineHeight); | |
244 | 225 | } |
245 | 226 | |
246 | 227 | /* Deletion Indicator: Simply a horizontal line */ |
248 | 229 | int delBelow= info.getRemovedLinesBelow(); |
249 | 230 | if (delBefore > 0 || delBelow > 0) { |
250 | 231 | gc.setForeground(deletionColor); |
251 | gc.setLineWidth(autoScaleUp(1)); | |
232 | gc.setLineWidth(1); | |
252 | 233 | if (delBefore > 0) |
253 | gc.drawLine(0, autoScaleUp(y), autoScaleUp(width), autoScaleUp(y)); | |
234 | gc.drawLine(0, y, width, y); | |
254 | 235 | if (delBelow > 0) |
255 | gc.drawLine(0, autoScaleUp(y + lineHeight - 1), autoScaleUp(width), autoScaleUp(y + lineHeight - 1)); | |
236 | gc.drawLine(0, y + lineHeight - 1, width, y + lineHeight - 1); | |
256 | 237 | } |
257 | 238 | } |
258 | 239 | } |
+5
-5
313 | 313 | private Anchor fAnchor= ANCHOR_BOTTOM; |
314 | 314 | |
315 | 315 | /** |
316 | * The anchor sequence used to layout the information control if the original anchor | |
317 | * can not be used because the information control would not fit in the display client area. | |
316 | * The anchor sequence used to layout the information control if the original anchor can not be | |
317 | * used because the information control would not fit in the display client area. | |
318 | 318 | * <p> |
319 | * The fallback anchor for a given anchor is the one that comes directly after the given anchor or | |
320 | * is the first one in the sequence if the given anchor is the last one in the sequence. | |
319 | * The fallback anchor for a given anchor is the one that comes directly after the given anchor | |
320 | * or is the first one in the sequence if the given anchor is the last one in the sequence. | |
321 | * </p> | |
321 | 322 | * <p> |
322 | * </p> | |
323 | 323 | * Note: This sequence is ignored if the original anchor is not contained in this sequence. |
324 | 324 | * </p> |
325 | 325 | * |
158 | 158 | } |
159 | 159 | return new IRegion[] {new Region(getOffset(), getLength())}; |
160 | 160 | } |
161 | ||
162 | /** | |
163 | * @since 3.16 | |
164 | */ | |
165 | @Override | |
166 | public String toString() { | |
167 | StringBuilder sb= new StringBuilder(); | |
168 | sb.append("BlockTextSelection [offset: ").append(getOffset()); //$NON-NLS-1$ | |
169 | sb.append(", startLine: ").append(fStartLine); //$NON-NLS-1$ | |
170 | if (fEndLine != fStartLine) { | |
171 | sb.append(", endLine: ").append(fEndLine); //$NON-NLS-1$ | |
172 | } | |
173 | sb.append(", startColumn: ").append(fStartColumn); //$NON-NLS-1$ | |
174 | if (fEndColumn != fStartColumn) { | |
175 | sb.append(", endColumn").append(fEndColumn); //$NON-NLS-1$ | |
176 | } | |
177 | if (getLength() != 0) { | |
178 | sb.append(", text: ").append(getText()); //$NON-NLS-1$ | |
179 | } | |
180 | if (getDocument() != null) { | |
181 | sb.append(", document: ").append(getDocument()); //$NON-NLS-1$ | |
182 | } | |
183 | sb.append("]"); //$NON-NLS-1$ | |
184 | return sb.toString(); | |
185 | } | |
161 | 186 | } |
0 | 0 | /******************************************************************************* |
1 | * Copyright (c) 2000, 2015 IBM Corporation and others. | |
1 | * Copyright (c) 2000, 2019 IBM Corporation and others. | |
2 | 2 | * |
3 | 3 | * This program and the accompanying materials |
4 | 4 | * are made available under the terms of the Eclipse Public License 2.0 |
250 | 250 | */ |
251 | 251 | public boolean shiftsCaret; |
252 | 252 | |
253 | ITextSelection fSelection; | |
253 | 254 | |
254 | 255 | /** |
255 | 256 | * Creates a new document command. |
+1
-1
37 | 37 | * <pre> |
38 | 38 | * return fShell.getDisplay().getActiveShell() == fShell |
39 | 39 | * </pre> |
40 | * | |
40 | * | |
41 | 41 | * Likewise, {@link IInformationControl#addFocusListener(org.eclipse.swt.events.FocusListener)} |
42 | 42 | * should install listeners for {@link SWT#Activate} and {@link SWT#Deactivate} on the shell and |
43 | 43 | * forward events to the focus listeners. Clients are encouraged to subclass |
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 | package org.eclipse.jface.text; | |
11 | ||
12 | import org.eclipse.jface.viewers.ISelectionProvider; | |
13 | ||
14 | /** | |
15 | * Extension interface for {@link org.eclipse.jface.text.ITextViewer}. Adds the ability to retrieve | |
16 | * the last known selection from outside of the UI Thread. | |
17 | * | |
18 | * @since 3.16 | |
19 | */ | |
20 | public interface ITextViewerExtension9 { | |
21 | ||
22 | ||
23 | /** | |
24 | * Returns the last known selection from a cache, without polling widget. | |
25 | * <p> | |
26 | * This may <strong>not</strong> be the current selection. Indeed, operations that change the | |
27 | * selection without sending related events may not refresh the returned value. | |
28 | * </p> | |
29 | * <p> | |
30 | * As opposed to {@link ISelectionProvider#getSelection()} that usually requires UI Thread, this | |
31 | * method can run from any thread. | |
32 | * </p> | |
33 | * | |
34 | * @return the last known selection. | |
35 | */ | |
36 | public ITextSelection getLastKnownSelection(); | |
37 | } |
0 | 0 | /******************************************************************************* |
1 | * Copyright (c) 2007, 2008 IBM Corporation and others. | |
1 | * Copyright (c) 2007, 2019 IBM Corporation and others. | |
2 | 2 | * |
3 | 3 | * This program and the accompanying materials |
4 | 4 | * are made available under the terms of the Eclipse Public License 2.0 |
12 | 12 | *******************************************************************************/ |
13 | 13 | package org.eclipse.jface.text; |
14 | 14 | |
15 | ||
16 | 15 | /** |
17 | 16 | * Auto edit strategy that converts tabs into spaces. |
18 | 17 | * <p> |
25 | 24 | public class TabsToSpacesConverter implements IAutoEditStrategy { |
26 | 25 | |
27 | 26 | private int fTabRatio; |
27 | ||
28 | private boolean fDeleteSpacesAsTab; | |
29 | ||
28 | 30 | private ILineTracker fLineTracker; |
29 | 31 | |
30 | 32 | |
31 | 33 | public void setNumberOfSpacesPerTab(int ratio) { |
32 | 34 | fTabRatio= ratio; |
35 | } | |
36 | ||
37 | /** | |
38 | * @param enabled if true, spaces deletion will be modified to match tabs behavior | |
39 | * @since 3.16 | |
40 | */ | |
41 | public void setDeleteSpacesAsTab(boolean enabled) { | |
42 | fDeleteSpacesAsTab= enabled; | |
33 | 43 | } |
34 | 44 | |
35 | 45 | public void setLineTracker(ILineTracker lineTracker) { |
54 | 64 | if (text == null) |
55 | 65 | return; |
56 | 66 | |
57 | int index= text.indexOf('\t'); | |
58 | if (index > -1) { | |
67 | if (text.isEmpty()) { | |
68 | ||
69 | replaceDeleteSpaceByDeleteTab(document, command); | |
70 | ||
71 | } else if (text.indexOf('\t') > -1) { | |
59 | 72 | |
60 | 73 | StringBuilder buffer= new StringBuilder(); |
61 | 74 | |
92 | 105 | command.text= buffer.toString(); |
93 | 106 | |
94 | 107 | } catch (BadLocationException x) { |
108 | throw new IllegalArgumentException("should never happen", x); //$NON-NLS-1$ | |
95 | 109 | } |
96 | 110 | } |
97 | 111 | } |
112 | ||
113 | private void replaceDeleteSpaceByDeleteTab(IDocument document, DocumentCommand command) { | |
114 | if (!fDeleteSpacesAsTab || fTabRatio == 0 || command.length != 1) | |
115 | return; | |
116 | ITextSelection selection= command.fSelection; | |
117 | if (selection == null || selection.getLength() != 0) | |
118 | return; | |
119 | try { | |
120 | if (document.getChar(command.offset) != ' ') | |
121 | return; | |
122 | ||
123 | IRegion line= document.getLineInformationOfOffset(command.offset); | |
124 | int offsetInLine= command.offset - line.getOffset(); | |
125 | boolean isDeleteKey= selection.getOffset() == command.offset; | |
126 | if (isDeleteKey) { | |
127 | int spacesToRemove= fTabRatio - (offsetInLine % fTabRatio) - 1; | |
128 | while (spacesToRemove-- > 0 && document.getChar(command.offset + command.length) == ' ') { | |
129 | command.length++; | |
130 | } | |
131 | } else { //backspace | |
132 | int spacesToRemove= offsetInLine % fTabRatio; | |
133 | while (spacesToRemove-- > 0 && document.getChar(command.offset - 1) == ' ') { | |
134 | command.offset--; | |
135 | command.length++; | |
136 | } | |
137 | } | |
138 | } catch (BadLocationException e) { | |
139 | throw new IllegalArgumentException("should never happen", e); //$NON-NLS-1$ | |
140 | } | |
141 | } | |
98 | 142 | } |
35 | 35 | |
36 | 36 | /** |
37 | 37 | * Text attribute for underline style. (value <code>1 << 30</code>) |
38 | * | |
38 | * | |
39 | 39 | * @since 3.1 |
40 | 40 | */ |
41 | 41 | public static final int UNDERLINE= 1 << 30; |
0 | 0 | /******************************************************************************* |
1 | * Copyright (c) 2000, 2018 IBM Corporation and others. | |
1 | * Copyright (c) 2000, 2019 IBM Corporation and others. | |
2 | 2 | * |
3 | 3 | * This program and the accompanying materials |
4 | 4 | * are made available under the terms of the Eclipse Public License 2.0 |
80 | 80 | import org.eclipse.jface.viewers.SelectionChangedEvent; |
81 | 81 | import org.eclipse.jface.viewers.Viewer; |
82 | 82 | |
83 | import org.eclipse.jface.text.MultiStringMatcher.Match; | |
83 | 84 | import org.eclipse.jface.text.hyperlink.HyperlinkManager; |
84 | 85 | import org.eclipse.jface.text.hyperlink.HyperlinkManager.DETECTION_STRATEGY; |
85 | 86 | import org.eclipse.jface.text.hyperlink.IHyperlinkDetector; |
111 | 112 | * @noextend This class is not intended to be subclassed by clients. |
112 | 113 | */ |
113 | 114 | public class TextViewer extends Viewer implements |
114 | ITextViewer, ITextViewerExtension, ITextViewerExtension2, ITextViewerExtension4, ITextViewerExtension6, ITextViewerExtension7, ITextViewerExtension8, | |
115 | ITextViewer, ITextViewerExtension, ITextViewerExtension2, ITextViewerExtension4, ITextViewerExtension6, ITextViewerExtension7, ITextViewerExtension8, ITextViewerExtension9, | |
115 | 116 | IEditingSupportRegistry, ITextOperationTarget, ITextOperationTargetExtension, |
116 | 117 | IWidgetTokenOwner, IWidgetTokenOwnerExtension, IPostSelectionProvider { |
117 | 118 | |
2232 | 2233 | |
2233 | 2234 | //---- Selection |
2234 | 2235 | |
2236 | /** | |
2237 | * Caches the selection value. Is only modified from inside UI Thread. Can be accessed from any | |
2238 | * thread. | |
2239 | */ | |
2240 | private volatile ITextSelection cachedSelection= TextSelection.emptySelection(); | |
2241 | ||
2242 | private void updateSelectionCache() { | |
2243 | cachedSelection= computeSelection(); | |
2244 | } | |
2245 | ||
2246 | @Override | |
2247 | public ITextSelection getLastKnownSelection() { | |
2248 | return cachedSelection; | |
2249 | } | |
2250 | ||
2235 | 2251 | @Override |
2236 | 2252 | public Point getSelectedRange() { |
2237 | 2253 | |
2408 | 2424 | |
2409 | 2425 | @Override |
2410 | 2426 | public ISelection getSelection() { |
2427 | final ITextSelection res= computeSelection(); | |
2428 | cachedSelection= res; | |
2429 | return res; | |
2430 | } | |
2431 | ||
2432 | private ITextSelection computeSelection() { | |
2411 | 2433 | if (fTextWidget != null && fTextWidget.getBlockSelection()) { |
2412 | 2434 | int[] ranges= fTextWidget.getSelectionRanges(); |
2413 | 2435 | int startOffset= ranges[0]; |
2572 | 2594 | * @param length the length of the newly selected range in the visible document |
2573 | 2595 | */ |
2574 | 2596 | protected void selectionChanged(int offset, int length) { |
2597 | updateSelectionCache(); | |
2575 | 2598 | queuePostSelectionChanged(true); |
2576 | 2599 | fireSelectionChanged(offset, length); |
2577 | 2600 | } |
3632 | 3655 | |
3633 | 3656 | IRegion modelRange= event2ModelRange(e); |
3634 | 3657 | fDocumentCommand.setEvent(e, modelRange); |
3658 | fDocumentCommand.fSelection= (ITextSelection) getSelection(); | |
3635 | 3659 | customizeDocumentCommand(fDocumentCommand); |
3636 | 3660 | if (!fDocumentCommand.fillEvent(e, modelRange)) { |
3637 | 3661 | |
3926 | 3950 | TextTransfer plainTextTransfer= TextTransfer.getInstance(); |
3927 | 3951 | String contents= (String) clipboard.getContents(plainTextTransfer, DND.CLIPBOARD); |
3928 | 3952 | String toInsert; |
3929 | if (TextUtilities.indexOf(fDocument.getLegalLineDelimiters(), contents, 0)[0] != -1) { | |
3953 | if (MultiStringMatcher.indexOf(contents, 0, fDocument.getLegalLineDelimiters()) != null) { | |
3930 | 3954 | // multi-line insertion |
3931 | 3955 | toInsert= contents; |
3932 | 3956 | } else { |
4302 | 4326 | |
4303 | 4327 | IRegion[] occurrences= new IRegion[endLine - startLine + 1]; |
4304 | 4328 | |
4329 | boolean allowEmptyPrefix= Arrays.stream(prefixes).anyMatch(String::isEmpty); | |
4330 | MultiStringMatcher prefixMatcher= MultiStringMatcher.create(prefixes); | |
4331 | ||
4305 | 4332 | // find all the first occurrences of prefix in the given lines |
4306 | 4333 | for (int i= 0; i < occurrences.length; i++) { |
4307 | 4334 | |
4309 | 4336 | String text= d.get(line.getOffset(), line.getLength()); |
4310 | 4337 | |
4311 | 4338 | int index= -1; |
4312 | int[] found= TextUtilities.indexOf(prefixes, text, 0); | |
4313 | if (found[0] != -1) { | |
4339 | int matchOffset= -1; | |
4340 | String matchText= ""; //$NON-NLS-1$ | |
4341 | Match m= prefixMatcher.indexOf(text, 0); | |
4342 | if (m != null) { | |
4343 | matchOffset= m.getOffset(); | |
4344 | matchText= m.getText(); | |
4345 | } else if (allowEmptyPrefix) { | |
4346 | matchOffset= 0; | |
4347 | } | |
4348 | if (matchOffset > -1) { | |
4314 | 4349 | if (ignoreWhitespace) { |
4315 | String s= d.get(line.getOffset(), found[0]); | |
4350 | String s= d.get(line.getOffset(), matchOffset); | |
4316 | 4351 | s= s.trim(); |
4317 | 4352 | if (s.isEmpty()) |
4318 | index= line.getOffset() + found[0]; | |
4319 | } else if (found[0] == 0) | |
4353 | index= line.getOffset() + matchOffset; | |
4354 | } else if (matchOffset == 0) | |
4320 | 4355 | index= line.getOffset(); |
4321 | 4356 | } |
4322 | 4357 | |
4323 | 4358 | if (index > -1) { |
4324 | 4359 | // remember where prefix is in line, so that it can be removed |
4325 | int length= prefixes[found[1]].length(); | |
4360 | int length= matchText.length(); | |
4326 | 4361 | if (length == 0 && !ignoreWhitespace && line.getLength() > 0) { |
4327 | 4362 | // found a non-empty line which cannot be shifted |
4328 | 4363 | return; |
57 | 57 | * |
58 | 58 | * <p> |
59 | 59 | * The returned label can have several values: |
60 | * </p> | |
60 | 61 | * <ul> |
61 | 62 | * <li><code>null</code> when mining is not resolved</li> |
62 | 63 | * <li><code>null</code> when mining is resolved means that mining was resolved with an error and it will not |
64 | 65 | * <li>empty when mining is resolved means that mining will not be displayed</li> |
65 | 66 | * <li>non empty when mining must be displayed</li> |
66 | 67 | * </ul> |
67 | * </p> | |
68 | 68 | * |
69 | 69 | * @return the label may be set early in the class lifecycle, or upon completion of the future |
70 | 70 | * provided by {@link #resolve(ITextViewer, IProgressMonitor)} operation. |
+1
-1
20 | 20 | |
21 | 21 | /** |
22 | 22 | * Abstract class for line content code mining. |
23 | * | |
23 | * | |
24 | 24 | * @since 3.13 |
25 | 25 | * |
26 | 26 | */ |
+1
-1
22 | 22 | |
23 | 23 | /** |
24 | 24 | * Abstract class for line header code mining. |
25 | * | |
25 | * | |
26 | 26 | * @since 3.13 |
27 | 27 | * |
28 | 28 | */ |
+20
-15
31 | 31 | import org.eclipse.swt.graphics.Image; |
32 | 32 | import org.eclipse.swt.graphics.Point; |
33 | 33 | import org.eclipse.swt.widgets.Control; |
34 | import org.eclipse.swt.widgets.Display; | |
35 | 34 | |
36 | 35 | import org.eclipse.core.runtime.ISafeRunnable; |
37 | 36 | import org.eclipse.core.runtime.SafeRunner; |
230 | 229 | } |
231 | 230 | List<ICompletionProposal> newProposals= new ArrayList<>(computedProposals); |
232 | 231 | fComputedProposals= newProposals; |
233 | Display.getDefault().asyncExec(() -> { | |
234 | if (autoInsert && !autoActivated && remaining.isEmpty() && newProposals.size() == 1 && canAutoInsert(newProposals.get(0))) { | |
235 | if (Helper.okToUse(fProposalShell)) { | |
236 | insertProposal(newProposals.get(0), (char) 0, 0, offset); | |
237 | hide(); | |
232 | Control control= fContentAssistSubjectControlAdapter.getControl(); | |
233 | if (!control.isDisposed()) { | |
234 | control.getDisplay().asyncExec(() -> { | |
235 | // Don't run anything if offset has changed while runnable was scheduled (i.e. filtering might have occurred for fast CA) | |
236 | if (offset == fInvocationOffset) { | |
237 | if (autoInsert && !autoActivated && remaining.isEmpty() && newProposals.size() == 1 && canAutoInsert(newProposals.get(0))) { | |
238 | if (Helper.okToUse(fProposalShell)) { | |
239 | insertProposal(newProposals.get(0), (char) 0, 0, offset); | |
240 | hide(); | |
241 | } | |
242 | return; | |
243 | } | |
244 | if (remaining.isEmpty() && callback != null) { | |
245 | callback.accept(newProposals); | |
246 | } else { | |
247 | setProposals(newProposals, false); | |
248 | displayProposals(); | |
249 | } | |
238 | 250 | } |
239 | return; | |
240 | } | |
241 | if (remaining.isEmpty() && callback != null) { | |
242 | callback.accept(newProposals); | |
243 | } else { | |
244 | setProposals(newProposals, false); | |
245 | displayProposals(); | |
246 | } | |
247 | }); | |
251 | }); | |
252 | } | |
248 | 253 | }); |
249 | 254 | } |
250 | 255 | displayProposals(); |
+4
-1
0 | 0 | /******************************************************************************* |
1 | * Copyright (c) 2015, 2016 IBM Corporation and others. | |
1 | * Copyright (c) 2015, 2019 IBM Corporation and others. | |
2 | 2 | * |
3 | 3 | * This program and the accompanying materials |
4 | 4 | * are made available under the terms of the Eclipse Public License 2.0 |
24 | 24 | * Provides {@link Styler} that applies bold style on the given font. |
25 | 25 | * |
26 | 26 | * @since 3.11 |
27 | * | |
28 | * @deprecated use {@link org.eclipse.jface.viewers.BoldStylerProvider} directly | |
27 | 29 | */ |
30 | @Deprecated | |
28 | 31 | public final class BoldStylerProvider { |
29 | 32 | |
30 | 33 | private Font fFont; |
+3
-0
140 | 140 | |
141 | 141 | @Override |
142 | 142 | public Object execute(ExecutionEvent event) throws ExecutionException { |
143 | if (fProposalTable.isDisposed()) { | |
144 | return null; | |
145 | } | |
143 | 146 | int itemCount= fProposalTable.getItemCount(); |
144 | 147 | int selectionIndex= fProposalTable.getSelectionIndex(); |
145 | 148 | switch (fOperationCode) { |
+44
-0
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 | package org.eclipse.jface.text.contentassist; | |
11 | ||
12 | import java.util.Arrays; | |
13 | ||
14 | import org.eclipse.jface.text.ITextViewer; | |
15 | import org.eclipse.jface.text.TextPresentation; | |
16 | ||
17 | class CompositeContextInformationValidator implements IContextInformationValidator, IContextInformationPresenter { | |
18 | ||
19 | private final IContextInformationValidator[] children; | |
20 | ||
21 | public CompositeContextInformationValidator(IContextInformationValidator[] validators) { | |
22 | this.children= validators; | |
23 | } | |
24 | ||
25 | @Override | |
26 | public void install(IContextInformation info, ITextViewer viewer, int offset) { | |
27 | Arrays.stream(children).forEach(child -> child.install(info, viewer, offset)); | |
28 | } | |
29 | ||
30 | @Override | |
31 | public boolean isContextInformationValid(int offset) { | |
32 | return Arrays.stream(children).anyMatch(child -> child.isContextInformationValid(offset)); | |
33 | } | |
34 | ||
35 | @Override | |
36 | public boolean updatePresentation(int offset, TextPresentation presentation) { | |
37 | if (children.length == 1 && children[0] instanceof IContextInformationPresenter) { | |
38 | return ((IContextInformationPresenter) children[0]).updatePresentation(offset, presentation); | |
39 | } | |
40 | return false; | |
41 | } | |
42 | ||
43 | } |
+1
-1
276 | 276 | * |
277 | 277 | * @param contentAssistant the content assistant |
278 | 278 | * @param controller the additional info controller, or <code>null</code> |
279 | * @param asynchronous <true> if this content assistant should present the proposals | |
279 | * @param asynchronous <code>true</code> if this content assistant should present the proposals | |
280 | 280 | * asynchronously, <code>false</code> otherwise |
281 | 281 | * @return the completion proposal popup |
282 | 282 | */ |
+20
-6
2113 | 2113 | if (processors == null || processors.isEmpty()) { |
2114 | 2114 | return null; |
2115 | 2115 | } |
2116 | // pick first one, arbitrary | |
2117 | IContentAssistProcessor p = processors.iterator().next(); | |
2118 | return p != null ? p.getContextInformationValidator() : null; | |
2116 | IContextInformationValidator[] validators= processors.stream() | |
2117 | .map(IContentAssistProcessor::getContextInformationValidator) | |
2118 | .filter(Objects::nonNull) | |
2119 | .toArray(IContextInformationValidator[]::new); | |
2120 | if (validators.length == 0) { | |
2121 | return null; | |
2122 | } else if (validators.length == 1) { | |
2123 | return validators[0]; | |
2124 | } | |
2125 | return new CompositeContextInformationValidator(validators); | |
2119 | 2126 | } |
2120 | 2127 | |
2121 | 2128 | /** |
2134 | 2141 | if (processors == null || processors.isEmpty()) { |
2135 | 2142 | return null; |
2136 | 2143 | } |
2137 | // pick first one, arbitrary | |
2138 | IContentAssistProcessor p = processors.iterator().next(); | |
2139 | return p != null ? p.getContextInformationValidator() : null; | |
2144 | IContextInformationValidator[] validators= processors.stream() | |
2145 | .map(IContentAssistProcessor::getContextInformationValidator) | |
2146 | .filter(Objects::nonNull) | |
2147 | .toArray(IContextInformationValidator[]::new); | |
2148 | if (validators.length == 0) { | |
2149 | return null; | |
2150 | } else if (validators.length == 1) { | |
2151 | return validators[0]; | |
2152 | } | |
2153 | return new CompositeContextInformationValidator(validators); | |
2140 | 2154 | } |
2141 | 2155 | |
2142 | 2156 | /** |
94 | 94 | |
95 | 95 | @Override |
96 | 96 | public int hashCode() { |
97 | return super.hashCode() | (fProposals == null ? 0 : fProposals.hashCode()); | |
97 | return super.hashCode() | (fProposals == null ? 0 : Arrays.hashCode(fProposals)); | |
98 | 98 | } |
99 | 99 | } |
+1
-0
104 | 104 | fQuickAssistAssistantImpl= new QuickAssistAssistantImpl(); |
105 | 105 | fQuickAssistAssistantImpl.enableAutoActivation(false); |
106 | 106 | fQuickAssistAssistantImpl.enableAutoInsert(false); |
107 | fQuickAssistAssistantImpl.setRepeatedInvocationMode(true); | |
107 | 108 | } |
108 | 109 | |
109 | 110 | @Override |
52 | 52 | * <p> |
53 | 53 | * This interface must be implemented by clients. |
54 | 54 | * </p> |
55 | * | |
55 | * | |
56 | 56 | * @since 3.0 |
57 | 57 | */ |
58 | 58 | public interface IReconcileStep { |
+63
-67
80 | 80 | private static class ReusableRegion extends Position implements IRegion {} |
81 | 81 | |
82 | 82 | /** |
83 | * Pair of an annotation and their associated position. Used inside the paint method | |
84 | * for sorting annotations based on the offset of their position. | |
83 | * Holder for an annotation, their associated position and paint layer. Used inside the paint | |
84 | * method for sorting annotations based on the offset of their position and layer. | |
85 | * | |
85 | 86 | * @since 3.0 |
86 | 87 | */ |
87 | 88 | private static class Tuple { |
88 | 89 | Annotation annotation; |
89 | 90 | Position position; |
90 | ||
91 | Tuple(Annotation annotation, Position position) { | |
91 | int layer; | |
92 | ||
93 | Tuple(Annotation annotation, Position position, int layer) { | |
92 | 94 | this.annotation= annotation; |
93 | 95 | this.position= position; |
94 | } | |
95 | } | |
96 | ||
97 | /** | |
98 | * Comparator for <code>Tuple</code>s. | |
96 | this.layer= layer; | |
97 | } | |
98 | } | |
99 | ||
100 | /** | |
101 | * Comparator for <code>Tuple</code>s to order them by layer and offset. | |
102 | * | |
99 | 103 | * @since 3.0 |
100 | 104 | */ |
101 | 105 | private static class TupleComparator implements Comparator<Tuple> { |
102 | 106 | @Override |
103 | 107 | public int compare(Tuple o1, Tuple o2) { |
108 | int cmp= Integer.compare(o1.layer, o2.layer); | |
109 | if (cmp != 0) { | |
110 | return cmp; | |
111 | } | |
104 | 112 | Position p1= o1.position; |
105 | 113 | Position p2= o2.position; |
106 | return p1.getOffset() - p2.getOffset(); | |
114 | return Integer.compare(p1.getOffset(), p2.getOffset()); | |
107 | 115 | } |
108 | 116 | } |
109 | 117 | |
724 | 732 | Rectangle r= new Rectangle(0, 0, 0, 0); |
725 | 733 | ReusableRegion range= new ReusableRegion(); |
726 | 734 | boolean isWrapActive= fCachedTextWidget.getWordWrap(); |
727 | int minLayer= Integer.MAX_VALUE, maxLayer= Integer.MIN_VALUE; | |
728 | 735 | fCachedAnnotations.clear(); |
729 | 736 | Iterator<Annotation> iter; |
730 | 737 | if (fModel instanceof IAnnotationModelExtension2) |
751 | 758 | if (fAnnotationAccessExtension != null) |
752 | 759 | lay= fAnnotationAccessExtension.getLayer(annotation); |
753 | 760 | |
754 | minLayer= Math.min(minLayer, lay); | |
755 | maxLayer= Math.max(maxLayer, lay); | |
756 | fCachedAnnotations.add(new Tuple(annotation, position)); | |
761 | fCachedAnnotations.add(new Tuple(annotation, position, lay)); | |
757 | 762 | } |
758 | 763 | Collections.sort(fCachedAnnotations, fTupleComparator); |
759 | 764 | |
760 | for (int layer= minLayer; layer <= maxLayer; layer++) { | |
761 | for (int i= 0, n= fCachedAnnotations.size(); i < n; i++) { | |
762 | Tuple tuple= fCachedAnnotations.get(i); | |
763 | Annotation annotation= tuple.annotation; | |
764 | Position position= tuple.position; | |
765 | ||
766 | int lay= IAnnotationAccessExtension.DEFAULT_LAYER; | |
767 | if (fAnnotationAccessExtension != null) | |
768 | lay= fAnnotationAccessExtension.getLayer(annotation); | |
769 | if (lay != layer) // wrong layer: skip annotation | |
770 | continue; | |
771 | ||
772 | range.setOffset(position.getOffset()); | |
773 | range.setLength(position.getLength()); | |
774 | IRegion widgetRegion= extension.modelRange2WidgetRange(range); | |
775 | if (widgetRegion == null) | |
776 | continue; | |
777 | ||
778 | int offset= widgetRegion.getOffset(); | |
779 | int startLine= extension.widgetLineOfWidgetOffset(offset); | |
780 | if (startLine == -1) | |
781 | continue; | |
782 | ||
783 | int length= Math.max(widgetRegion.getLength() -1, 0); | |
784 | int endLine= extension.widgetLineOfWidgetOffset(offset + length); | |
785 | if (endLine == -1) | |
786 | continue; | |
787 | ||
788 | r.x= 0; | |
789 | ||
790 | r.width= dimension.x; | |
791 | int lines= endLine - startLine; | |
792 | ||
793 | if(startLine != endLine || !isWrapActive || length <= 0){ | |
794 | // line height for different lines includes wrapped line info already, | |
795 | // end we show annotations without offset info at very first line anyway | |
796 | r.height= JFaceTextUtil.computeLineHeight(fCachedTextWidget, startLine, endLine + 1, lines + 1); | |
797 | r.y= JFaceTextUtil.computeLineHeight(fCachedTextWidget, 0, startLine, startLine) - fScrollPos; | |
798 | } else { | |
799 | // annotate only the part of the line related to the given offset | |
800 | Rectangle textBounds= fCachedTextWidget.getTextBounds(offset, offset + length); | |
801 | r.height= textBounds.height; | |
802 | r.y = textBounds.y; | |
803 | } | |
804 | // adjust the annotation position at the bottom of the line if line height has custom vertical line indent | |
805 | int verticalIndent= fCachedTextViewer.getTextWidget().getLineVerticalIndent(startLine); | |
806 | if (verticalIndent > 0) { | |
807 | r.y+= verticalIndent; | |
808 | r.height-= verticalIndent; | |
809 | } | |
810 | if (r.y < dimension.y && fAnnotationAccessExtension != null) // annotation within visible area | |
811 | fAnnotationAccessExtension.paint(annotation, gc, fCanvas, r); | |
812 | } | |
765 | for (Tuple tuple : fCachedAnnotations) { | |
766 | Annotation annotation= tuple.annotation; | |
767 | Position position= tuple.position; | |
768 | ||
769 | range.setOffset(position.getOffset()); | |
770 | range.setLength(position.getLength()); | |
771 | IRegion widgetRegion= extension.modelRange2WidgetRange(range); | |
772 | if (widgetRegion == null) | |
773 | continue; | |
774 | ||
775 | int offset= widgetRegion.getOffset(); | |
776 | int startLine= extension.widgetLineOfWidgetOffset(offset); | |
777 | if (startLine == -1) | |
778 | continue; | |
779 | ||
780 | int length= Math.max(widgetRegion.getLength() - 1, 0); | |
781 | int endLine= extension.widgetLineOfWidgetOffset(offset + length); | |
782 | if (endLine == -1) | |
783 | continue; | |
784 | ||
785 | r.x= 0; | |
786 | ||
787 | r.width= dimension.x; | |
788 | int lines= endLine - startLine; | |
789 | ||
790 | if (startLine != endLine || !isWrapActive || length <= 0) { | |
791 | // line height for different lines includes wrapped line info already, | |
792 | // end we show annotations without offset info at very first line anyway | |
793 | r.height= JFaceTextUtil.computeLineHeight(fCachedTextWidget, startLine, endLine + 1, lines + 1); | |
794 | r.y= JFaceTextUtil.computeLineHeight(fCachedTextWidget, 0, startLine, startLine) - fScrollPos; | |
795 | } else { | |
796 | // annotate only the part of the line related to the given offset | |
797 | Rectangle textBounds= fCachedTextWidget.getTextBounds(offset, offset + length); | |
798 | r.height= textBounds.height; | |
799 | r.y= textBounds.y; | |
800 | } | |
801 | // adjust the annotation position at the bottom of the line if line height has custom vertical line indent | |
802 | int verticalIndent= fCachedTextViewer.getTextWidget().getLineVerticalIndent(startLine); | |
803 | if (verticalIndent > 0) { | |
804 | r.y+= verticalIndent; | |
805 | r.height-= verticalIndent; | |
806 | } | |
807 | if (r.y < dimension.y && fAnnotationAccessExtension != null) // annotation within visible area | |
808 | fAnnotationAccessExtension.paint(annotation, gc, fCanvas, r); | |
813 | 809 | } |
814 | 810 | |
815 | 811 | fCachedAnnotations.clear(); |
+0
-2
169 | 169 | Color foreground= gc.getForeground(); |
170 | 170 | if (visibleLines != null) { |
171 | 171 | if (fRevisionPainter.hasInformation()) { |
172 | fRevisionPainter.setZoom(fZoom); | |
173 | 172 | fRevisionPainter.paint(gc, visibleLines); |
174 | 173 | } else if (fDiffPainter.hasInformation()) { // don't paint quick diff colors if revisions are painted |
175 | fDiffPainter.setZoom(fZoom); | |
176 | 174 | fDiffPainter.paint(gc, visibleLines); |
177 | 175 | } |
178 | 176 | } |
+116
-123
0 | 0 | /******************************************************************************* |
1 | * Copyright (c) 2000, 2018 IBM Corporation and others. | |
1 | * Copyright (c) 2000, 2019 IBM Corporation and others. | |
2 | 2 | * |
3 | 3 | * This program and the accompanying materials |
4 | 4 | * are made available under the terms of the Eclipse Public License 2.0 |
17 | 17 | *******************************************************************************/ |
18 | 18 | package org.eclipse.jface.text.source; |
19 | 19 | |
20 | import java.lang.ref.WeakReference; | |
21 | 20 | import java.util.Arrays; |
22 | 21 | import java.util.function.Consumer; |
23 | 22 | |
31 | 30 | import org.eclipse.swt.events.MouseWheelListener; |
32 | 31 | import org.eclipse.swt.graphics.Color; |
33 | 32 | import org.eclipse.swt.graphics.Font; |
34 | import org.eclipse.swt.graphics.FontData; | |
35 | 33 | import org.eclipse.swt.graphics.FontMetrics; |
36 | 34 | import org.eclipse.swt.graphics.GC; |
37 | 35 | import org.eclipse.swt.graphics.Image; |
38 | import org.eclipse.swt.graphics.ImageData; | |
39 | import org.eclipse.swt.graphics.ImageDataProvider; | |
40 | 36 | import org.eclipse.swt.graphics.Point; |
41 | 37 | import org.eclipse.swt.graphics.Rectangle; |
42 | 38 | import org.eclipse.swt.widgets.Canvas; |
44 | 40 | import org.eclipse.swt.widgets.Control; |
45 | 41 | import org.eclipse.swt.widgets.Display; |
46 | 42 | import org.eclipse.swt.widgets.TypedListener; |
47 | ||
48 | import org.eclipse.jface.util.Util; | |
49 | 43 | |
50 | 44 | import org.eclipse.jface.text.BadLocationException; |
51 | 45 | import org.eclipse.jface.text.IDocument; |
65 | 59 | * @since 2.0 |
66 | 60 | */ |
67 | 61 | public class LineNumberRulerColumn implements IVerticalRulerColumn { |
68 | ||
69 | /** | |
70 | * <code>true</code> if we're on a Mac, where drawing on an Image currently only draws at 100% zoom level, | |
71 | * which results in blurry line numbers on a Retina display. | |
72 | * | |
73 | * @see <a href="https://bugs.eclipse.org/516293">bug 516293</a> | |
74 | * @since 3.6 | |
75 | */ | |
76 | private final boolean IS_MAC_BUG_516293= Util.isMac() | |
77 | && !"false".equals(System.getProperty("LineNumberRulerColumn.retina.workaround")) //$NON-NLS-1$ //$NON-NLS-2$ | |
78 | && internalSupportsZoomedPaint(); | |
79 | 62 | |
80 | 63 | /** |
81 | 64 | * Internal listener class. |
397 | 380 | private int fCachedNumberOfDigits= -1; |
398 | 381 | /** Flag indicating whether a relayout is required */ |
399 | 382 | private boolean fRelayoutRequired= false; |
383 | /** Last top pixel. */ | |
384 | private int fLastTopPixel = -1; | |
385 | /** Last top model line. */ | |
386 | private int fLastTopModelLine; | |
387 | /** Last number of lines visible. */ | |
388 | private int fLastNumberOfLines; | |
389 | /** Last bottom model line. */ | |
390 | private int fLastBottomModelLine; | |
391 | /** Last canvas height used. */ | |
392 | private int fLastHeight= -1; | |
400 | 393 | /** |
401 | 394 | * Redraw runnable lock |
402 | 395 | * @since 3.0 |
419 | 412 | }; |
420 | 413 | /* @since 3.2 */ |
421 | 414 | private MouseHandler fMouseHandler; |
422 | /* | |
423 | * Zoom level and cached font for the current painting operation. Workaround for bug 516293. | |
424 | * @since 3.12 | |
425 | */ | |
426 | int fZoom= 100; | |
427 | private WeakReference<Font> fLastFont; | |
428 | private Font fLastZoomedFont; | |
429 | 415 | |
430 | 416 | /** |
431 | 417 | * Redraw the ruler handler called when a line height change. |
671 | 657 | fBuffer.dispose(); |
672 | 658 | fBuffer= null; |
673 | 659 | } |
674 | ||
675 | if (fLastZoomedFont != null) { | |
676 | fLastZoomedFont.dispose(); | |
677 | fLastZoomedFont= null; | |
678 | fLastFont= null; | |
679 | } | |
680 | 660 | } |
681 | 661 | |
682 | 662 | /** |
688 | 668 | |
689 | 669 | Point size= fCanvas.getSize(); |
690 | 670 | |
691 | if (size.x <= 0 || size.y <= 0) | |
671 | if (size.x <= 0 || size.y <= 0) { | |
692 | 672 | return; |
673 | } | |
693 | 674 | |
694 | 675 | if (fBuffer != null) { |
695 | 676 | Rectangle r= fBuffer.getBounds(); |
696 | if (IS_MAC_BUG_516293 || r.width != size.x || r.height != size.y) { | |
677 | if (r.width != size.x || r.height != size.y) { | |
697 | 678 | fBuffer.dispose(); |
698 | 679 | fBuffer= null; |
699 | 680 | } |
700 | 681 | } |
701 | 682 | |
702 | 683 | ILineRange visibleLines= JFaceTextUtil.getVisibleModelLines(fCachedTextViewer); |
703 | if (visibleLines == null) | |
684 | if (visibleLines == null) { | |
704 | 685 | return; |
705 | ||
706 | if (IS_MAC_BUG_516293) { | |
707 | /* FIXME: Workaround (bug 516293): | |
708 | * Relies on SWT implementation detail that GC drawing on macOS only draws at 100% zoom level. | |
709 | * For higher zoom levels (200%), we manually scale the font and drawing coordinates, | |
710 | * and then use getImageData(100) to extract the high-resolution image data. */ | |
711 | fBuffer= new Image(fCanvas.getDisplay(), (ImageDataProvider) zoom -> { | |
712 | fZoom = zoom; | |
713 | internalSetZoom(zoom); | |
714 | int width= size.x * zoom / 100; | |
715 | int height= size.y * zoom / 100; | |
716 | Image gcImage= new Image(fCanvas.getDisplay(), width, height); | |
717 | ||
718 | GC gc= new GC(gcImage); | |
719 | Font font= fCanvas.getFont(); | |
720 | if (zoom != 100) { | |
721 | if (fLastFont != null && font == fLastFont.get()) { | |
722 | font= fLastZoomedFont; | |
686 | } | |
687 | ||
688 | boolean bufferStillValid = fBuffer != null; | |
689 | if (fBuffer == null) { | |
690 | fBuffer= new Image(fCanvas.getDisplay(), size.x, size.y); | |
691 | } | |
692 | GC bufferGC= new GC(fBuffer); | |
693 | Image newBuffer= null; | |
694 | try { | |
695 | int topPixel= fCachedTextWidget.getTopPixel(); | |
696 | int bufferY= 0; | |
697 | int bufferH= size.y; | |
698 | int numberOfLines= visibleLines.getNumberOfLines(); | |
699 | int dy= topPixel - fLastTopPixel; | |
700 | int topModelLine= visibleLines.getStartLine(); | |
701 | int bottomModelLine= topModelLine + numberOfLines - 1; | |
702 | int bottomWidgetLine= JFaceTextUtil.modelLineToWidgetLine(fCachedTextViewer, bottomModelLine); | |
703 | boolean atEnd= bottomWidgetLine + 1 >= fCachedTextWidget.getLineCount(); | |
704 | int height= size.y; | |
705 | if (dy != 0 && !atEnd && bufferStillValid && fLastTopPixel >= 0 && numberOfLines > 1 && numberOfLines == fLastNumberOfLines) { | |
706 | int bottomPixel= fCachedTextWidget.getLinePixel(bottomWidgetLine + 1); | |
707 | if (dy > 0 && bottomPixel < size.y) { | |
708 | // Can occur on GTK with static scrollbars; see bug 551320. | |
709 | height= bottomPixel; | |
710 | } | |
711 | if (dy > 0 && dy < height) { | |
712 | int goodPixels= height; | |
713 | if (goodPixels > fLastHeight) { | |
714 | // Dont copy empty pixels from last time. | |
715 | goodPixels= fLastHeight; | |
716 | } | |
717 | if (dy < goodPixels) { | |
718 | bufferGC.copyArea(0, dy, size.x, goodPixels - dy, 0, 0); | |
719 | bufferY= goodPixels - dy; | |
720 | bufferH= height - bufferY; | |
723 | 721 | } else { |
724 | fLastFont= new WeakReference<>(font); | |
725 | FontData fontData= font.getFontData()[0]; | |
726 | fontData.setHeight(fontData.getHeight() * zoom / 100); | |
727 | font= new Font(font.getDevice(), fontData); | |
728 | fLastZoomedFont= font; | |
722 | // Redraw everything. | |
723 | height= size.y; | |
724 | dy= 0; | |
729 | 725 | } |
726 | } else if (dy < 0 && -dy < height) { | |
727 | bufferGC.copyArea(0, 0, size.x, height + dy, 0, -dy); | |
728 | bufferY= 0; | |
729 | bufferH= -dy; | |
730 | } else { | |
731 | height= size.y; | |
732 | dy= 0; | |
730 | 733 | } |
731 | gc.setFont(font); | |
732 | if (fForeground != null) | |
733 | gc.setForeground(fForeground); | |
734 | ||
734 | } else { | |
735 | dy= 0; | |
736 | } | |
737 | // dy == 0 means now "draw everything", either because there was no overlap, or we indeed didn't move | |
738 | // (refresh or other cases), or there was a resize, or it's the first time, or we are showing the very | |
739 | // last line. | |
740 | if (dy != 0) { | |
741 | // Reduce the line range. | |
742 | if (dy > 0) { | |
743 | visibleLines= new LineRange(fLastBottomModelLine, bottomModelLine - fLastBottomModelLine + 1); | |
744 | } else { | |
745 | visibleLines= new LineRange(topModelLine, fLastTopModelLine - topModelLine + 1); | |
746 | } | |
747 | } | |
748 | fLastTopPixel= topPixel; | |
749 | fLastTopModelLine= topModelLine; | |
750 | fLastNumberOfLines= numberOfLines; | |
751 | fLastBottomModelLine= bottomModelLine; | |
752 | fLastHeight= height; | |
753 | if (dy != 0) { | |
754 | // Some rulers may paint outside the line region. Let them paint in a new image, | |
755 | // the copy the wanted bits. | |
756 | newBuffer= new Image(fCanvas.getDisplay(), size.x, size.y); | |
757 | GC localGC= new GC(newBuffer); | |
735 | 758 | try { |
736 | gc.setBackground(getBackground(fCanvas.getDisplay())); | |
737 | gc.fillRectangle(0, 0, width, height); | |
738 | ||
739 | doPaint(gc, visibleLines); | |
759 | initializeGC(localGC, 0, bufferY, size.x, bufferH); | |
760 | doPaint(localGC, visibleLines); | |
740 | 761 | } finally { |
741 | gc.dispose(); | |
742 | fZoom= 100; | |
762 | localGC.dispose(); | |
743 | 763 | } |
744 | ||
745 | ImageData imageData= gcImage.getImageData(100); | |
746 | gcImage.dispose(); | |
747 | return imageData; | |
748 | }); | |
749 | ||
750 | } else { | |
751 | if (fBuffer == null) | |
752 | fBuffer= new Image(fCanvas.getDisplay(), size.x, size.y); | |
753 | ||
754 | GC gc= new GC(fBuffer); | |
755 | gc.setFont(fCanvas.getFont()); | |
756 | if (fForeground != null) | |
757 | gc.setForeground(fForeground); | |
758 | ||
759 | try { | |
760 | gc.setBackground(getBackground(fCanvas.getDisplay())); | |
761 | gc.fillRectangle(0, 0, size.x, size.y); | |
762 | ||
763 | doPaint(gc, visibleLines); | |
764 | } finally { | |
765 | gc.dispose(); | |
766 | } | |
767 | } | |
768 | ||
764 | bufferGC.drawImage(newBuffer, 0, bufferY, size.x, bufferH, 0, bufferY, size.x, bufferH); | |
765 | if (dy > 0 && bufferY + bufferH < size.y) { | |
766 | // Scrolled down in the text, but didn't use the full height of the Canvas: clear | |
767 | // the rest. Occurs on GTK with static scrollbars; the area cleared here is the | |
768 | // bit next to the horizontal scrollbar. See bug 551320. | |
769 | bufferGC.setBackground(getBackground(fCanvas.getDisplay())); | |
770 | bufferGC.fillRectangle(0, bufferY + bufferH, size.x, size.y - bufferY - bufferH + 1); | |
771 | } | |
772 | } else { | |
773 | // We redraw everything; paint directly into the buffer | |
774 | initializeGC(bufferGC, 0, 0, size.x, size.y); | |
775 | doPaint(bufferGC, visibleLines); | |
776 | } | |
777 | } finally { | |
778 | bufferGC.dispose(); | |
779 | if (newBuffer != null) { | |
780 | newBuffer.dispose(); | |
781 | } | |
782 | } | |
769 | 783 | dest.drawImage(fBuffer, 0, 0); |
770 | 784 | } |
771 | 785 | |
772 | /** | |
773 | * This method is not API and it is expected to disappear in Eclipse 4.8. | |
774 | * Subclasses that want to take advantage of the unsupported workaround for bug 516258 | |
775 | * can re-implement this method and return true. | |
776 | * | |
777 | * @return true iff this class supports the workaround for bug 516258 | |
778 | * | |
779 | * @nooverride This method is not intended to be re-implemented or extended by clients. | |
780 | * @noreference This method is not intended to be referenced by clients. | |
781 | * @since 3.12 | |
782 | */ | |
783 | protected boolean internalSupportsZoomedPaint() { | |
784 | return getClass().getPackage().equals(LineNumberChangeRulerColumn.class.getPackage()); | |
785 | } | |
786 | ||
787 | /** | |
788 | * This method is not API and it is expected to disappear in Eclipse 4.8. | |
789 | * Subclasses that want to take advantage of the unsupported workaround for bug 516258 | |
790 | * can override this method and store the given zoom level for later use. | |
791 | * | |
792 | * @param zoom the zoom level to use for drawing operations | |
793 | * | |
794 | * @nooverride This method is not intended to be re-implemented or extended by clients. | |
795 | * @noreference This method is not intended to be referenced by clients. | |
796 | * @since 3.12 | |
797 | */ | |
798 | protected void internalSetZoom(int zoom) { | |
799 | // callback for subclasses | |
786 | private void initializeGC(GC gc, int x, int y, int width, int height) { | |
787 | gc.setFont(fCanvas.getFont()); | |
788 | if (fForeground != null) { | |
789 | gc.setForeground(fForeground); | |
790 | } | |
791 | gc.setBackground(getBackground(fCanvas.getDisplay())); | |
792 | gc.fillRectangle(x, y, width, height); | |
800 | 793 | } |
801 | 794 | |
802 | 795 | /** |
833 | 826 | void doPaint(GC gc, ILineRange visibleLines) { |
834 | 827 | Display display= fCachedTextWidget.getDisplay(); |
835 | 828 | |
836 | // draw diff info | |
837 | int y= -JFaceTextUtil.getHiddenTopLinePixels(fCachedTextWidget); | |
829 | int firstWidgetLineToDraw= JFaceTextUtil.modelLineToWidgetLine(fCachedTextViewer, visibleLines.getStartLine()); | |
830 | int y= fCachedTextWidget.getLinePixel(firstWidgetLineToDraw); | |
838 | 831 | |
839 | 832 | // add empty lines if line is wrapped |
840 | 833 | boolean isWrapActive= fCachedTextWidget.getWordWrap(); |
937 | 930 | int indentation= fIndentation[index]; |
938 | 931 | int baselineBias= getBaselineBias(gc, widgetLine); |
939 | 932 | int verticalIndent= fCachedTextViewer.getTextWidget().getLineVerticalIndent(widgetLine); |
940 | gc.drawString(s, indentation * fZoom / 100, (y + baselineBias + verticalIndent) * fZoom / 100, true); | |
933 | gc.drawString(s, indentation, y + baselineBias + verticalIndent, true); | |
941 | 934 | } |
942 | 935 | |
943 | 936 | /** |
+1
-1
278 | 278 | * |
279 | 279 | * @param sourceViewer the source viewer |
280 | 280 | * @return a region denoting the current signed selection, for a resulting RtoL selections |
281 | * length is < 0 | |
281 | * length is < 0 | |
282 | 282 | * @since 3.8 |
283 | 283 | */ |
284 | 284 | private static final IRegion getSignedSelection(ISourceViewer sourceViewer) { |
307 | 307 | * |
308 | 308 | * @since 3.7 |
309 | 309 | */ |
310 | static class WidgetInfos { | |
310 | private static class WidgetInfos { | |
311 | 311 | /** |
312 | 312 | * the text widget line count |
313 | 313 | */ |
328 | 328 | * the bounds of {@link OverviewRuler#fCanvas} |
329 | 329 | */ |
330 | 330 | Rectangle bounds; |
331 | ||
331 | 332 | /** |
332 | * the writable area in the text widget (height of all lines in pixels) | |
333 | * the writable area in the text widget (height of all lines in pixels), if smaller than | |
334 | * bounds.height; otherwise an unspecified value >= bounds.height | |
333 | 335 | */ |
334 | 336 | int writable; |
335 | 337 | |
342 | 344 | public WidgetInfos(StyledText textWidget, Canvas canvas) { |
343 | 345 | maxLines= textWidget.getLineCount(); |
344 | 346 | bounds= canvas.getBounds(); |
345 | writable= JFaceTextUtil.computeLineHeight(textWidget, 0, maxLines, maxLines); | |
347 | // writeable is of interest only if it is smaller than bounds.height. | |
348 | int w= 0; | |
349 | for (int i= 0; i < maxLines && w < bounds.height; i++) { | |
350 | w+= JFaceTextUtil.computeLineHeight(textWidget, i); | |
351 | } | |
352 | writable= w; | |
346 | 353 | |
347 | 354 | ScrollBar verticalBar= textWidget.getVerticalBar(); |
348 | 355 | if (verticalBar != null && !verticalBar.getVisible()) { |
+1
-8
18 | 18 | |
19 | 19 | import org.eclipse.swt.SWT; |
20 | 20 | import org.eclipse.swt.graphics.RGB; |
21 | import org.eclipse.swt.widgets.Shell; | |
22 | 21 | |
23 | 22 | import org.eclipse.jface.text.DefaultInformationControl; |
24 | 23 | import org.eclipse.jface.text.DefaultTextDoubleClickStrategy; |
25 | 24 | import org.eclipse.jface.text.IAutoEditStrategy; |
26 | 25 | import org.eclipse.jface.text.IDocument; |
27 | 26 | import org.eclipse.jface.text.IDocumentExtension3; |
28 | import org.eclipse.jface.text.IInformationControl; | |
29 | 27 | import org.eclipse.jface.text.IInformationControlCreator; |
30 | 28 | import org.eclipse.jface.text.ITextDoubleClickStrategy; |
31 | 29 | import org.eclipse.jface.text.ITextHover; |
332 | 330 | * @since 2.0 |
333 | 331 | */ |
334 | 332 | public IInformationControlCreator getInformationControlCreator(ISourceViewer sourceViewer) { |
335 | return new IInformationControlCreator() { | |
336 | @Override | |
337 | public IInformationControl createInformationControl(Shell parent) { | |
338 | return new DefaultInformationControl(parent); | |
339 | } | |
340 | }; | |
333 | return DefaultInformationControl::new; | |
341 | 334 | } |
342 | 335 | |
343 | 336 | /** |
0 | /** | |
1 | * Copyright (c) 2018 Angelo ZERR. | |
0 | /******************************************************************************* | |
1 | * Copyright (c) 2018, 2019 Angelo ZERR and others. | |
2 | 2 | * |
3 | 3 | * This program and the accompanying materials |
4 | 4 | * are made available under the terms of the Eclipse Public License 2.0 |
8 | 8 | * SPDX-License-Identifier: EPL-2.0 |
9 | 9 | * |
10 | 10 | * Contributors: |
11 | * Angelo Zerr <angelo.zerr@gmail.com> - Bug 527720 - [CodeMining] Line number in vertical ruler can be not synchronized with line header annotation | |
12 | */ | |
11 | * Angelo Zerr <angelo.zerr@gmail.com> - Bug 527720 - [CodeMining] Line number in vertical ruler can be not synchronized with line header annotation | |
12 | * Thomas Wolf <thomas.wolf@paranor.ch> - Bug 553133 | |
13 | *******************************************************************************/ | |
13 | 14 | package org.eclipse.jface.text.source; |
14 | 15 | |
15 | 16 | import java.util.LinkedHashSet; |
23 | 24 | import org.eclipse.jface.text.JFaceTextUtil; |
24 | 25 | |
25 | 26 | /** |
26 | * Class to track line height change of visible lines of a given {@link StyledText}. | |
27 | * | |
27 | * Tracks line height changes of visible lines of a given {@link StyledText}. | |
28 | 28 | */ |
29 | 29 | class VisibleLinesTracker implements PaintListener { |
30 | 30 | |
36 | 36 | private final ITextViewer viewer; |
37 | 37 | |
38 | 38 | /** |
39 | * The previous bottom line index. | |
39 | * The previous bottom model line index. | |
40 | 40 | */ |
41 | private int oldBottom= -1; | |
41 | private int oldModelBottom= -1; | |
42 | ||
43 | /** | |
44 | * The previous bottom widget line index. | |
45 | */ | |
46 | private int oldWidgetBottom= -1; | |
42 | 47 | |
43 | 48 | /** |
44 | 49 | * The previous bottom line pixel. |
64 | 69 | public void paintControl(PaintEvent e) { |
65 | 70 | StyledText textWidget= viewer.getTextWidget(); |
66 | 71 | // track if bottom line index or bottom line pixel changed. |
67 | if (oldBottom == -1) { | |
68 | oldBottom= JFaceTextUtil.getPartialBottomIndex(viewer); | |
69 | oldBottomPixel= JFaceTextUtil.getLinePixel(textWidget, oldBottom); | |
72 | if (oldModelBottom == -1) { | |
73 | oldWidgetBottom= JFaceTextUtil.getPartialBottomIndex(textWidget); | |
74 | oldModelBottom= JFaceTextUtil.widgetLine2ModelLine(viewer, oldWidgetBottom); | |
75 | oldBottomPixel= JFaceTextUtil.getLinePixel(textWidget, oldWidgetBottom); | |
70 | 76 | return; |
71 | 77 | } |
72 | int newBottom= JFaceTextUtil.getPartialBottomIndex(viewer); | |
73 | if (newBottom != oldBottom) { | |
74 | oldBottom= newBottom; | |
75 | oldBottomPixel= JFaceTextUtil.getLinePixel(textWidget, oldBottom); | |
76 | handlers.forEach(handler -> handler.accept(textWidget)); | |
77 | return; | |
78 | } | |
79 | int newBottomPixel= JFaceTextUtil.getLinePixel(textWidget, newBottom); | |
80 | if (newBottomPixel != oldBottomPixel) { | |
78 | int newWidgetBottom= JFaceTextUtil.getPartialBottomIndex(textWidget); | |
79 | int newModelBottom= JFaceTextUtil.widgetLine2ModelLine(viewer, newWidgetBottom); | |
80 | int newBottomPixel= JFaceTextUtil.getLinePixel(textWidget, newWidgetBottom); | |
81 | if (newWidgetBottom != oldWidgetBottom || newModelBottom != oldModelBottom || newBottomPixel != oldBottomPixel) { | |
82 | oldWidgetBottom= newWidgetBottom; | |
83 | oldModelBottom= newModelBottom; | |
81 | 84 | oldBottomPixel= newBottomPixel; |
82 | 85 | handlers.forEach(handler -> handler.accept(textWidget)); |
83 | return; | |
84 | 86 | } |
85 | 87 | } |
86 | 88 |
0 | <?xml version="1.0" encoding="UTF-8"?> | |
1 | <classpath> | |
2 | <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/> | |
3 | <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/> | |
4 | <classpathentry kind="src" path="src"/> | |
5 | <classpathentry kind="output" path="bin"/> | |
6 | </classpath> | |
0 | <?xml version="1.0" encoding="UTF-8"?> | |
1 | <classpath> | |
2 | <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/> | |
3 | <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/> | |
4 | <classpathentry kind="src" path="src"/> | |
5 | <classpathentry kind="output" path="bin"/> | |
6 | </classpath> |
0 | <?xml version="1.0" encoding="UTF-8"?> | |
1 | <projectDescription> | |
2 | <name>org.eclipse.jface.text.examples</name> | |
3 | <comment></comment> | |
4 | <projects> | |
5 | </projects> | |
6 | <buildSpec> | |
7 | <buildCommand> | |
8 | <name>org.eclipse.jdt.core.javabuilder</name> | |
9 | <arguments> | |
10 | </arguments> | |
11 | </buildCommand> | |
12 | <buildCommand> | |
13 | <name>org.eclipse.pde.ManifestBuilder</name> | |
14 | <arguments> | |
15 | </arguments> | |
16 | </buildCommand> | |
17 | <buildCommand> | |
18 | <name>org.eclipse.pde.SchemaBuilder</name> | |
19 | <arguments> | |
20 | </arguments> | |
21 | </buildCommand> | |
22 | </buildSpec> | |
23 | <natures> | |
24 | <nature>org.eclipse.pde.PluginNature</nature> | |
25 | <nature>org.eclipse.jdt.core.javanature</nature> | |
26 | </natures> | |
27 | </projectDescription> | |
0 | <?xml version="1.0" encoding="UTF-8"?> | |
1 | <projectDescription> | |
2 | <name>org.eclipse.jface.text.examples</name> | |
3 | <comment></comment> | |
4 | <projects> | |
5 | </projects> | |
6 | <buildSpec> | |
7 | <buildCommand> | |
8 | <name>org.eclipse.jdt.core.javabuilder</name> | |
9 | <arguments> | |
10 | </arguments> | |
11 | </buildCommand> | |
12 | <buildCommand> | |
13 | <name>org.eclipse.pde.ManifestBuilder</name> | |
14 | <arguments> | |
15 | </arguments> | |
16 | </buildCommand> | |
17 | <buildCommand> | |
18 | <name>org.eclipse.pde.SchemaBuilder</name> | |
19 | <arguments> | |
20 | </arguments> | |
21 | </buildCommand> | |
22 | </buildSpec> | |
23 | <natures> | |
24 | <nature>org.eclipse.pde.PluginNature</nature> | |
25 | <nature>org.eclipse.jdt.core.javanature</nature> | |
26 | </natures> | |
27 | </projectDescription> |
0 | eclipse.preferences.version=1 | |
1 | org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled | |
2 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 | |
3 | org.eclipse.jdt.core.compiler.compliance=1.8 | |
4 | org.eclipse.jdt.core.compiler.problem.assertIdentifier=error | |
5 | org.eclipse.jdt.core.compiler.problem.enumIdentifier=error | |
6 | org.eclipse.jdt.core.compiler.source=1.8 | |
0 | eclipse.preferences.version=1 | |
1 | org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled | |
2 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 | |
3 | org.eclipse.jdt.core.compiler.compliance=1.8 | |
4 | org.eclipse.jdt.core.compiler.problem.assertIdentifier=error | |
5 | org.eclipse.jdt.core.compiler.problem.enumIdentifier=error | |
6 | org.eclipse.jdt.core.compiler.source=1.8 |
0 | eclipse.preferences.version=1 | |
1 | pluginProject.extensions=false | |
2 | resolve.requirebundle=false | |
0 | eclipse.preferences.version=1 | |
1 | pluginProject.extensions=false | |
2 | resolve.requirebundle=false |
0 | source.. = src/ | |
1 | output.. = bin/ | |
2 | bin.includes = META-INF/,\ | |
3 | . | |
0 | source.. = src/ | |
1 | output.. = bin/ | |
2 | bin.includes = META-INF/,\ | |
3 | . |
13 | 13 | <parent> |
14 | 14 | <artifactId>eclipse.platform.text</artifactId> |
15 | 15 | <groupId>eclipse.platform.text</groupId> |
16 | <version>4.13.0-SNAPSHOT</version> | |
16 | <version>4.14.0-SNAPSHOT</version> | |
17 | 17 | </parent> |
18 | 18 | <groupId>org.eclipse.core</groupId> |
19 | 19 | <artifactId>org.eclipse.jface.text.examples</artifactId> |
+6
-7
0 | /**s | |
1 | * Copyright (c) 2017 Angelo ZERR. | |
0 | /** Copyright (c) 2017, 2019 Angelo ZERR and others. | |
2 | 1 | * |
3 | 2 | * This program and the accompanying materials |
4 | 3 | * are made available under the terms of the Eclipse Public License 2.0 |
37 | 36 | public class ColorAnnotation extends LineContentAnnotation { |
38 | 37 | |
39 | 38 | private Color color; |
40 | ||
39 | ||
41 | 40 | private Consumer<MouseEvent> action = e -> { |
42 | 41 | StyledText styledText = super.getTextWidget(); |
43 | 42 | Shell shell = new Shell(styledText.getDisplay()); |
61 | 60 | } |
62 | 61 | } |
63 | 62 | }; |
64 | ||
63 | ||
65 | 64 | /** |
66 | 65 | * Format the given rgb to hexa color. |
67 | * | |
66 | * | |
68 | 67 | * @param rgb |
69 | 68 | * @return the hexa color from the given rgb. |
70 | 69 | */ |
118 | 117 | */ |
119 | 118 | private static int getSquareWidth(FontMetrics fontMetrics) { |
120 | 119 | // width = 2 spaces + size width of square |
121 | int width = 2 * fontMetrics.getAverageCharWidth() + getSquareSize(fontMetrics); | |
120 | int width = (int) (2 * fontMetrics.getAverageCharacterWidth() + getSquareSize(fontMetrics)); | |
122 | 121 | return width; |
123 | 122 | } |
124 | ||
123 | ||
125 | 124 | @Override |
126 | 125 | public Consumer<MouseEvent> getAction(MouseEvent e) { |
127 | 126 | return action; |
+1
-1
209 | 209 | |
210 | 210 | /** |
211 | 211 | * Add RGB parameter name annotation |
212 | * | |
212 | * | |
213 | 213 | * @param paramName |
214 | 214 | * @param rgbContent |
215 | 215 | * @param startIndex |
1 | 1 | Bundle-ManifestVersion: 2 |
2 | 2 | Bundle-Name: %Plugin.name |
3 | 3 | Bundle-SymbolicName: org.eclipse.jface.text.tests |
4 | Bundle-Version: 3.11.800.qualifier | |
4 | Bundle-Version: 3.11.900.qualifier | |
5 | 5 | Bundle-Vendor: %Plugin.providerName |
6 | 6 | Bundle-Localization: plugin |
7 | 7 | Export-Package: |
15 | 15 | org.eclipse.jface.text.tests.templates.persistence, |
16 | 16 | org.eclipse.jface.text.tests.util |
17 | 17 | Require-Bundle: |
18 | org.eclipse.jface.text;bundle-version="[3.5.0,4.0.0)", | |
18 | org.eclipse.jface.text;bundle-version="[3.16.0,4.0.0)", | |
19 | 19 | org.eclipse.jface;bundle-version="[3.5.0,4.0.0)", |
20 | 20 | org.junit;bundle-version="4.12.0", |
21 | 21 | org.eclipse.text.tests;bundle-version="[3.5.0,4.0.0)", |
13 | 13 | <parent> |
14 | 14 | <artifactId>tests-pom</artifactId> |
15 | 15 | <groupId>eclipse.platform.text</groupId> |
16 | <version>4.13.0-SNAPSHOT</version> | |
16 | <version>4.14.0-SNAPSHOT</version> | |
17 | 17 | <relativePath>../tests-pom/</relativePath> |
18 | 18 | </parent> |
19 | 19 | <groupId>org.eclipse.jface</groupId> |
20 | 20 | <artifactId>org.eclipse.jface.text.tests</artifactId> |
21 | <version>3.11.800-SNAPSHOT</version> | |
21 | <version>3.11.900-SNAPSHOT</version> | |
22 | 22 | <packaging>eclipse-test-plugin</packaging> |
23 | 23 | <properties> |
24 | 24 | <testSuite>${project.artifactId}</testSuite> |
+12
-12
54 | 54 | |
55 | 55 | /** |
56 | 56 | * Constructs a new character pair matcher. |
57 | * | |
57 | * | |
58 | 58 | * @param chars the characters to match |
59 | 59 | * @return the character pair matcher |
60 | 60 | */ |
64 | 64 | |
65 | 65 | /** |
66 | 66 | * Returns the partitioning treated by the matcher. |
67 | * | |
67 | * | |
68 | 68 | * @return the partition |
69 | 69 | */ |
70 | 70 | protected String getDocumentPartitioning() { |
82 | 82 | |
83 | 83 | /** |
84 | 84 | * Very simple checks. |
85 | * | |
85 | * | |
86 | 86 | * @throws BadLocationException test failure |
87 | 87 | */ |
88 | 88 | @Test |
115 | 115 | |
116 | 116 | /** |
117 | 117 | * Very simple checks. |
118 | * | |
118 | * | |
119 | 119 | * @throws BadLocationException test failure |
120 | 120 | */ |
121 | 121 | @Test |
134 | 134 | |
135 | 135 | /** |
136 | 136 | * Close matches. |
137 | * | |
137 | * | |
138 | 138 | * @throws BadLocationException test failure |
139 | 139 | */ |
140 | 140 | @Test |
162 | 162 | |
163 | 163 | /** |
164 | 164 | * Checks of simple situations where no matches should be found. |
165 | * | |
165 | * | |
166 | 166 | * @throws BadLocationException test failure |
167 | 167 | */ |
168 | 168 | @Test |
176 | 176 | |
177 | 177 | /** |
178 | 178 | * Test that it doesn't match across different partitions. |
179 | * | |
179 | * | |
180 | 180 | * @throws BadLocationException test failure |
181 | 181 | */ |
182 | 182 | @Test |
214 | 214 | |
215 | 215 | /** |
216 | 216 | * Test that it works properly next to partition boundaries. |
217 | * | |
217 | * | |
218 | 218 | * @throws BadLocationException test failure |
219 | 219 | */ |
220 | 220 | @Test |
270 | 270 | |
271 | 271 | /** |
272 | 272 | * Test a few boundary conditions. |
273 | * | |
273 | * | |
274 | 274 | * * @throws BadLocationException test failure |
275 | 275 | */ |
276 | 276 | @Test |
306 | 306 | |
307 | 307 | /** |
308 | 308 | * Checks that the test case reader reads the test case as specified. |
309 | * | |
309 | * | |
310 | 310 | * @param testString the string to test |
311 | 311 | * @param expectedPos the expected position |
312 | 312 | * @param expectedMatch the expected match |
321 | 321 | |
322 | 322 | /** |
323 | 323 | * Checks that the given matcher matches the input as specified. |
324 | * | |
324 | * | |
325 | 325 | * @param matcher the matcher |
326 | 326 | * @param testCase the test string |
327 | 327 | */ |
371 | 371 | /** |
372 | 372 | * Creates a text case from a string. In the given string a '%' represents the position of the |
373 | 373 | * cursor and a '#' represents the position of the expected matching character. |
374 | * | |
374 | * | |
375 | 375 | * @param str the string for which to create the test case |
376 | 376 | * @return the created test case |
377 | 377 | */ |
+3
-3
25 | 25 | * @since 3.3 |
26 | 26 | */ |
27 | 27 | public class DefaultPairMatcherTest extends AbstractPairMatcherTest { |
28 | ||
28 | ||
29 | 29 | public DefaultPairMatcherTest() { |
30 | 30 | super(false); |
31 | 31 | } |
39 | 39 | |
40 | 40 | /** |
41 | 41 | * Close matches. |
42 | * | |
42 | * | |
43 | 43 | * @throws BadLocationException test failure |
44 | 44 | */ |
45 | 45 | @Test |
53 | 53 | |
54 | 54 | /** |
55 | 55 | * Checks of simple situations where no matches should be found. |
56 | * | |
56 | * | |
57 | 57 | * @throws BadLocationException test failure |
58 | 58 | */ |
59 | 59 | @Test |
+2
-2
19 | 19 | |
20 | 20 | /** |
21 | 21 | * Tests for the default pair matcher. |
22 | * | |
22 | * | |
23 | 23 | * @since 3.8 |
24 | 24 | */ |
25 | 25 | public class DefaultPairMatcherTest2 extends AbstractPairMatcherTest { |
37 | 37 | |
38 | 38 | /** |
39 | 39 | * Very simple checks. |
40 | * | |
40 | * | |
41 | 41 | * @throws BadLocationException test failure |
42 | 42 | */ |
43 | 43 | @Test |
+14
-14
91 | 91 | if (DEBUG) |
92 | 92 | System.out.println("<" + result + "/>"); |
93 | 93 | assertEquals(expectedOutput, result); |
94 | ||
94 | ||
95 | 95 | Iterator<StyleRange> styleRangeIterator= textPresentation.getAllStyleRangeIterator(); |
96 | 96 | List<StyleRange> ranges= new ArrayList<>(); |
97 | 97 | while (styleRangeIterator.hasNext()) { |
98 | 98 | ranges.add(styleRangeIterator.next()); |
99 | 99 | } |
100 | ||
100 | ||
101 | 101 | Collections.sort(ranges, (r1, r2) -> r1.start - r2.start); |
102 | ||
102 | ||
103 | 103 | assertEquals(Arrays.asList(styleRanges), ranges); |
104 | ||
104 | ||
105 | 105 | for (int i= 0; i < ranges.size() - 1; i++) { |
106 | 106 | StyleRange range1= ranges.get(i); |
107 | 107 | StyleRange range2= ranges.get(i + 1); |
108 | ||
108 | ||
109 | 109 | if (range1.start + range1.length > range2.start) { |
110 | 110 | assertTrue("StyleRanges overlap", false); |
111 | 111 | } |
112 | 112 | } |
113 | ||
113 | ||
114 | 114 | } |
115 | 115 | |
116 | 116 | @Test |
119 | 119 | String expected= "3<5"; |
120 | 120 | verify(string, expected, 0); |
121 | 121 | } |
122 | ||
122 | ||
123 | 123 | @Test |
124 | 124 | public void test1() throws IOException{ |
125 | 125 | String string= "<dl><dt>@author</dt><dd>Foo Bar</dd></dl>"; |
126 | 126 | String expected= LD+ "@author"+LD+"\tFoo Bar"+LD; |
127 | 127 | verify(string, expected, 1); |
128 | 128 | } |
129 | ||
129 | ||
130 | 130 | @Test |
131 | 131 | public void test2() throws IOException{ |
132 | 132 | String string= "<code>3>5<code>"; |
147 | 147 | String expected= "void p.Bb.fes()"+ LD + LD + LD+ "Parameters:"+ LD + "\ti fred or null"+LD; |
148 | 148 | verify(string, expected, 3); |
149 | 149 | } |
150 | ||
150 | ||
151 | 151 | @Test |
152 | 152 | public void test5() throws IOException{ |
153 | 153 | String string= "<code>1<2<3<4</code>"; |
162 | 162 | String expected= LD + "Something." + LD + "Something more."; |
163 | 163 | verify(string, expected, 0); |
164 | 164 | } |
165 | ||
165 | ||
166 | 166 | @Test |
167 | 167 | public void testEntity1() throws IOException { |
168 | 168 | String string= "&"; |
176 | 176 | String expected= "&unknown;"; |
177 | 177 | verify(string, expected, 0); |
178 | 178 | } |
179 | ||
179 | ||
180 | 180 | @Test |
181 | 181 | public void testBug367378() throws IOException { |
182 | 182 | verify("<head>", "", 0); |
196 | 196 | String expected= "no comment"; |
197 | 197 | verify(string, expected, 0); |
198 | 198 | } |
199 | ||
199 | ||
200 | 200 | @Test |
201 | 201 | public void testStyles1() throws IOException { |
202 | 202 | String string= "<b>Hello World</b>"; |
266 | 266 | String expected= "This is yet another test"; |
267 | 267 | verify(string, expected, 3); |
268 | 268 | } |
269 | ||
269 | ||
270 | 270 | @Test |
271 | 271 | public void testStylesWithPre() throws IOException { |
272 | 272 | String string= "I am <b>bold</b>." + LD + "<p>" + LD + "<pre>One" + LD + LD + "<b>T</b>hree.</pre>" + LD + "<p>" + LD + "<b>Author:</b> me."; |
278 | 278 | }; |
279 | 279 | verify(string, expected, ranges); |
280 | 280 | } |
281 | ||
281 | ||
282 | 282 | @Test |
283 | 283 | public void testCombineBoldItalicStriker() throws IOException { |
284 | 284 | String string= "<strong>strong</strong>,<em>italic</em>,<s>strike</s>," + |
+10
-2
0 | 0 | /******************************************************************************* |
1 | * Copyright (c) 2000, 2016 IBM Corporation and others. | |
1 | * Copyright (c) 2000, 2019 IBM Corporation and others. | |
2 | 2 | * |
3 | 3 | * This program and the accompanying materials |
4 | 4 | * are made available under the terms of the Eclipse Public License 2.0 |
19 | 19 | import org.eclipse.jface.text.tests.codemining.CodeMiningProjectionViewerTest; |
20 | 20 | import org.eclipse.jface.text.tests.codemining.CodeMiningTest; |
21 | 21 | import org.eclipse.jface.text.tests.contentassist.AsyncContentAssistTest; |
22 | import org.eclipse.jface.text.tests.contentassist.ContextInformationPresenterTest; | |
23 | import org.eclipse.jface.text.tests.contentassist.ContextInformationTest; | |
24 | import org.eclipse.jface.text.tests.contentassist.FilteringAsyncContentAssistTests; | |
22 | 25 | import org.eclipse.jface.text.tests.reconciler.AbstractReconcilerTest; |
23 | 26 | import org.eclipse.jface.text.tests.rules.DefaultPartitionerTest; |
24 | 27 | import org.eclipse.jface.text.tests.rules.DefaultPartitionerZeroLengthTest; |
48 | 51 | DefaultPairMatcherTest.class, |
49 | 52 | DefaultPairMatcherTest2.class, |
50 | 53 | AsyncContentAssistTest.class, |
54 | FilteringAsyncContentAssistTests.class, | |
55 | ContextInformationTest.class, | |
56 | ContextInformationPresenterTest.class, | |
51 | 57 | |
52 | 58 | AbstractReconcilerTest.class, |
53 | 59 | |
61 | 67 | LineContentBoundsDrawingTest.class, |
62 | 68 | AnnotationOnTabTest.class, |
63 | 69 | CodeMiningTest.class, |
64 | CodeMiningProjectionViewerTest.class | |
70 | CodeMiningProjectionViewerTest.class, | |
71 | ||
72 | TabsToSpacesConverterTest.class, | |
65 | 73 | }) |
66 | 74 | public class JFaceTextTestSuite { |
67 | 75 | // see @SuiteClasses |
+201
-0
0 | /******************************************************************************* | |
1 | * Copyright (c) 2019 Mateusz Matela 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 | * Mateusz Matela - initial API and implementation | |
12 | *******************************************************************************/ | |
13 | package org.eclipse.jface.text.tests; | |
14 | ||
15 | import static org.junit.Assert.assertEquals; | |
16 | ||
17 | import org.junit.Test; | |
18 | ||
19 | import org.eclipse.swt.SWT; | |
20 | import org.eclipse.swt.widgets.Shell; | |
21 | ||
22 | import org.eclipse.jface.text.BadLocationException; | |
23 | import org.eclipse.jface.text.DefaultLineTracker; | |
24 | import org.eclipse.jface.text.Document; | |
25 | import org.eclipse.jface.text.Position; | |
26 | import org.eclipse.jface.text.TabsToSpacesConverter; | |
27 | import org.eclipse.jface.text.TextViewer; | |
28 | import org.eclipse.jface.text.source.projection.ProjectionAnnotation; | |
29 | import org.eclipse.jface.text.source.projection.ProjectionAnnotationModel; | |
30 | import org.eclipse.jface.text.source.projection.ProjectionViewer; | |
31 | ||
32 | public class TabsToSpacesConverterTest { | |
33 | ||
34 | private void doTest(String input, String output, int keyCode, int tabWidth) { | |
35 | Shell shell= new Shell(); | |
36 | TextViewer textViewer= new TextViewer(shell, SWT.NONE); | |
37 | ||
38 | TabsToSpacesConverter tabToSpacesConverter= new TabsToSpacesConverter(); | |
39 | tabToSpacesConverter.setLineTracker(new DefaultLineTracker()); | |
40 | tabToSpacesConverter.setNumberOfSpacesPerTab(tabWidth); | |
41 | tabToSpacesConverter.setDeleteSpacesAsTab(true); | |
42 | textViewer.setTabsToSpacesConverter(tabToSpacesConverter); | |
43 | ||
44 | int selectionFrom= input.indexOf('|'); | |
45 | int selectionTo= input.indexOf('|', selectionFrom + 1) - 1; | |
46 | Document document= new Document(input.replace("|", "")); | |
47 | textViewer.setDocument(document); | |
48 | textViewer.setSelectedRange(selectionFrom, selectionTo - selectionFrom); | |
49 | ||
50 | TextViewerTest.postKeyEvent(textViewer.getTextWidget(), keyCode, SWT.NONE, SWT.KeyDown); | |
51 | ||
52 | assertEquals(output, document.get()); | |
53 | } | |
54 | ||
55 | @Test | |
56 | public void testDelete1() { | |
57 | doTest("|| ABC", " ABC", SWT.DEL, 4); | |
58 | } | |
59 | ||
60 | @Test | |
61 | public void testDelete2() { | |
62 | doTest(" || ABC", " ABC", SWT.DEL, 4); | |
63 | } | |
64 | ||
65 | @Test | |
66 | public void testDelete3() { | |
67 | doTest(" || ABC", " ABC", SWT.DEL, 4); | |
68 | } | |
69 | ||
70 | @Test | |
71 | public void testDelete4() { | |
72 | doTest(" || ABC", " ABC", SWT.DEL, 4); | |
73 | } | |
74 | ||
75 | @Test | |
76 | public void testDeleteRange1() { | |
77 | doTest(" | | ABC", " ABC", SWT.DEL, 4); | |
78 | } | |
79 | ||
80 | @Test | |
81 | public void testDeleteRange2() { | |
82 | doTest(" | | ABC", " ABC", SWT.DEL, 4); | |
83 | } | |
84 | ||
85 | @Test | |
86 | public void testDeleteInside1() { | |
87 | doTest(" ABCD|| EFG", " ABCDEFG", SWT.DEL, 4); | |
88 | } | |
89 | ||
90 | @Test | |
91 | public void testDeleteInside2() { | |
92 | doTest(" ABCD || EFG", " ABCD EFG", SWT.DEL, 4); | |
93 | } | |
94 | ||
95 | @Test | |
96 | public void testDeleteInside3() { | |
97 | doTest(" ABCD|| EFG", " ABCDEFG", SWT.DEL, 4); | |
98 | } | |
99 | ||
100 | @Test | |
101 | public void testDeleteLargeWidth1() { | |
102 | doTest(" || ABC", " ABC", SWT.DEL, 10); | |
103 | } | |
104 | ||
105 | @Test | |
106 | public void testDeleteLargeWidth2() { | |
107 | doTest(" || ABC", " ABC", SWT.DEL, 10); | |
108 | } | |
109 | ||
110 | @Test | |
111 | public void testDeleteSmallWidth() { | |
112 | doTest(" || ABC", " ABC", SWT.DEL, 2); | |
113 | } | |
114 | ||
115 | @Test | |
116 | public void testBackspace1() { | |
117 | doTest(" || ABC", " ABC", SWT.BS, 4); | |
118 | } | |
119 | ||
120 | @Test | |
121 | public void testBackspace2() { | |
122 | doTest(" ||ABC", " ABC", SWT.BS, 4); | |
123 | } | |
124 | ||
125 | @Test | |
126 | public void testBackspace3() { | |
127 | doTest(" || ABC", " ABC", SWT.BS, 4); | |
128 | } | |
129 | ||
130 | @Test | |
131 | public void testBackspace4() { | |
132 | doTest(" || ABC", " ABC", SWT.BS, 4); | |
133 | } | |
134 | ||
135 | @Test | |
136 | public void testBackspaceRange1() { | |
137 | doTest(" | | ABC", " ABC", SWT.BS, 4); | |
138 | } | |
139 | ||
140 | @Test | |
141 | public void testBackspaceRange2() { | |
142 | doTest(" | | ABC", " ABC", SWT.BS, 4); | |
143 | } | |
144 | ||
145 | @Test | |
146 | public void testBackspaceInside1() { | |
147 | doTest(" ABCD ||EFG", " ABCDEFG", SWT.BS, 4); | |
148 | } | |
149 | ||
150 | @Test | |
151 | public void testBackspaceInside2() { | |
152 | doTest(" ABCD ||EFG", " ABCD EFG", SWT.BS, 4); | |
153 | } | |
154 | ||
155 | @Test | |
156 | public void testBackspaceInside3() { | |
157 | doTest(" ABCDEF ||G", " ABCDEFG", SWT.BS, 4); | |
158 | } | |
159 | ||
160 | @Test | |
161 | public void testBackspaceLargeWidth1() { | |
162 | doTest(" || ABC", " ABC", SWT.BS, 10); | |
163 | } | |
164 | ||
165 | @Test | |
166 | public void testBackspaceLargeWidth2() { | |
167 | doTest(" || ABC", " ABC", SWT.BS, 10); | |
168 | } | |
169 | ||
170 | @Test | |
171 | public void testBackspaceSmallWidth() { | |
172 | doTest(" || ABC", " ABC", SWT.BS, 2); | |
173 | } | |
174 | ||
175 | @Test | |
176 | public void testDeleteAfterCollapsedRegion() throws BadLocationException { | |
177 | Shell shell= new Shell(); | |
178 | ProjectionViewer textViewer= new ProjectionViewer(shell, null, null, false, SWT.NONE); | |
179 | ||
180 | TabsToSpacesConverter tabToSpacesConverter= new TabsToSpacesConverter(); | |
181 | tabToSpacesConverter.setLineTracker(new DefaultLineTracker()); | |
182 | tabToSpacesConverter.setNumberOfSpacesPerTab(4); | |
183 | tabToSpacesConverter.setDeleteSpacesAsTab(true); | |
184 | textViewer.setTabsToSpacesConverter(tabToSpacesConverter); | |
185 | ||
186 | Document document= new Document(" COLLAPSED!!!\n REGION!!!\n VISIBLE\n REGION"); | |
187 | int caretPosition= document.get().indexOf("VISIBLE") - 4; | |
188 | textViewer.setDocument(document, new ProjectionAnnotationModel()); | |
189 | textViewer.enableProjection(); | |
190 | textViewer.setSelectedRange(caretPosition, 0); | |
191 | ||
192 | ProjectionAnnotation annotation= new ProjectionAnnotation(true); | |
193 | textViewer.getProjectionAnnotationModel().addAnnotation(annotation, new Position(0, document.getLineOffset(2))); | |
194 | textViewer.doOperation(ProjectionViewer.COLLAPSE_ALL); | |
195 | ||
196 | TextViewerTest.postKeyEvent(textViewer.getTextWidget(), SWT.DEL, SWT.NONE, SWT.KeyDown); | |
197 | ||
198 | assertEquals(" COLLAPSED!!!\n REGION!!!\nVISIBLE\n REGION", document.get()); | |
199 | } | |
200 | } |
+2
-2
86 | 86 | |
87 | 87 | /** |
88 | 88 | * Creates a new color. |
89 | * | |
89 | * | |
90 | 90 | * @param red the amount of red in the color |
91 | 91 | * @param green the amount of green in the color |
92 | 92 | * @param blue the amount of blue in the color |
118 | 118 | public void testUnclippedRegions() { |
119 | 119 | checkRegions(fAllRanges, fNonDefaultRanges); |
120 | 120 | } |
121 | ||
121 | ||
122 | 122 | @Test |
123 | 123 | public void testClippedRegions1() { |
124 | 124 | fTextPresentation.setResultWindow(new Region(0, 140)); |
10 | 10 | * Contributors: |
11 | 11 | * Sergey Prigogin (Google) - initial API and implementation |
12 | 12 | * Mickael Istria (Red Hat Inc.) - [Bug 544708] Ctrl+Home |
13 | * Paul Pazderski - [Bug 545530] Test for TextViewer's default IDocumentAdapter implementation. | |
13 | * Paul Pazderski - [Bug 545530] Test for TextViewer's default IDocumentAdapter implementation. | |
14 | 14 | *******************************************************************************/ |
15 | 15 | package org.eclipse.jface.text.tests; |
16 | 16 | |
26 | 26 | import org.junit.Test; |
27 | 27 | |
28 | 28 | import org.eclipse.swt.SWT; |
29 | import org.eclipse.swt.custom.StyledText; | |
29 | 30 | import org.eclipse.swt.custom.StyledTextContent; |
30 | 31 | import org.eclipse.swt.layout.FillLayout; |
31 | 32 | import org.eclipse.swt.widgets.Control; |
34 | 35 | import org.eclipse.swt.widgets.Listener; |
35 | 36 | import org.eclipse.swt.widgets.Shell; |
36 | 37 | |
38 | import org.eclipse.core.runtime.IStatus; | |
39 | import org.eclipse.core.runtime.Status; | |
40 | import org.eclipse.core.runtime.jobs.Job; | |
41 | ||
37 | 42 | import org.eclipse.jface.util.Util; |
38 | 43 | |
44 | import org.eclipse.jface.text.BlockTextSelection; | |
39 | 45 | import org.eclipse.jface.text.Document; |
46 | import org.eclipse.jface.text.IDocument; | |
40 | 47 | import org.eclipse.jface.text.IDocumentAdapter; |
48 | import org.eclipse.jface.text.IDocumentExtension3; | |
49 | import org.eclipse.jface.text.ITextOperationTarget; | |
50 | import org.eclipse.jface.text.ITextSelection; | |
41 | 51 | import org.eclipse.jface.text.ITextViewer; |
42 | 52 | import org.eclipse.jface.text.TextViewer; |
43 | 53 | import org.eclipse.jface.text.source.SourceViewer; |
71 | 81 | assertEquals(0, textViewer.getTextWidget().getCaretOffset()); |
72 | 82 | } finally { |
73 | 83 | shell.dispose(); |
84 | } | |
85 | } | |
86 | ||
87 | @Test | |
88 | public void testCaretMoveChangesSelection() throws Exception { | |
89 | Shell shell= new Shell(); | |
90 | try { | |
91 | TextViewer textViewer= new TextViewer(shell, SWT.NONE); | |
92 | Document document= new Document("abc"); | |
93 | textViewer.setDocument(document); | |
94 | int len= document.getLength(); | |
95 | // Select the whole document with the caret at the beginning. | |
96 | textViewer.setSelectedRange(0, len); | |
97 | ITextSelection selection = (ITextSelection)textViewer.getSelectionProvider().getSelection(); | |
98 | assertEquals(0, selection.getOffset()); | |
99 | assertEquals(len, selection.getLength()); | |
100 | textViewer.getTextWidget().setCaretOffset(1); | |
101 | selection = (ITextSelection)textViewer.getSelectionProvider().getSelection(); | |
102 | assertEquals(1, selection.getOffset()); | |
103 | assertEquals(0, selection.getLength()); | |
104 | } finally { | |
105 | shell.dispose(); | |
106 | } | |
107 | } | |
108 | ||
109 | @Test | |
110 | public void testGetCachedSelection() throws Exception { | |
111 | Shell shell= new Shell(); | |
112 | try { | |
113 | TextViewer textViewer= new TextViewer(shell, SWT.NONE); | |
114 | Document document= new Document("abc"); | |
115 | textViewer.setDocument(document); | |
116 | int len= document.getLength(); | |
117 | // Select the whole document with the caret at the beginning. | |
118 | textViewer.setSelectedRange(0, len); | |
119 | checkInAndOutUIThread(() -> { | |
120 | ITextSelection selection = textViewer.getLastKnownSelection(); | |
121 | assertEquals(0, selection.getOffset()); | |
122 | assertEquals(len, selection.getLength()); | |
123 | }); | |
124 | } finally { | |
125 | shell.dispose(); | |
126 | } | |
127 | } | |
128 | ||
129 | @Test | |
130 | public void testBlockSelectionAccessors() throws Exception { | |
131 | Shell shell= new Shell(); | |
132 | try { | |
133 | ITextViewer textViewer= new TextViewer(shell, SWT.NONE); | |
134 | Document document= new Document("0123\n4567\n89ab\ncdef"); | |
135 | textViewer.setDocument(document); | |
136 | // Select the whole document with the caret at the beginning. | |
137 | StyledText textWidget= textViewer.getTextWidget(); | |
138 | textWidget.setBlockSelection(true); | |
139 | shell.setLayout(new FillLayout()); | |
140 | shell.open(); | |
141 | textViewer.getSelectionProvider().setSelection(new BlockTextSelection(textViewer.getDocument(), 1, 1, 2, 2, textWidget.getTabs())); | |
142 | BlockTextSelection sel = (BlockTextSelection)textViewer.getSelectionProvider().getSelection(); | |
143 | assertEquals(1, sel.getStartLine()); | |
144 | assertEquals(2, sel.getEndLine()); | |
145 | assertEquals(1, sel.getStartColumn()); | |
146 | assertEquals(2, sel.getEndColumn()); | |
147 | } finally { | |
148 | shell.dispose(); | |
149 | } | |
150 | } | |
151 | ||
152 | ||
153 | private void checkInAndOutUIThread(Runnable r) throws InterruptedException { | |
154 | // first run in UI Thread, forward exceptions | |
155 | r.run(); | |
156 | // then run in non-UI Thread | |
157 | Job job = Job.create("Check in non-UI Thread", monitor -> { | |
158 | try { | |
159 | r.run(); | |
160 | return Status.OK_STATUS; | |
161 | } catch (Throwable t) { | |
162 | return new Status(IStatus.ERROR, "org.eclipse.jface.text.tests", t.getMessage(), t); | |
163 | } | |
164 | }); | |
165 | job.schedule(); | |
166 | job.join(); | |
167 | if (!job.getResult().isOK()) { | |
168 | Throwable ex = job.getResult().getException(); | |
169 | if (ex != null) { | |
170 | throw new AssertionError("Assertion fail in non-UI Thread", ex); | |
171 | } else { | |
172 | fail(job.getResult().toString()); | |
173 | } | |
74 | 174 | } |
75 | 175 | } |
76 | 176 | |
194 | 294 | postKeyEvent(viewer.getTextWidget(), SWT.HOME, SWT.CTRL, SWT.KeyDown); |
195 | 295 | } |
196 | 296 | |
197 | private static void postKeyEvent(Control widget, int keyCode, int stateMask, int type) { | |
297 | static void postKeyEvent(Control widget, int keyCode, int stateMask, int type) { | |
198 | 298 | Display display= widget.getDisplay(); |
199 | 299 | widget.setFocus(); |
200 | 300 | DisplayHelper.driveEventQueue(display); |
220 | 320 | b.append("end"); |
221 | 321 | return b.toString(); |
222 | 322 | } |
323 | ||
324 | @Test | |
325 | public void testShiftLeft() { | |
326 | Shell shell= new Shell(); | |
327 | try { | |
328 | TextViewer textViewer= new TextViewer(shell, SWT.NONE); | |
329 | { | |
330 | // Normal case, both lines match prefix | |
331 | Document document= new Document("//line1\n//line2"); | |
332 | textViewer.setDocumentPartitioning(IDocumentExtension3.DEFAULT_PARTITIONING); | |
333 | textViewer.setDocument(document); | |
334 | textViewer.setDefaultPrefixes(new String[] { "//" }, IDocument.DEFAULT_CONTENT_TYPE); | |
335 | ||
336 | textViewer.doOperation(ITextOperationTarget.SELECT_ALL); | |
337 | textViewer.doOperation(ITextOperationTarget.STRIP_PREFIX); | |
338 | ||
339 | assertEquals("line1\nline2", textViewer.getDocument().get()); | |
340 | } | |
341 | { | |
342 | // Don't shift anything, as 2nd line does not match any prefix | |
343 | Document document= new Document("//line1\nline2"); | |
344 | textViewer.setDocumentPartitioning(IDocumentExtension3.DEFAULT_PARTITIONING); | |
345 | textViewer.setDocument(document); | |
346 | textViewer.setDefaultPrefixes(new String[] { "//" }, IDocument.DEFAULT_CONTENT_TYPE); | |
347 | ||
348 | textViewer.doOperation(ITextOperationTarget.SELECT_ALL); | |
349 | textViewer.doOperation(ITextOperationTarget.STRIP_PREFIX); | |
350 | ||
351 | assertEquals("//line1\nline2", textViewer.getDocument().get()); | |
352 | } | |
353 | { | |
354 | // Shift line1, since line2 matches the allowed empty prefix | |
355 | Document document= new Document("//line1\nline2"); | |
356 | textViewer.setDocumentPartitioning(IDocumentExtension3.DEFAULT_PARTITIONING); | |
357 | textViewer.setDocument(document); | |
358 | textViewer.setDefaultPrefixes(new String[] { "//", "" }, IDocument.DEFAULT_CONTENT_TYPE); | |
359 | ||
360 | textViewer.doOperation(ITextOperationTarget.SELECT_ALL); | |
361 | textViewer.doOperation(ITextOperationTarget.STRIP_PREFIX); | |
362 | ||
363 | assertEquals("line1\nline2", textViewer.getDocument().get()); | |
364 | } | |
365 | } finally { | |
366 | shell.dispose(); | |
367 | } | |
368 | } | |
223 | 369 | } |
+3
-3
94 | 94 | |
95 | 95 | undoManager.disconnect(newContext); |
96 | 96 | } |
97 | ||
97 | ||
98 | 98 | @Test |
99 | 99 | public void testTransferNonUndoableNonTextOp() throws Exception { |
100 | 100 | internalTestTransferNonTextOp(false); |
101 | 101 | } |
102 | ||
102 | ||
103 | 103 | @Test |
104 | 104 | public void testTransferUndoableNonTextOp() throws Exception { |
105 | 105 | internalTestTransferNonTextOp(true); |
106 | 106 | } |
107 | ||
107 | ||
108 | 108 | @Test |
109 | 109 | public void testCanUndo() throws Exception { |
110 | 110 | IDocument doc= new Document(); |
+1
-1
194 | 194 | } |
195 | 195 | |
196 | 196 | @Test |
197 | public void testCodeMiningMultiLine() throws BadLocationException { | |
197 | public void testCodeMiningMultiLine() { | |
198 | 198 | fViewer.getDocument().set("a\nbc"); |
199 | 199 | fViewer.setCodeMiningProviders(new ICodeMiningProvider[] { new ICodeMiningProvider() { |
200 | 200 | @Override |
+173
-0
0 | /******************************************************************************* | |
1 | * Copyright (c) 2019 Stephan Wahlbrink 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 | * Stephan Wahlbrink <sw@wahlbrink.eu> | |
12 | *******************************************************************************/ | |
13 | ||
14 | package org.eclipse.jface.text.tests.contentassist; | |
15 | ||
16 | import static org.junit.Assert.assertEquals; | |
17 | import static org.junit.Assert.assertTrue; | |
18 | ||
19 | import java.util.Arrays; | |
20 | import java.util.Collection; | |
21 | import java.util.List; | |
22 | import java.util.stream.Collectors; | |
23 | ||
24 | import org.junit.After; | |
25 | import org.junit.Assert; | |
26 | ||
27 | import org.eclipse.swt.SWT; | |
28 | import org.eclipse.swt.custom.StyledText; | |
29 | import org.eclipse.swt.layout.FillLayout; | |
30 | import org.eclipse.swt.widgets.Event; | |
31 | import org.eclipse.swt.widgets.Shell; | |
32 | ||
33 | import org.eclipse.jface.text.Document; | |
34 | import org.eclipse.jface.text.ITextOperationTarget; | |
35 | import org.eclipse.jface.text.contentassist.ContentAssistant; | |
36 | import org.eclipse.jface.text.contentassist.IContentAssistant; | |
37 | import org.eclipse.jface.text.source.ISourceViewer; | |
38 | import org.eclipse.jface.text.source.SourceViewer; | |
39 | import org.eclipse.jface.text.source.SourceViewerConfiguration; | |
40 | import org.eclipse.jface.text.tests.util.DisplayHelper; | |
41 | ||
42 | ||
43 | public class AbstractContentAssistTest { | |
44 | ||
45 | ||
46 | private Shell shell; | |
47 | private SourceViewer viewer; | |
48 | private ContentAssistant assistant; | |
49 | private Document document; | |
50 | ||
51 | ||
52 | public AbstractContentAssistTest() { | |
53 | } | |
54 | ||
55 | ||
56 | @After | |
57 | public void close() { | |
58 | if (shell != null && !shell.isDisposed()) { | |
59 | shell.close(); | |
60 | } | |
61 | } | |
62 | ||
63 | ||
64 | protected void setupSourceViewer(ContentAssistant contentAssistant, String initialText) { | |
65 | shell= new Shell(); | |
66 | shell.setSize(500, 240); | |
67 | shell.setLayout(new FillLayout()); | |
68 | ||
69 | viewer= new SourceViewer(shell, null, SWT.NONE); | |
70 | assistant= contentAssistant; | |
71 | viewer.configure(createSourceViewerConfiguration()); | |
72 | ||
73 | document= new Document(); | |
74 | if (initialText != null) { | |
75 | document.set(initialText); | |
76 | } | |
77 | viewer.setDocument(document); | |
78 | ||
79 | shell.open(); | |
80 | Assert.assertTrue(new DisplayHelper() { | |
81 | @Override | |
82 | protected boolean condition() { | |
83 | return viewer.getTextWidget().isVisible(); | |
84 | } | |
85 | }.waitForCondition(shell.getDisplay(), 3000)); | |
86 | } | |
87 | ||
88 | protected SourceViewerConfiguration createSourceViewerConfiguration() { | |
89 | return new SourceViewerConfiguration() { | |
90 | @Override | |
91 | public IContentAssistant getContentAssistant(ISourceViewer sourceViewer) { | |
92 | return AbstractContentAssistTest.this.getContentAssistant(); | |
93 | } | |
94 | }; | |
95 | } | |
96 | ||
97 | protected SourceViewer getSourceViewer() { | |
98 | return viewer; | |
99 | } | |
100 | ||
101 | protected Document getDocument() { | |
102 | return document; | |
103 | } | |
104 | ||
105 | protected ContentAssistant getContentAssistant() { | |
106 | return assistant; | |
107 | } | |
108 | ||
109 | protected void selectAndReveal(int selectionStart, int selectionLength) { | |
110 | StyledText widget= viewer.getTextWidget(); | |
111 | widget.setRedraw(false); | |
112 | ||
113 | viewer.revealRange(selectionStart, selectionLength); | |
114 | viewer.setSelectedRange(selectionStart, selectionLength); | |
115 | ||
116 | widget.setRedraw(true); | |
117 | } | |
118 | ||
119 | protected void postSourceViewerKeyEvent(int keyCode, int stateMask, int type) { | |
120 | processEvents(); | |
121 | Event event= new Event(); | |
122 | event.type= type; | |
123 | event.widget= viewer.getTextWidget(); | |
124 | event.display= viewer.getTextWidget().getDisplay(); | |
125 | event.keyCode= keyCode; | |
126 | event.stateMask= stateMask; | |
127 | event.doit= true; | |
128 | viewer.getTextWidget().notifyListeners(type, event); | |
129 | processEvents(); | |
130 | } | |
131 | ||
132 | protected void runTextOperation(int operation) { | |
133 | ITextOperationTarget textOperationTarget= viewer.getTextOperationTarget(); | |
134 | ||
135 | assertTrue(textOperationTarget.canDoOperation(operation)); | |
136 | textOperationTarget.doOperation(operation); | |
137 | } | |
138 | ||
139 | protected void triggerContextInformation() { | |
140 | runTextOperation(ISourceViewer.CONTENTASSIST_CONTEXT_INFORMATION); | |
141 | } | |
142 | ||
143 | ||
144 | protected void processEvents() { | |
145 | DisplayHelper.driveEventQueue(shell.getDisplay()); | |
146 | } | |
147 | ||
148 | protected List<Shell> getCurrentShells() { | |
149 | return Arrays.stream(shell.getDisplay().getShells()) | |
150 | .filter(Shell::isVisible) | |
151 | .collect(Collectors.toList()); | |
152 | } | |
153 | ||
154 | protected List<Shell> findNewShells(Collection<Shell> beforeShells) { | |
155 | return Arrays.stream(shell.getDisplay().getShells()) | |
156 | .filter(Shell::isVisible) | |
157 | .filter(shell -> !beforeShells.contains(shell)) | |
158 | .collect(Collectors.toList()); | |
159 | } | |
160 | ||
161 | protected Shell findNewShell(Collection<Shell> beforeShells) { | |
162 | DisplayHelper.sleep(shell.getDisplay(), 100); | |
163 | List<Shell> afterShells= findNewShells(beforeShells); | |
164 | if (afterShells.isEmpty()) { | |
165 | DisplayHelper.sleep(shell.getDisplay(), 1000); | |
166 | } | |
167 | afterShells= findNewShells(beforeShells); | |
168 | assertEquals("No new shell found", 1, afterShells.size()); | |
169 | return afterShells.get(0); | |
170 | } | |
171 | ||
172 | } |
+181
-0
0 | /******************************************************************************* | |
1 | * Copyright (c) 2016, 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 | * Stephan Wahlbrink <sw@wahlbrink.eu> - Bug 512251 - Fix IllegalArgumentException in ContextInformationPopup | |
13 | *******************************************************************************/ | |
14 | ||
15 | package org.eclipse.jface.text.tests.contentassist; | |
16 | ||
17 | import java.util.Arrays; | |
18 | ||
19 | import org.eclipse.swt.graphics.Image; | |
20 | ||
21 | import org.eclipse.jface.text.BadLocationException; | |
22 | import org.eclipse.jface.text.IDocument; | |
23 | import org.eclipse.jface.text.IRegion; | |
24 | import org.eclipse.jface.text.ITextViewer; | |
25 | import org.eclipse.jface.text.contentassist.CompletionProposal; | |
26 | import org.eclipse.jface.text.contentassist.ICompletionProposal; | |
27 | import org.eclipse.jface.text.contentassist.IContentAssistProcessor; | |
28 | import org.eclipse.jface.text.contentassist.IContextInformation; | |
29 | import org.eclipse.jface.text.contentassist.IContextInformationExtension; | |
30 | import org.eclipse.jface.text.contentassist.IContextInformationValidator; | |
31 | ||
32 | ||
33 | public class BarContentAssistProcessor implements IContentAssistProcessor { | |
34 | ||
35 | public static final String PROPOSAL= "bars are good for a beer."; | |
36 | ||
37 | protected static class BarContextInformation implements IContextInformation, IContextInformationExtension { | |
38 | ||
39 | private String contextDisplayString; | |
40 | ||
41 | private String informationDisplayString; | |
42 | ||
43 | private int offset; | |
44 | ||
45 | public BarContextInformation(String contextDisplayString, String informationDisplayString, int offset) { | |
46 | this.contextDisplayString= contextDisplayString; | |
47 | this.informationDisplayString= informationDisplayString; | |
48 | this.offset= offset; | |
49 | } | |
50 | ||
51 | @Override | |
52 | public String getContextDisplayString() { | |
53 | return contextDisplayString; | |
54 | } | |
55 | ||
56 | @Override | |
57 | public Image getImage() { | |
58 | return null; | |
59 | } | |
60 | ||
61 | @Override | |
62 | public String getInformationDisplayString() { | |
63 | return informationDisplayString; | |
64 | } | |
65 | ||
66 | @Override | |
67 | public int getContextInformationPosition() { | |
68 | return offset; | |
69 | } | |
70 | ||
71 | } | |
72 | ||
73 | protected static class ContextInformationValidator implements IContextInformationValidator { | |
74 | ||
75 | protected BarContextInformation info; | |
76 | ||
77 | protected ITextViewer viewer; | |
78 | ||
79 | protected int offset; | |
80 | ||
81 | @Override | |
82 | public void install(IContextInformation info, ITextViewer viewer, int offset) { | |
83 | if (info instanceof BarContextInformation) { | |
84 | this.info= (BarContextInformation) info; | |
85 | } | |
86 | this.viewer= viewer; | |
87 | this.offset= offset; | |
88 | } | |
89 | ||
90 | @Override | |
91 | public boolean isContextInformationValid(int offset) { | |
92 | if (this.info == null) { | |
93 | return false; | |
94 | } | |
95 | try { | |
96 | IDocument document= viewer.getDocument(); | |
97 | IRegion line= document.getLineInformationOfOffset(this.offset); | |
98 | int end= line.getOffset() + line.getLength(); | |
99 | return (offset >= this.offset && offset < end); | |
100 | } catch (BadLocationException e) { | |
101 | return false; | |
102 | } | |
103 | } | |
104 | } | |
105 | ||
106 | ||
107 | private final String completeString; | |
108 | ||
109 | public BarContentAssistProcessor() { | |
110 | this(PROPOSAL); | |
111 | } | |
112 | ||
113 | public BarContentAssistProcessor(String completeString) { | |
114 | this.completeString= completeString; | |
115 | } | |
116 | ||
117 | @Override | |
118 | public ICompletionProposal[] computeCompletionProposals(ITextViewer viewer, int offset) { | |
119 | for (int offsetInProposal= Math.min(this.completeString.length(), viewer.getDocument().getLength()); offsetInProposal > 0; offsetInProposal--) { | |
120 | String maybeMatchingString= this.completeString.substring(0, offsetInProposal); | |
121 | try { | |
122 | int lastIndex= offset - offsetInProposal + this.completeString.length(); | |
123 | if (offset >= offsetInProposal && viewer.getDocument().get(offset - offsetInProposal, maybeMatchingString.length()).equals(maybeMatchingString)) { | |
124 | CompletionProposal proposal= new CompletionProposal(this.completeString.substring(offsetInProposal), offset, 0, lastIndex); | |
125 | return new ICompletionProposal[] { proposal }; | |
126 | } | |
127 | } catch (BadLocationException e) { | |
128 | e.printStackTrace(); | |
129 | } | |
130 | } | |
131 | return new ICompletionProposal[0]; | |
132 | } | |
133 | ||
134 | @Override | |
135 | public char[] getCompletionProposalAutoActivationCharacters() { | |
136 | return null; | |
137 | } | |
138 | ||
139 | @Override | |
140 | public char[] getContextInformationAutoActivationCharacters() { | |
141 | return null; | |
142 | } | |
143 | ||
144 | /** | |
145 | * Creates context info "idx= <word index in #PROPOSAL>" at the end of a word. | |
146 | **/ | |
147 | @Override | |
148 | public IContextInformation[] computeContextInformation(ITextViewer viewer, int offset) { | |
149 | try { | |
150 | IDocument document= viewer.getDocument(); | |
151 | int wordBegin= offset; | |
152 | while (wordBegin > 0 && Character.isLetterOrDigit(document.getChar(wordBegin - 1))) { | |
153 | wordBegin--; | |
154 | } | |
155 | if (wordBegin < offset) { | |
156 | String word= document.get(wordBegin, offset - wordBegin); | |
157 | int wordIdx= Arrays.asList(completeString.split("\\W")).indexOf(word); | |
158 | if (wordIdx >= 0) { | |
159 | return new IContextInformation[] { | |
160 | new BarContextInformation(word, "idx= " + wordIdx, wordBegin) | |
161 | }; | |
162 | } | |
163 | } | |
164 | } catch (BadLocationException e) { | |
165 | e.printStackTrace(); | |
166 | } | |
167 | return null; | |
168 | } | |
169 | ||
170 | @Override | |
171 | public IContextInformationValidator getContextInformationValidator() { | |
172 | return new ContextInformationValidator(); | |
173 | } | |
174 | ||
175 | @Override | |
176 | public String getErrorMessage() { | |
177 | return null; | |
178 | } | |
179 | ||
180 | } |
+127
-0
0 | /******************************************************************************* | |
1 | * Copyright (c) 2017, 2019 Stephan Wahlbrink 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 | * Stephan Wahlbrink <sw@wahlbrink.eu> | |
12 | *******************************************************************************/ | |
13 | package org.eclipse.jface.text.tests.contentassist; | |
14 | ||
15 | import static org.eclipse.jface.text.tests.contentassist.ContextInformationTest.getInfoText; | |
16 | import static org.junit.Assert.assertArrayEquals; | |
17 | import static org.junit.Assert.assertEquals; | |
18 | import static org.junit.Assert.assertTrue; | |
19 | ||
20 | import java.util.List; | |
21 | ||
22 | import org.junit.Test; | |
23 | ||
24 | import org.eclipse.swt.SWT; | |
25 | import org.eclipse.swt.custom.StyleRange; | |
26 | import org.eclipse.swt.custom.StyledText; | |
27 | import org.eclipse.swt.widgets.Control; | |
28 | import org.eclipse.swt.widgets.Shell; | |
29 | import org.eclipse.swt.widgets.Text; | |
30 | ||
31 | import org.eclipse.jface.text.IDocument; | |
32 | import org.eclipse.jface.text.TextPresentation; | |
33 | import org.eclipse.jface.text.contentassist.ContentAssistant; | |
34 | import org.eclipse.jface.text.contentassist.IContextInformationPresenter; | |
35 | import org.eclipse.jface.text.contentassist.IContextInformationValidator; | |
36 | ||
37 | ||
38 | public class ContextInformationPresenterTest extends AbstractContentAssistTest { | |
39 | ||
40 | private static class ValidatorWithPresenter extends BarContentAssistProcessor.ContextInformationValidator | |
41 | implements IContextInformationPresenter { | |
42 | ||
43 | private boolean isStyled; | |
44 | ||
45 | /** | |
46 | * Hightlight (bold) "idx" if caret is inside the word (including end) | |
47 | */ | |
48 | @Override | |
49 | public boolean updatePresentation(int offset, TextPresentation presentation) { | |
50 | if (info == null) { // Ignore unknown information | |
51 | return false; | |
52 | } | |
53 | ||
54 | int begin= info.getContextInformationPosition(); | |
55 | int end= begin + info.getContextDisplayString().length(); | |
56 | boolean style= (offset >= begin && offset <= end); | |
57 | if (style == isStyled) { | |
58 | return false; | |
59 | } | |
60 | if (style) { | |
61 | presentation.clear(); | |
62 | presentation.addStyleRange(new StyleRange(0, 3, null, null, SWT.BOLD)); | |
63 | } else { | |
64 | presentation.clear(); | |
65 | } | |
66 | isStyled= style; | |
67 | return true; | |
68 | } | |
69 | ||
70 | } | |
71 | ||
72 | ||
73 | private Shell infoShell; | |
74 | ||
75 | ||
76 | private ContentAssistant createBarContentAssist() { | |
77 | ContentAssistant contentAssistant= new ContentAssistant(); | |
78 | contentAssistant.setContentAssistProcessor(new BarContentAssistProcessor() { | |
79 | @Override | |
80 | public IContextInformationValidator getContextInformationValidator() { | |
81 | return new ValidatorWithPresenter(); | |
82 | } | |
83 | }, IDocument.DEFAULT_CONTENT_TYPE); | |
84 | return contentAssistant; | |
85 | } | |
86 | ||
87 | @Test | |
88 | public void testContextInfo_withStyledTextPresentation() throws Exception { | |
89 | setupSourceViewer(createBarContentAssist(), BarContentAssistProcessor.PROPOSAL); | |
90 | ||
91 | final List<Shell> beforeShells= getCurrentShells(); | |
92 | ||
93 | postSourceViewerKeyEvent(SWT.ARROW_RIGHT, 0, SWT.KeyDown); | |
94 | selectAndReveal(4, 0); | |
95 | processEvents(); | |
96 | ||
97 | triggerContextInformation(); | |
98 | this.infoShell= findNewShell(beforeShells); | |
99 | assertEquals("idx= 0", getInfoText(this.infoShell)); | |
100 | assertArrayEquals(new StyleRange[] { | |
101 | new StyleRange(0, 3, null, null, SWT.BOLD) | |
102 | }, getInfoStyleRanges(this.infoShell)); | |
103 | ||
104 | postSourceViewerKeyEvent(SWT.ARROW_RIGHT, 0, SWT.KeyDown); | |
105 | ||
106 | assertEquals("idx= 0", getInfoText(this.infoShell)); | |
107 | assertArrayEquals(new StyleRange[] { | |
108 | }, getInfoStyleRanges(this.infoShell)); | |
109 | } | |
110 | ||
111 | ||
112 | static StyleRange[] getInfoStyleRanges(final Shell shell) { | |
113 | assertTrue(shell.isVisible()); | |
114 | Control[] children= shell.getChildren(); | |
115 | for (Control child : children) { | |
116 | if (child instanceof Text) { | |
117 | return null; | |
118 | } | |
119 | if (child instanceof StyledText) { | |
120 | return ((StyledText) child).getStyleRanges(); | |
121 | } | |
122 | } | |
123 | return null; | |
124 | } | |
125 | ||
126 | } |
+106
-0
0 | /******************************************************************************* | |
1 | * Copyright (c) 2017, 2019 Stephan Wahlbrink 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 | * Stephan Wahlbrink <sw@wahlbrink.eu> | |
12 | *******************************************************************************/ | |
13 | package org.eclipse.jface.text.tests.contentassist; | |
14 | ||
15 | import static org.junit.Assert.assertEquals; | |
16 | import static org.junit.Assert.assertTrue; | |
17 | ||
18 | import java.util.List; | |
19 | ||
20 | import org.junit.Test; | |
21 | ||
22 | import org.eclipse.swt.custom.StyledText; | |
23 | import org.eclipse.swt.widgets.Control; | |
24 | import org.eclipse.swt.widgets.Shell; | |
25 | import org.eclipse.swt.widgets.Text; | |
26 | ||
27 | import org.eclipse.text.tests.Accessor; | |
28 | ||
29 | import org.eclipse.jface.text.IDocument; | |
30 | import org.eclipse.jface.text.contentassist.ContentAssistant; | |
31 | ||
32 | ||
33 | public class ContextInformationTest extends AbstractContentAssistTest { | |
34 | ||
35 | ||
36 | private Shell infoShell; | |
37 | ||
38 | ||
39 | private ContentAssistant createBarContentAssist() { | |
40 | ContentAssistant contentAssistant= new ContentAssistant(); | |
41 | contentAssistant.setContentAssistProcessor(new BarContentAssistProcessor(), IDocument.DEFAULT_CONTENT_TYPE); | |
42 | return contentAssistant; | |
43 | } | |
44 | ||
45 | @Test | |
46 | public void testContextInfo() throws Exception { | |
47 | setupSourceViewer(createBarContentAssist(), BarContentAssistProcessor.PROPOSAL); | |
48 | ||
49 | final List<Shell> beforeShells= getCurrentShells(); | |
50 | ||
51 | selectAndReveal(4, 0); | |
52 | processEvents(); | |
53 | ||
54 | triggerContextInformation(); | |
55 | this.infoShell= findNewShell(beforeShells); | |
56 | assertEquals("idx= 0", getInfoText(this.infoShell)); | |
57 | ||
58 | selectAndReveal(8, 0); | |
59 | processEvents(); | |
60 | ||
61 | triggerContextInformation(); | |
62 | this.infoShell= findNewShell(beforeShells); | |
63 | assertEquals("idx= 1", getInfoText(this.infoShell)); | |
64 | } | |
65 | ||
66 | @Test | |
67 | public void testContextInfo_hide_Bug512251() throws Exception { | |
68 | setupSourceViewer(createBarContentAssist(), BarContentAssistProcessor.PROPOSAL); | |
69 | ||
70 | final List<Shell> beforeShells= getCurrentShells(); | |
71 | ||
72 | selectAndReveal(4, 0); | |
73 | processEvents(); | |
74 | ||
75 | triggerContextInformation(); | |
76 | this.infoShell= findNewShell(beforeShells); | |
77 | ||
78 | selectAndReveal(8, 0); | |
79 | processEvents(); | |
80 | ||
81 | triggerContextInformation(); | |
82 | this.infoShell= findNewShell(beforeShells); | |
83 | ||
84 | // ITextEditorActionConstants.DELETE_LINE | |
85 | getDocument().set(""); | |
86 | ||
87 | new Accessor(getContentAssistant(), ContentAssistant.class).invoke("hide", new Object[0]); | |
88 | } | |
89 | ||
90 | ||
91 | static String getInfoText(final Shell shell) { | |
92 | assertTrue(shell.isVisible()); | |
93 | Control[] children= shell.getChildren(); | |
94 | for (Control child : children) { | |
95 | if (child instanceof Text) { | |
96 | return ((Text) child).getText(); | |
97 | } | |
98 | if (child instanceof StyledText) { | |
99 | return ((StyledText) child).getText(); | |
100 | } | |
101 | } | |
102 | return null; | |
103 | } | |
104 | ||
105 | } |
+581
-0
0 | /******************************************************************************* | |
1 | * Copyright (c) 2019 Pivotal, Inc. | |
2 | * All rights reserved. This program and the accompanying materials | |
3 | * are made available under the terms of the Eclipse Public License v1.0 | |
4 | * which accompanies this distribution, and is available at | |
5 | * https://www.eclipse.org/legal/epl-v10.html | |
6 | * | |
7 | * Contributors: | |
8 | * Pivotal, Inc. - initial API and implementation | |
9 | *******************************************************************************/ | |
10 | package org.eclipse.jface.text.tests.contentassist; | |
11 | ||
12 | import static org.junit.Assert.assertEquals; | |
13 | import static org.junit.Assert.assertTrue; | |
14 | ||
15 | import java.lang.reflect.Field; | |
16 | import java.util.List; | |
17 | import java.util.function.Predicate; | |
18 | import java.util.stream.Collectors; | |
19 | ||
20 | import org.junit.After; | |
21 | import org.junit.Before; | |
22 | import org.junit.Ignore; | |
23 | import org.junit.Test; | |
24 | ||
25 | import org.eclipse.swt.SWT; | |
26 | import org.eclipse.swt.graphics.Image; | |
27 | import org.eclipse.swt.graphics.Point; | |
28 | import org.eclipse.swt.widgets.Shell; | |
29 | ||
30 | import org.eclipse.text.edits.InsertEdit; | |
31 | ||
32 | import org.eclipse.jface.text.BadLocationException; | |
33 | import org.eclipse.jface.text.Document; | |
34 | import org.eclipse.jface.text.DocumentEvent; | |
35 | import org.eclipse.jface.text.IDocument; | |
36 | import org.eclipse.jface.text.ITextViewer; | |
37 | import org.eclipse.jface.text.contentassist.ContentAssistant; | |
38 | import org.eclipse.jface.text.contentassist.ContextInformationValidator; | |
39 | import org.eclipse.jface.text.contentassist.ICompletionProposal; | |
40 | import org.eclipse.jface.text.contentassist.ICompletionProposalExtension; | |
41 | import org.eclipse.jface.text.contentassist.ICompletionProposalExtension2; | |
42 | import org.eclipse.jface.text.contentassist.IContentAssistProcessor; | |
43 | import org.eclipse.jface.text.contentassist.IContextInformation; | |
44 | import org.eclipse.jface.text.contentassist.IContextInformationValidator; | |
45 | import org.eclipse.jface.text.source.SourceViewer; | |
46 | import org.eclipse.jface.text.tests.util.DisplayHelper; | |
47 | ||
48 | /** | |
49 | * Tests for Async completion proposal popup proposals filtering mechanics | |
50 | * | |
51 | * @author Alex Boyko | |
52 | * | |
53 | */ | |
54 | public class FilteringAsyncContentAssistTests { | |
55 | ||
56 | private Shell shell; | |
57 | private SourceViewer viewer; | |
58 | private ContentAssistant ca; | |
59 | ||
60 | @Before | |
61 | public void setup() { | |
62 | tearDown(); | |
63 | ||
64 | shell = new Shell(); | |
65 | shell.setSize(300, 300); | |
66 | shell.open(); | |
67 | ||
68 | viewer = new SourceViewer(shell, null, SWT.NONE); | |
69 | Document document = new Document(); | |
70 | viewer.setDocument(document); | |
71 | ca = new ContentAssistant(true); | |
72 | } | |
73 | ||
74 | @After | |
75 | public void tearDown() { | |
76 | if (shell != null) { | |
77 | ca.uninstall(); | |
78 | if (!shell.isDisposed()) { | |
79 | shell.dispose(); | |
80 | } | |
81 | shell = null; | |
82 | } | |
83 | } | |
84 | ||
85 | /** | |
86 | * Simple CA with 1 immediate CA processor. Empty text, invoke CA, verify 1 | |
87 | * proposal, apply it, verify the resultant text | |
88 | * | |
89 | * @throws Exception exception | |
90 | */ | |
91 | @Test | |
92 | public void testSimpleCa() throws Exception { | |
93 | ||
94 | ca.addContentAssistProcessor(new ImmediateContentAssistProcessor("xx"), IDocument.DEFAULT_CONTENT_TYPE); | |
95 | ||
96 | ca.install(viewer); | |
97 | ||
98 | viewer.setSelectedRange(0, 0); | |
99 | ||
100 | ca.showPossibleCompletions(); | |
101 | ||
102 | DisplayHelper.sleep(shell.getDisplay(), 300); | |
103 | ||
104 | List<ICompletionProposal> computedProposals = getComputedProposals(ca); | |
105 | ||
106 | assertEquals(1, computedProposals.size()); | |
107 | ||
108 | ICompletionProposal proposal = computedProposals.get(0); | |
109 | ||
110 | IDocument document = viewer.getDocument(); | |
111 | ||
112 | proposal.apply(document); | |
113 | ||
114 | assertEquals("xx", document.get()); | |
115 | } | |
116 | ||
117 | /** | |
118 | * Simple CA with filtering with 2 immediate CA processors. Empty text | |
119 | * initially. Invoke CA, verify 2 proposals, type 'x', verify only 1 proposal 1 | |
120 | * | |
121 | * @throws Exception exception | |
122 | */ | |
123 | @Test | |
124 | public void testFilteredCa() throws Exception { | |
125 | IDocument document = viewer.getDocument(); | |
126 | ||
127 | ca.addContentAssistProcessor(new ImmediateContentAssistProcessor("xx"), IDocument.DEFAULT_CONTENT_TYPE); | |
128 | ca.addContentAssistProcessor(new ImmediateContentAssistProcessor("yy"), IDocument.DEFAULT_CONTENT_TYPE); | |
129 | ||
130 | ca.install(viewer); | |
131 | ||
132 | viewer.setSelectedRange(1, 0); | |
133 | ||
134 | ca.showPossibleCompletions(); | |
135 | ||
136 | DisplayHelper.sleep(shell.getDisplay(), 300); | |
137 | ||
138 | List<ICompletionProposal> computedProposals = getComputedProposals(ca); | |
139 | assertEquals(2, computedProposals.size()); | |
140 | List<ICompletionProposal> filteredProposals = getFilteredProposals(ca); | |
141 | assertEquals(2, filteredProposals.size()); | |
142 | ||
143 | new InsertEdit(0, "x").apply(document); | |
144 | viewer.setSelectedRange(1, 0); | |
145 | ||
146 | DisplayHelper.sleep(shell.getDisplay(), 300); | |
147 | ||
148 | computedProposals = getComputedProposals(ca); | |
149 | assertEquals(2, computedProposals.size()); | |
150 | filteredProposals = getFilteredProposals(ca); | |
151 | assertEquals(1, filteredProposals.size()); | |
152 | ||
153 | ((ICompletionProposalExtension) filteredProposals.get(0)).apply(document, (char) 0, | |
154 | viewer.getSelectedRange().x); | |
155 | assertEquals("xxx", document.get()); | |
156 | } | |
157 | ||
158 | /** | |
159 | * Simple CA with filtering with 1 immediate CA processors. Empty text | |
160 | * initially. Invoke CA, verify 1 proposal, type 'a', verify no proposals | |
161 | * | |
162 | * @throws Exception exception | |
163 | */ | |
164 | @Test | |
165 | public void testFilteredCa_AllFilteredOut() throws Exception { | |
166 | IDocument document = viewer.getDocument(); | |
167 | ||
168 | ca.addContentAssistProcessor(new ImmediateContentAssistProcessor("xx"), IDocument.DEFAULT_CONTENT_TYPE); | |
169 | ||
170 | ca.install(viewer); | |
171 | ||
172 | viewer.setSelectedRange(1, 0); | |
173 | ||
174 | ca.showPossibleCompletions(); | |
175 | ||
176 | DisplayHelper.sleep(shell.getDisplay(), 300); | |
177 | ||
178 | List<ICompletionProposal> computedProposals = getComputedProposals(ca); | |
179 | assertEquals(1, computedProposals.size()); | |
180 | List<ICompletionProposal> filteredProposals = getFilteredProposals(ca); | |
181 | assertEquals(1, filteredProposals.size()); | |
182 | ||
183 | new InsertEdit(0, "a").apply(document); | |
184 | viewer.setSelectedRange(1, 0); | |
185 | ||
186 | DisplayHelper.sleep(shell.getDisplay(), 600); | |
187 | ||
188 | filteredProposals = getFilteredProposals(ca); | |
189 | assertTrue(filteredProposals == null || filteredProposals.isEmpty()); | |
190 | } | |
191 | ||
192 | /** | |
193 | * CA with 1 immediate and 1 delayed CA processors. Empty text initially. Invoke | |
194 | * CA, verify 1 proposal shows right away, and then another added later after | |
195 | * delay | |
196 | * | |
197 | * @throws Exception exception | |
198 | */ | |
199 | @Test | |
200 | public void testMultipleCaProcessors() throws Exception { | |
201 | IDocument document = viewer.getDocument(); | |
202 | ||
203 | ca.addContentAssistProcessor(new ImmediateContentAssistProcessor("xx"), IDocument.DEFAULT_CONTENT_TYPE); | |
204 | ca.addContentAssistProcessor(new DelayedContentAssistProcessor("yy", 3000, false), | |
205 | IDocument.DEFAULT_CONTENT_TYPE); | |
206 | ||
207 | ca.install(viewer); | |
208 | ||
209 | viewer.setSelectedRange(0, 0); | |
210 | ||
211 | ca.showPossibleCompletions(); | |
212 | ||
213 | DisplayHelper.sleep(shell.getDisplay(), 300); | |
214 | ||
215 | List<ICompletionProposal> computedProposals = getComputedProposals(ca, | |
216 | p -> p instanceof IncompleteCompletionProposal); | |
217 | assertEquals(1, computedProposals.size()); | |
218 | List<ICompletionProposal> filteredProposals = getFilteredProposals(ca, | |
219 | p -> p instanceof IncompleteCompletionProposal); | |
220 | assertEquals(1, filteredProposals.size()); | |
221 | ||
222 | DisplayHelper.sleep(shell.getDisplay(), 3000); | |
223 | ||
224 | computedProposals = getComputedProposals(ca, p -> p instanceof IncompleteCompletionProposal); | |
225 | assertEquals(2, computedProposals.size()); | |
226 | filteredProposals = getFilteredProposals(ca, p -> p instanceof IncompleteCompletionProposal); | |
227 | assertEquals(2, filteredProposals.size()); | |
228 | ||
229 | ((ICompletionProposalExtension) filteredProposals.get(1)).apply(document, (char) 0, | |
230 | viewer.getSelectedRange().x); | |
231 | assertEquals("yy", document.get()); | |
232 | } | |
233 | ||
234 | /** | |
235 | * CA with 1 CA processor for which the first request takes long time and consequent request are | |
236 | * instant. Invoke CA. and type 'a' such that completions are not ready yet, but while recompute | |
237 | * was cancelling futures the futures from previous invocation completed and scheduled an async | |
238 | * UI runnable to show completions. Recompute is immediate. Hence proposals shown right away. | |
239 | * However the async UI runnable to show old proposals runs after and overwrites the correct | |
240 | * immediate proposals. Test that this behaviour is fixed | |
241 | * | |
242 | * @throws Exception exception | |
243 | */ | |
244 | @Test | |
245 | public void testCA_WithFirstDelayedThenImmediateProposals() throws Exception { | |
246 | IDocument document = viewer.getDocument(); | |
247 | ||
248 | ca.addContentAssistProcessor(new LongInitialContentAssistProcessor("abc", 500, true), | |
249 | IDocument.DEFAULT_CONTENT_TYPE); | |
250 | ||
251 | ca.install(viewer); | |
252 | ||
253 | viewer.setSelectedRange(0, 0); | |
254 | ||
255 | ca.showPossibleCompletions(); | |
256 | ||
257 | DisplayHelper.sleep(shell.getDisplay(), 200); | |
258 | new InsertEdit(0, "a").apply(document); | |
259 | viewer.setSelectedRange(1, 0); | |
260 | ||
261 | DisplayHelper.sleep(shell.getDisplay(), 3000); | |
262 | ||
263 | List<ICompletionProposal> filteredProposals= getFilteredProposals(ca, | |
264 | p -> p instanceof IncompleteCompletionProposal); | |
265 | assertTrue(filteredProposals != null); | |
266 | assertEquals(1, filteredProposals.size()); | |
267 | ||
268 | filteredProposals.get(0).apply(document); | |
269 | ||
270 | assertEquals("aabc", document.get()); | |
271 | ||
272 | } | |
273 | ||
274 | /** | |
275 | * CA with filtering with 1 immediate and 1 delayed CA processors. Empty text | |
276 | * initially. Invoke CA, verify 1 proposal shows right away, type `a` before | |
277 | * delayed proposal calculated, verify immediate proposal filtered out | |
278 | * | |
279 | * Bug: filtering only applied after all CA processors have completed | |
280 | * | |
281 | * @throws Exception exception | |
282 | */ | |
283 | @Test @Ignore | |
284 | public void testFastCompletionsNotFilteredUntilLongComplitionsCalculated() throws Exception { | |
285 | IDocument document = viewer.getDocument(); | |
286 | ||
287 | ca.addContentAssistProcessor(new ImmediateContentAssistProcessor("xxxx"), IDocument.DEFAULT_CONTENT_TYPE); | |
288 | ca.addContentAssistProcessor(new DelayedContentAssistProcessor("yyyy", 5000, false), | |
289 | IDocument.DEFAULT_CONTENT_TYPE); | |
290 | ||
291 | ca.install(viewer); | |
292 | ||
293 | viewer.setSelectedRange(1, 0); | |
294 | ||
295 | ca.showPossibleCompletions(); | |
296 | ||
297 | DisplayHelper.sleep(shell.getDisplay(), 300); | |
298 | ||
299 | List<ICompletionProposal> computedProposals = getComputedProposals(ca, | |
300 | p -> p instanceof IncompleteCompletionProposal); | |
301 | assertEquals(1, computedProposals.size()); | |
302 | List<ICompletionProposal> filteredProposals = getFilteredProposals(ca, | |
303 | p -> p instanceof IncompleteCompletionProposal); | |
304 | assertEquals(1, filteredProposals.size()); | |
305 | ||
306 | new InsertEdit(0, "a").apply(document); | |
307 | viewer.setSelectedRange(1, 0); | |
308 | ||
309 | DisplayHelper.sleep(shell.getDisplay(), 1000); | |
310 | ||
311 | filteredProposals = getFilteredProposals(ca, p -> p instanceof IncompleteCompletionProposal); | |
312 | assertTrue(filteredProposals == null || filteredProposals.isEmpty()); | |
313 | } | |
314 | ||
315 | private class ImmediateContentAssistProcessor implements IContentAssistProcessor { | |
316 | ||
317 | final private String template; | |
318 | final private boolean incomplete; | |
319 | ||
320 | ImmediateContentAssistProcessor(String template) { | |
321 | this(template, false); | |
322 | } | |
323 | ||
324 | ImmediateContentAssistProcessor(String template, boolean incomplete) { | |
325 | this.template = template; | |
326 | this.incomplete = incomplete; | |
327 | } | |
328 | ||
329 | @Override | |
330 | public ICompletionProposal[] computeCompletionProposals(ITextViewer textViewer, int offset) { | |
331 | try { | |
332 | IDocument document= textViewer.getDocument(); | |
333 | if (document != null && (document.getLength() == 0 || isSubstringFoundOrderedInString(document.get(0, offset), template))) { | |
334 | if (incomplete) { | |
335 | return new ICompletionProposal[] { | |
336 | new IncompleteCompletionProposal(template, offset, 0, offset, template) }; | |
337 | } else { | |
338 | CompletionProposal proposal = new CompletionProposal(template, offset, 0, offset, template); | |
339 | return new ICompletionProposal[] { proposal }; | |
340 | } | |
341 | } | |
342 | } catch (BadLocationException e) { | |
343 | throw new IllegalStateException("Error computing proposals"); | |
344 | } | |
345 | return new ICompletionProposal[0]; | |
346 | } | |
347 | ||
348 | @Override | |
349 | public IContextInformation[] computeContextInformation(ITextViewer textViewer, int offset) { | |
350 | return new IContextInformation[0]; | |
351 | } | |
352 | ||
353 | @Override | |
354 | public char[] getCompletionProposalAutoActivationCharacters() { | |
355 | return new char[0]; | |
356 | } | |
357 | ||
358 | @Override | |
359 | public char[] getContextInformationAutoActivationCharacters() { | |
360 | return new char[0]; | |
361 | } | |
362 | ||
363 | @Override | |
364 | public String getErrorMessage() { | |
365 | return "No proposals!"; | |
366 | } | |
367 | ||
368 | @Override | |
369 | public IContextInformationValidator getContextInformationValidator() { | |
370 | return new ContextInformationValidator(this); | |
371 | } | |
372 | ||
373 | } | |
374 | ||
375 | private class DelayedContentAssistProcessor extends ImmediateContentAssistProcessor { | |
376 | ||
377 | protected long delay; | |
378 | ||
379 | DelayedContentAssistProcessor(String template, long delay, boolean incomplete) { | |
380 | super(template, incomplete); | |
381 | this.delay = delay; | |
382 | } | |
383 | ||
384 | @Override | |
385 | public ICompletionProposal[] computeCompletionProposals(ITextViewer textViewer, int offset) { | |
386 | if (delay > 0) { | |
387 | try { | |
388 | Thread.sleep(delay); | |
389 | } catch (InterruptedException e) { | |
390 | throw new IllegalStateException("Cannot generate delayed content assist proposals!"); | |
391 | } | |
392 | } | |
393 | return super.computeCompletionProposals(viewer, offset); | |
394 | } | |
395 | } | |
396 | ||
397 | private class LongInitialContentAssistProcessor extends DelayedContentAssistProcessor { | |
398 | ||
399 | LongInitialContentAssistProcessor(String template, long delay, boolean incomplete) { | |
400 | super(template, delay, incomplete); | |
401 | } | |
402 | ||
403 | @Override | |
404 | public ICompletionProposal[] computeCompletionProposals(ITextViewer textViewer, int offset) { | |
405 | ICompletionProposal[] completionProposals= super.computeCompletionProposals(viewer, offset); | |
406 | delay = 0; | |
407 | return completionProposals; | |
408 | } | |
409 | } | |
410 | ||
411 | @SuppressWarnings("unchecked") | |
412 | private static List<ICompletionProposal> getComputedProposals(ContentAssistant ca) throws Exception { | |
413 | Field f = ContentAssistant.class.getDeclaredField("fProposalPopup"); | |
414 | f.setAccessible(true); | |
415 | Object caPopup = f.get(ca); | |
416 | assertEquals("org.eclipse.jface.text.contentassist.AsyncCompletionProposalPopup", caPopup.getClass().getName()); | |
417 | Class<?> caPopupSuperClass = caPopup.getClass().getSuperclass(); | |
418 | assertEquals("org.eclipse.jface.text.contentassist.CompletionProposalPopup", caPopupSuperClass.getName()); | |
419 | Field computedProposals = caPopupSuperClass.getDeclaredField("fComputedProposals"); | |
420 | computedProposals.setAccessible(true); | |
421 | return (List<ICompletionProposal>) computedProposals.get(caPopup); | |
422 | } | |
423 | ||
424 | @SuppressWarnings("unchecked") | |
425 | private static List<ICompletionProposal> getFilteredProposals(ContentAssistant ca) throws Exception { | |
426 | Field f = ContentAssistant.class.getDeclaredField("fProposalPopup"); | |
427 | f.setAccessible(true); | |
428 | Object caPopup = f.get(ca); | |
429 | assertEquals("org.eclipse.jface.text.contentassist.AsyncCompletionProposalPopup", caPopup.getClass().getName()); | |
430 | Class<?> caPopupSuperClass = caPopup.getClass().getSuperclass(); | |
431 | assertEquals("org.eclipse.jface.text.contentassist.CompletionProposalPopup", caPopupSuperClass.getName()); | |
432 | Field computedProposals = caPopupSuperClass.getDeclaredField("fFilteredProposals"); | |
433 | computedProposals.setAccessible(true); | |
434 | return (List<ICompletionProposal>) computedProposals.get(caPopup); | |
435 | } | |
436 | ||
437 | private static List<ICompletionProposal> getComputedProposals(ContentAssistant ca, Predicate<ICompletionProposal> p) | |
438 | throws Exception { | |
439 | List<ICompletionProposal> computedProposals = getComputedProposals(ca); | |
440 | return computedProposals == null ? null : computedProposals.stream().filter(p).collect(Collectors.toList()); | |
441 | } | |
442 | ||
443 | private static List<ICompletionProposal> getFilteredProposals(ContentAssistant ca, Predicate<ICompletionProposal> p) | |
444 | throws Exception { | |
445 | List<ICompletionProposal> filteredProposals = getFilteredProposals(ca); | |
446 | return filteredProposals == null ? null : filteredProposals.stream().filter(p).collect(Collectors.toList()); | |
447 | } | |
448 | ||
449 | private static class IncompleteCompletionProposal implements ICompletionProposal { | |
450 | ||
451 | /** The string to be displayed in the completion proposal popup. */ | |
452 | private String fDisplayString; | |
453 | /** The replacement string. */ | |
454 | protected String fReplacementString; | |
455 | /** The replacement offset. */ | |
456 | protected int fReplacementOffset; | |
457 | /** The replacement length. */ | |
458 | private int fReplacementLength; | |
459 | /** The cursor position after this proposal has been applied. */ | |
460 | private int fCursorPosition; | |
461 | ||
462 | public IncompleteCompletionProposal(String replacementString, int replacementOffset, int replacementLength, int cursorPosition, String displayString) { | |
463 | fReplacementString= replacementString; | |
464 | fReplacementOffset= replacementOffset; | |
465 | fReplacementLength= replacementLength; | |
466 | fCursorPosition= cursorPosition; | |
467 | fDisplayString= displayString; | |
468 | } | |
469 | ||
470 | @Override | |
471 | public void apply(IDocument document) { | |
472 | try { | |
473 | document.replace(fReplacementOffset, fReplacementLength, fReplacementString); | |
474 | } catch (BadLocationException x) { | |
475 | // ignore | |
476 | } | |
477 | } | |
478 | ||
479 | @Override | |
480 | public Point getSelection(IDocument document) { | |
481 | return new Point(fReplacementOffset + fCursorPosition, 0); | |
482 | } | |
483 | ||
484 | @Override | |
485 | public IContextInformation getContextInformation() { | |
486 | return null; | |
487 | } | |
488 | ||
489 | @Override | |
490 | public Image getImage() { | |
491 | return null; | |
492 | } | |
493 | ||
494 | @Override | |
495 | public String getDisplayString() { | |
496 | if (fDisplayString != null) | |
497 | return fDisplayString; | |
498 | return fReplacementString; | |
499 | } | |
500 | ||
501 | @Override | |
502 | public String getAdditionalProposalInfo() { | |
503 | return null; | |
504 | } | |
505 | } | |
506 | ||
507 | private static class CompletionProposal extends IncompleteCompletionProposal | |
508 | implements ICompletionProposalExtension, ICompletionProposalExtension2 { | |
509 | ||
510 | public CompletionProposal(String replacementString, int replacementOffset, int replacementLength, | |
511 | int cursorPosition, String displayString) { | |
512 | super(replacementString, replacementOffset, replacementLength, cursorPosition, displayString); | |
513 | } | |
514 | ||
515 | @Override | |
516 | public void apply(ITextViewer viewer, char trigger, int stateMask, int offset) { | |
517 | apply(viewer.getDocument()); | |
518 | } | |
519 | ||
520 | @Override | |
521 | public void selected(ITextViewer viewer, boolean smartToggle) { | |
522 | // nothing | |
523 | } | |
524 | ||
525 | @Override | |
526 | public void unselected(ITextViewer viewer) { | |
527 | // nothing | |
528 | } | |
529 | ||
530 | @Override | |
531 | public boolean validate(IDocument document, int offset, DocumentEvent event) { | |
532 | if (offset > fReplacementOffset) { | |
533 | try { | |
534 | return isSubstringFoundOrderedInString(document.get(fReplacementOffset, offset - fReplacementOffset), fReplacementString); | |
535 | } catch (BadLocationException e) { | |
536 | throw new IllegalStateException("Completion validation failed"); | |
537 | } | |
538 | } | |
539 | return false; | |
540 | } | |
541 | ||
542 | @Override | |
543 | public void apply(IDocument document, char trigger, int offset) { | |
544 | apply(document); | |
545 | } | |
546 | ||
547 | @Override | |
548 | public boolean isValidFor(IDocument document, int offset) { | |
549 | return validate(document, offset, null); | |
550 | } | |
551 | ||
552 | @Override | |
553 | public char[] getTriggerCharacters() { | |
554 | return new char[0]; | |
555 | } | |
556 | ||
557 | @Override | |
558 | public int getContextInformationPosition() { | |
559 | return 0; | |
560 | } | |
561 | ||
562 | } | |
563 | ||
564 | @SuppressWarnings("boxing") | |
565 | private static boolean isSubstringFoundOrderedInString(String subString, String string) { | |
566 | int lastIndex = 0; | |
567 | subString = subString.toLowerCase(); | |
568 | string = string.toLowerCase(); | |
569 | for (Character c : subString.toCharArray()) { | |
570 | int index = string.indexOf(c, lastIndex); | |
571 | if (index < 0) { | |
572 | return false; | |
573 | } else { | |
574 | lastIndex = index + 1; | |
575 | } | |
576 | } | |
577 | return true; | |
578 | } | |
579 | ||
580 | } |
+5
-6
44 | 44 | * Reconciler tests. Uses barrier synchronization and a call log to assert |
45 | 45 | * correct order of reconciling events. |
46 | 46 | * |
47 | * TODO test reconciler arguments (delay > 0 etc.) | |
48 | * TODO incremental reconciler tests | |
49 | * | |
50 | 47 | * @since 3.1 |
51 | 48 | */ |
49 | // TODO test reconciler arguments (delay > 0 etc.) | |
50 | // TODO incremental reconciler tests | |
52 | 51 | public class AbstractReconcilerTest { |
53 | 52 | |
54 | 53 | /** |
147 | 146 | @Before |
148 | 147 | public void setUp() { |
149 | 148 | fBarrier= new Barrier(); |
150 | fCallLog= Collections.synchronizedList(new ArrayList<String>()); | |
149 | fCallLog= Collections.synchronizedList(new ArrayList<>()); | |
151 | 150 | fReconciler= new AbstractReconciler() { |
152 | 151 | @Override |
153 | 152 | protected void initialProcess() { |
178 | 177 | }; |
179 | 178 | fReconciler.setIsIncrementalReconciler(false); |
180 | 179 | fReconciler.setDelay(50); // make tests run faster |
181 | ||
180 | ||
182 | 181 | fProgressMonitor= new NullProgressMonitor(); |
183 | 182 | fReconciler.setProgressMonitor(fProgressMonitor); |
184 | 183 | |
221 | 220 | assertFalse(isActive()); |
222 | 221 | assertFalse(isDirty()); |
223 | 222 | } |
224 | ||
223 | ||
225 | 224 | @Test |
226 | 225 | public void testDirtyingWhenClean() throws BadLocationException, InterruptedException { |
227 | 226 | installDocument(); |
+1
-1
78 | 78 | int[] offsets= new int[] { 13, 26, 26, 39 }; |
79 | 79 | assertGetPartition_InterleavingPartitions(offsets); |
80 | 80 | } |
81 | ||
81 | ||
82 | 82 | @Test |
83 | 83 | public void testGetPartitionEmptyStart() { |
84 | 84 | fDoc.set("/* comment */docu ment"); |
+1
-1
107 | 107 | /** |
108 | 108 | * The condition which has to be met in order for {@link #waitForCondition(Display, long)} to |
109 | 109 | * return before the timeout elapses. |
110 | * | |
110 | * | |
111 | 111 | * @return <code>true</code> if the condition is met, <code>false</code> if the event loop |
112 | 112 | * should be driven some more |
113 | 113 | */ |
1 | 1 | Bundle-ManifestVersion: 2 |
2 | 2 | Bundle-Name: %pluginName |
3 | 3 | Bundle-SymbolicName: org.eclipse.search; singleton:=true |
4 | Bundle-Version: 3.11.700.qualifier | |
4 | Bundle-Version: 3.11.800.qualifier | |
5 | 5 | Bundle-Activator: org.eclipse.search.internal.ui.SearchPlugin |
6 | 6 | Bundle-ActivationPolicy: lazy |
7 | 7 | Bundle-Vendor: %providerName |
Binary diff not shown
Binary diff not shown
Binary diff not shown
Binary diff not shown
0 | <?xml version="1.0" encoding="UTF-8"?> | |
1 | <!-- | |
2 | Copyright (c) 2012, 2015 Eclipse Foundation and others. | |
3 | All rights reserved. This program and the accompanying materials | |
4 | are made available under the terms of the Eclipse Distribution License v1.0 | |
5 | which accompanies this distribution, and is available at | |
6 | http://www.eclipse.org/org/documents/edl-v10.php | |
7 | ||
8 | Contributors: | |
9 | Igor Fedorenko - initial implementation | |
10 | --> | |
11 | <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | |
12 | <modelVersion>4.0.0</modelVersion> | |
13 | <parent> | |
14 | <artifactId>eclipse.platform.text</artifactId> | |
15 | <groupId>eclipse.platform.text</groupId> | |
16 | <version>4.13.0-SNAPSHOT</version> | |
17 | </parent> | |
18 | <groupId>org.eclipse.search</groupId> | |
19 | <artifactId>org.eclipse.search</artifactId> | |
20 | <version>3.11.700-SNAPSHOT</version> | |
21 | <packaging>eclipse-plugin</packaging> | |
22 | </project> |
+4
-2
269 | 269 | * Copied from {@link FindReplaceDocumentAdapter}} |
270 | 270 | * |
271 | 271 | * FindReplaceDocumentAdapter with contributions from: |
272 | * Cagatay Calli <ccalli@gmail.com> - [find/replace] retain caps when replacing - https://bugs.eclipse.org/bugs/show_bug.cgi?id=28949 | |
273 | * Cagatay Calli <ccalli@gmail.com> - [find/replace] define & fix behavior of retain caps with other escapes and text before \C - https://bugs.eclipse.org/bugs/show_bug.cgi?id=217061 | |
272 | * <ul> | |
273 | * <li>Cagatay Calli <ccalli@gmail.com> - [find/replace] retain caps when replacing - https://bugs.eclipse.org/bugs/show_bug.cgi?id=28949 | |
274 | * <li>Cagatay Calli <ccalli@gmail.com> - [find/replace] define & fix behavior of retain caps with other escapes and text before \C - https://bugs.eclipse.org/bugs/show_bug.cgi?id=217061 | |
275 | * </ul> | |
274 | 276 | */ |
275 | 277 | private static class ReplaceStringConstructor { |
276 | 278 |
0 | 0 | /******************************************************************************* |
1 | * Copyright (c) 2000, 2018 IBM Corporation and others. | |
1 | * Copyright (c) 2000, 2019 IBM Corporation and others. | |
2 | 2 | * |
3 | 3 | * This program and the accompanying materials |
4 | 4 | * are made available under the terms of the Eclipse Public License 2.0 |
127 | 127 | private SortAction fSortByPathAction; |
128 | 128 | |
129 | 129 | |
130 | private static final String[] SHOW_IN_TARGETS= new String[] { IPageLayout.ID_RES_NAV }; | |
130 | private static final String[] SHOW_IN_TARGETS = new String[] { IPageLayout.ID_PROJECT_EXPLORER }; | |
131 | 131 | private static final IShowInTargetList SHOW_IN_TARGET_LIST= () -> SHOW_IN_TARGETS; |
132 | 132 | |
133 | 133 | public FileSearchPage() { |
1 | 1 | Bundle-ManifestVersion: 2 |
2 | 2 | Bundle-Name: %pluginName |
3 | 3 | Bundle-SymbolicName: org.eclipse.search.tests |
4 | Bundle-Version: 3.9.400.qualifier | |
4 | Bundle-Version: 3.9.500.qualifier | |
5 | 5 | Bundle-Activator: org.eclipse.search.tests.SearchTestPlugin |
6 | 6 | Bundle-Vendor: %providerName |
7 | 7 | Bundle-Localization: plugin |
8 | Export-Package: org.eclipse.search.core.tests, | |
9 | org.eclipse.search.tests, | |
10 | org.eclipse.search.tests.filesearch | |
8 | Export-Package: org.eclipse.search.core.tests;x-internal:=true, | |
9 | org.eclipse.search.tests;x-internal:=true, | |
10 | org.eclipse.search.tests.filesearch;x-internal:=true | |
11 | 11 | Require-Bundle: |
12 | 12 | org.eclipse.ui;bundle-version="[3.5.0,4.0.0)", |
13 | 13 | org.eclipse.ui.ide;bundle-version="[3.5.0,4.0.0)", |
13 | 13 | <parent> |
14 | 14 | <artifactId>tests-pom</artifactId> |
15 | 15 | <groupId>eclipse.platform.text</groupId> |
16 | <version>4.13.0-SNAPSHOT</version> | |
16 | <version>4.14.0-SNAPSHOT</version> | |
17 | 17 | <relativePath>../tests-pom/</relativePath> |
18 | 18 | </parent> |
19 | 19 | <groupId>org.eclipse.search</groupId> |
20 | 20 | <artifactId>org.eclipse.search.tests</artifactId> |
21 | <version>3.9.400-SNAPSHOT</version> | |
21 | <version>3.9.500-SNAPSHOT</version> | |
22 | 22 | <packaging>eclipse-test-plugin</packaging> |
23 | 23 | <properties> |
24 | 24 | <testSuite>${project.artifactId}</testSuite> |
16 | 16 | import java.io.File; |
17 | 17 | import java.io.FileInputStream; |
18 | 18 | import java.io.FileOutputStream; |
19 | import java.io.FileReader; | |
20 | import java.io.FileWriter; | |
21 | 19 | import java.io.IOException; |
22 | 20 | import java.io.InputStream; |
23 | 21 | import java.io.OutputStream; |
24 | import java.io.Reader; | |
25 | import java.io.Writer; | |
26 | 22 | import java.net.URL; |
27 | 23 | import java.util.Enumeration; |
28 | 24 | import java.util.zip.ZipEntry; |
171 | 167 | return stateLocation.toFile(); |
172 | 168 | } |
173 | 169 | |
174 | public static StringBuffer read(String fileName) throws IOException { | |
175 | return read(new FileReader(fileName)); | |
176 | } | |
177 | ||
178 | public static StringBuffer read(Reader reader) throws IOException { | |
179 | StringBuffer s= new StringBuffer(); | |
180 | try { | |
181 | char[] charBuffer= new char[8196]; | |
182 | int chars= reader.read(charBuffer); | |
183 | while (chars != -1) { | |
184 | s.append(charBuffer, 0, chars); | |
185 | chars= reader.read(charBuffer); | |
186 | } | |
187 | } finally { | |
188 | try { | |
189 | reader.close(); | |
190 | } catch (IOException e) { | |
191 | } | |
192 | } | |
193 | return s; | |
194 | } | |
195 | ||
196 | public static void write(String fileName, StringBuffer content) throws IOException { | |
197 | try (Writer writer= new FileWriter(fileName)) { | |
198 | writer.write(content.toString()); | |
199 | } | |
200 | } | |
201 | ||
202 | 170 | public static void delete(File file) { |
203 | 171 | if (file.exists()) { |
204 | 172 | for (int i= 0; i < MAX_RETRY; i++) { |
1 | 1 | Bundle-ManifestVersion: 2 |
2 | 2 | Bundle-Name: %pluginName |
3 | 3 | Bundle-SymbolicName: org.eclipse.text |
4 | Bundle-Version: 3.9.0.qualifier | |
4 | Bundle-Version: 3.10.0.qualifier | |
5 | 5 | Bundle-Vendor: %providerName |
6 | 6 | Bundle-Localization: plugin |
7 | 7 | Export-Package: |
0 | <?xml version="1.0" encoding="UTF-8"?> | |
1 | <!-- | |
2 | Copyright (c) 2012, 2015 Eclipse Foundation and others. | |
3 | All rights reserved. This program and the accompanying materials | |
4 | are made available under the terms of the Eclipse Distribution License v1.0 | |
5 | which accompanies this distribution, and is available at | |
6 | http://www.eclipse.org/org/documents/edl-v10.php | |
7 | ||
8 | Contributors: | |
9 | Igor Fedorenko - initial implementation | |
10 | --> | |
11 | <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | |
12 | <modelVersion>4.0.0</modelVersion> | |
13 | <parent> | |
14 | <artifactId>eclipse.platform.text</artifactId> | |
15 | <groupId>eclipse.platform.text</groupId> | |
16 | <version>4.13.0-SNAPSHOT</version> | |
17 | </parent> | |
18 | <groupId>org.eclipse.text</groupId> | |
19 | <artifactId>org.eclipse.text</artifactId> | |
20 | <version>3.9.0-SNAPSHOT</version> | |
21 | <packaging>eclipse-plugin</packaging> | |
22 | </project> |
45 | 45 | * Combines the information of the occurrence of a line delimiter. <code>delimiterIndex</code> |
46 | 46 | * is the index where a line delimiter starts, whereas <code>delimiterLength</code>, |
47 | 47 | * indicates the length of the delimiter. |
48 | */ | |
49 | protected static class DelimiterInfo { | |
48 | * @since 3.10 | |
49 | */ | |
50 | public static class DelimiterInfo { | |
50 | 51 | public int delimiterIndex; |
51 | 52 | public int delimiterLength; |
52 | 53 | public String delimiter; |
262 | 262 | } |
263 | 263 | |
264 | 264 | /** |
265 | * Substitutes \R in a regex find pattern with (?>\r\n?|\n) | |
265 | * Substitutes \R in a regex find pattern with {@code (?>\r\n?|\n)} | |
266 | 266 | * |
267 | 267 | * @param findString the original find pattern |
268 | 268 | * @return the transformed find pattern |
22 | 22 | * line delimiters to subclasses. Assuming that '\n' is the only line delimiter, this abstract |
23 | 23 | * implementation defines the following line scheme: |
24 | 24 | * <ul> |
25 | * <li> "" -> [0,0] | |
26 | * <li> "a" -> [0,1] | |
27 | * <li> "\n" -> [0,1], [1,0] | |
28 | * <li> "a\n" -> [0,2], [2,0] | |
29 | * <li> "a\nb" -> [0,2], [2,1] | |
30 | * <li> "a\nbc\n" -> [0,2], [2,3], [5,0] | |
25 | * <li> "" -> [0,0] | |
26 | * <li> "a" -> [0,1] | |
27 | * <li> "\n" -> [0,1], [1,0] | |
28 | * <li> "a\n" -> [0,2], [2,0] | |
29 | * <li> "a\nb" -> [0,2], [2,1] | |
30 | * <li> "a\nbc\n" -> [0,2], [2,3], [5,0] | |
31 | 31 | * </ul> |
32 | 32 | * This class must be subclassed. |
33 | 33 | * |
17 | 17 | import java.util.List; |
18 | 18 | import java.util.Map; |
19 | 19 | import java.util.Objects; |
20 | import java.util.function.Consumer; | |
20 | 21 | import java.util.stream.Collectors; |
21 | 22 | |
22 | 23 | /** |
115 | 116 | // no search strings were added; return a specialized "matches nothing" matcher |
116 | 117 | return new MultiStringMatcher() { |
117 | 118 | @Override |
118 | public List<Match> find(CharSequence text, int offset) { | |
119 | return new LinkedList<>(); | |
119 | public void find(CharSequence text, int offset, Consumer<Match> matches) { | |
120 | return; | |
120 | 121 | } |
121 | 122 | |
122 | 123 | @Override |
193 | 194 | |
194 | 195 | Node output; |
195 | 196 | |
197 | final int depth; | |
198 | ||
199 | Node(int depth) { | |
200 | this.depth= depth; | |
201 | } | |
202 | ||
196 | 203 | Node next(Character c) { |
197 | 204 | return children == null ? null : children.get(c); |
198 | 205 | } |
201 | 208 | if (children == null) { |
202 | 209 | children= new HashMap<>(); |
203 | 210 | } |
204 | return children.computeIfAbsent(Character.valueOf(c), key -> new Node()); | |
211 | return children.computeIfAbsent(Character.valueOf(c), key -> new Node(depth + 1)); | |
205 | 212 | } |
206 | 213 | |
207 | 214 | boolean hasChildren() { |
210 | 217 | |
211 | 218 | @Override |
212 | 219 | public String toString() { |
213 | return "Match: " + (match == null ? "null" : '>' + match + '<') //$NON-NLS-1$ //$NON-NLS-2$ | |
214 | + " Children: " + (children == null ? "<none>" : children.keySet().stream().map(c -> c.toString()).collect(Collectors.joining(", "))); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ | |
220 | return "[depth=" + depth + ", match=" + match //$NON-NLS-1$ //$NON-NLS-2$ | |
221 | + ", children=" + (children == null ? "<none>" : children.keySet().stream().map(c -> c.toString()).collect(Collectors.joining(", "))) //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ | |
222 | + ']'; | |
215 | 223 | } |
216 | 224 | } |
217 | 225 | |
218 | 226 | /** Root node of the trie. */ |
219 | private final Node root= new Node() { | |
227 | private final Node root= new Node(0) { | |
220 | 228 | @Override |
221 | 229 | Node next(Character c) { |
222 | 230 | // Implements the sentinel loop on the root node for all non-matching characters. |
250 | 258 | // s, r, and state are kept as in the paper. |
251 | 259 | List<Node> queue= new LinkedList<>(); |
252 | 260 | for (Node s : root.children.values()) { |
253 | if (s.children != null) { | |
261 | if (s.hasChildren()) { | |
254 | 262 | // No need to queue nodes without children since we don't do anything |
255 | 263 | // with them anyway. |
256 | 264 | queue.add(s); |
262 | 270 | for (Map.Entry<Character, Node> entry : r.children.entrySet()) { |
263 | 271 | Character c= entry.getKey(); |
264 | 272 | Node s= entry.getValue(); |
265 | if (s.children != null) { | |
273 | if (s.hasChildren()) { | |
266 | 274 | queue.add(s); |
267 | 275 | } |
268 | 276 | Node state= r.fail; |
278 | 286 | } |
279 | 287 | } |
280 | 288 | } |
289 | } | |
290 | ||
291 | /** | |
292 | * Finds all occurrences of any of the search strings of the {@link MultiStringMatcher} in the | |
293 | * given {@code text} starting at the given {@code offset}, including overlapping occurrences. | |
294 | * | |
295 | * @param text to search (not {@code null}) | |
296 | * @param offset to start searching at | |
297 | * @param matches {@link Consumer} all matches are fed to | |
298 | * | |
299 | * @since 3.10 | |
300 | */ | |
301 | public void find(CharSequence text, int offset, Consumer<Match> matches) { | |
302 | // Main search loop of the standard Aho-Corasick algorithm. | |
303 | int textEnd= text.length(); | |
304 | Node node= root; | |
305 | for (int i= offset; i < textEnd; i++) { | |
306 | Character c= Character.valueOf(text.charAt(i)); | |
307 | Node next; | |
308 | while ((next= node.next(c)) == null) { | |
309 | node= node.fail; | |
310 | } | |
311 | node= next; | |
312 | if (node.match != null) { | |
313 | matches.accept(new MatchResult(node.match, i - node.depth + 1)); | |
314 | } | |
315 | Node out= node.output; | |
316 | while (out != null) { | |
317 | matches.accept(new MatchResult(out.match, i - out.depth + 1)); | |
318 | out= out.output; | |
319 | } | |
320 | } | |
321 | } | |
322 | ||
323 | /** | |
324 | * Finds all occurrences of any of the search strings of the {@link MultiStringMatcher} in the | |
325 | * given {@code text} starting at the given {@code offset}, including overlapping occurrences. | |
326 | * | |
327 | * @param text to search (not {@code null}) | |
328 | * @param offset to start searching at | |
329 | * @return a possibly empty list of matches | |
330 | */ | |
331 | public List<Match> find(CharSequence text, int offset) { | |
332 | List<Match> matches= new LinkedList<>(); | |
333 | find(text, offset, matches::add); | |
334 | return matches; | |
281 | 335 | } |
282 | 336 | |
283 | 337 | /** |
320 | 374 | int textEnd= text.length(); |
321 | 375 | Match primaryMatch= null; |
322 | 376 | Match subMatch= null; |
323 | boolean failover= false; | |
324 | 377 | Node node= root; |
325 | 378 | for (int i= offset; i < textEnd; i++) { |
326 | 379 | Character c= Character.valueOf(text.charAt(i)); |
327 | 380 | Node next= node.next(c); |
328 | 381 | if (next == null) { |
329 | // Fell off the trie. | |
382 | // Can't continue on this path. | |
330 | 383 | if (primaryMatch != null) { |
331 | 384 | // Return primary match because any other match must have a higher offset. |
332 | 385 | return primaryMatch; |
333 | 386 | } |
334 | // Search for other trie to change to. | |
387 | // Search for another path to continue matching. | |
335 | 388 | do { |
336 | 389 | node= node.fail; |
337 | 390 | } while ((next= node.next(c)) == null); |
338 | failover= (node != root); | |
339 | if (!failover && subMatch != null) { | |
340 | // We fell of the trie and could not switch to another. Return best sub-match | |
341 | // if possible. | |
342 | return subMatch; | |
391 | if (subMatch != null) { | |
392 | if (next == root) { | |
393 | // We fell off the trie and could not switch to another. Return the best | |
394 | // sub-match. | |
395 | return subMatch; | |
396 | } else if (subMatch.getOffset() < i - node.depth) { | |
397 | // The new path starts at i - node.depth == i - next.depth + 1, so if a | |
398 | // sub-match is earlier, we may return it. Any primary match on this path | |
399 | // or on any other path we might switch to later on will have a higher | |
400 | // offset, and so will any sub-matches we might discover on these paths. | |
401 | return subMatch; | |
402 | } | |
343 | 403 | } |
344 | 404 | } |
345 | 405 | node= next; |
346 | 406 | if (node.match != null) { |
347 | int newOffset= i - node.match.length() + 1; | |
348 | // On a failover trie the sub match can be better. | |
349 | // And if it is return it because nothing better will follow. | |
350 | if (failover && subMatch != null && subMatch.getOffset() < newOffset) { | |
351 | return subMatch; | |
352 | } | |
353 | 407 | // Any new primary match is better because all have the same offset but any new one |
354 | // must be longer. | |
355 | primaryMatch= new MatchResult(node.match, newOffset); | |
408 | // must be longer. An existing sub-match from a previous path is checked above. | |
409 | primaryMatch= new MatchResult(node.match, i - node.depth + 1); | |
356 | 410 | if (!node.hasChildren()) { |
357 | // We will fall off the trie on the next character, so we can return right here | |
411 | // We will fall off the trie on the next character, so we can return right here. | |
358 | 412 | return primaryMatch; |
359 | 413 | } |
360 | 414 | } |
363 | 417 | if (primaryMatch == null) { |
364 | 418 | Node out= node.output; |
365 | 419 | if (out != null) { |
366 | int newOffset= i - out.match.length() + 1; | |
420 | int newOffset= i - out.depth + 1; | |
367 | 421 | if (subMatch == null |
368 | 422 | || newOffset < subMatch.getOffset() |
369 | || (newOffset == subMatch.getOffset() && out.match.length() > subMatch.getText().length())) { | |
423 | || (newOffset == subMatch.getOffset() && out.depth > subMatch.getText().length())) { | |
370 | 424 | subMatch= new MatchResult(out.match, newOffset); |
371 | 425 | } |
372 | 426 | } |
373 | 427 | } |
374 | 428 | } |
375 | 429 | return primaryMatch != null ? primaryMatch : subMatch; |
376 | } | |
377 | ||
378 | /** | |
379 | * Finds all occurrences of any of the search strings of the {@link MultiStringMatcher} in the | |
380 | * given {@code text} starting at the given {@code offset}, including overlapping occurrences. | |
381 | * | |
382 | * @param text to search (not {@code null}) | |
383 | * @param offset to start searching at | |
384 | * @return a possibly empty list of matches | |
385 | */ | |
386 | public List<Match> find(CharSequence text, int offset) { | |
387 | // Main search loop of the standard Aho-Corasick algorithm. | |
388 | int textEnd= text.length(); | |
389 | List<Match> matches= new LinkedList<>(); | |
390 | Node node= root; | |
391 | for (int i= offset; i < textEnd; i++) { | |
392 | Character c= Character.valueOf(text.charAt(i)); | |
393 | Node next; | |
394 | while ((next= node.next(c)) == null) { | |
395 | node= node.fail; | |
396 | } | |
397 | node= next; | |
398 | if (node.match != null) { | |
399 | matches.add(new MatchResult(node.match, i - node.match.length() + 1)); | |
400 | } | |
401 | Node out= node.output; | |
402 | while (out != null) { | |
403 | matches.add(new MatchResult(out.match, i - out.match.length() + 1)); | |
404 | out= out.output; | |
405 | } | |
406 | } | |
407 | return matches; | |
408 | 430 | } |
409 | 431 | |
410 | 432 | /** |
0 | 0 | /******************************************************************************* |
1 | * Copyright (c) 2000, 2016 IBM Corporation and others. | |
1 | * Copyright (c) 2000, 2019 IBM Corporation and others. | |
2 | 2 | * |
3 | 3 | * This program and the accompanying materials |
4 | 4 | * are made available under the terms of the Eclipse Public License 2.0 |
20 | 20 | import java.util.ListIterator; |
21 | 21 | import java.util.Map; |
22 | 22 | import java.util.Map.Entry; |
23 | import java.util.Objects; | |
23 | 24 | import java.util.Set; |
24 | 25 | |
25 | 26 | import org.eclipse.core.runtime.Assert; |
26 | 27 | |
28 | import org.eclipse.jface.text.AbstractLineTracker.DelimiterInfo; | |
27 | 29 | |
28 | 30 | /** |
29 | 31 | * A collection of text functions. |
38 | 40 | /** |
39 | 41 | * Default line delimiters used by the text functions of this class. |
40 | 42 | */ |
43 | // Note: nextDelimiter implementation is sensitive to element order | |
41 | 44 | public final static String[] DELIMITERS= new String[] { "\n", "\r", "\r\n" }; //$NON-NLS-3$ //$NON-NLS-2$ //$NON-NLS-1$ |
42 | 45 | |
43 | 46 | /** |
59 | 62 | * @return the line delimiter |
60 | 63 | */ |
61 | 64 | public static String determineLineDelimiter(String text, String hint) { |
62 | try { | |
63 | int[] info= indexOf(DELIMITERS, text, 0); | |
64 | return DELIMITERS[info[1]]; | |
65 | } catch (ArrayIndexOutOfBoundsException x) { | |
66 | } | |
67 | return hint; | |
68 | } | |
69 | ||
70 | /** | |
71 | * Returns the starting position and the index of the first matching search string | |
72 | * in the given text that is greater than the given offset. If more than one search | |
73 | * string matches with the same starting position then the longest one is returned. | |
65 | String delimiter = nextDelimiter(text, 0).delimiter; | |
66 | return delimiter != null ? delimiter : hint; | |
67 | } | |
68 | ||
69 | /** | |
70 | * Returns the starting position and the index of the first matching search string in the given | |
71 | * text that is greater than the given offset. If more than one search string matches with the | |
72 | * same starting position then the longest one is returned. | |
74 | 73 | * |
75 | 74 | * @param searchStrings the strings to search for |
76 | 75 | * @param text the text to be searched |
77 | 76 | * @param offset the offset at which to start the search |
78 | * @return an <code>int[]</code> with two elements where the first is the starting offset, the second the index of the found | |
79 | * search string in the given <code>searchStrings</code> array, returns <code>[-1, -1]</code> if no match exists | |
80 | */ | |
77 | * @return an <code>int[]</code> with two elements where the first is the starting offset, the | |
78 | * second the index of the found search string in the given <code>searchStrings</code> | |
79 | * array, returns <code>[-1, -1]</code> if no match exists | |
80 | * @deprecated use {@link MultiStringMatcher#indexOf(CharSequence, int, String...)} instead. | |
81 | * Notable differences: | |
82 | * <ul> | |
83 | * <li>new matcher indexOf does not allow negative offsets (old matcher treated them | |
84 | * as <code>0</code>)</li> | |
85 | * <li>new matcher indexOf will tolerate <code>null</code> and empty search strings | |
86 | * (old accepted empty but throw on <code>null</code>)</li> | |
87 | * <li>new matcher indexOf will <b>not</b> match empty string (old matched empty if | |
88 | * nothing else matched)</li> | |
89 | * </ul> | |
90 | * For the common case of searching the next default {@link #DELIMITERS delimiter} | |
91 | * use the optimized {@link #nextDelimiter(CharSequence, int)} method instead. | |
92 | */ | |
93 | @Deprecated | |
81 | 94 | public static int[] indexOf(String[] searchStrings, String text, int offset) { |
82 | ||
83 | int[] result= { -1, -1 }; | |
84 | int zeroIndex= -1; | |
85 | ||
86 | for (int i= 0; i < searchStrings.length; i++) { | |
87 | ||
88 | int length= searchStrings[i].length(); | |
89 | ||
90 | if (length == 0) { | |
91 | zeroIndex= i; | |
92 | continue; | |
93 | } | |
94 | ||
95 | int index= text.indexOf(searchStrings[i], offset); | |
96 | if (index >= 0) { | |
97 | ||
98 | if (result[0] == -1) { | |
99 | result[0]= index; | |
100 | result[1]= i; | |
101 | } else if (index < result[0]) { | |
102 | result[0]= index; | |
103 | result[1]= i; | |
104 | } else if (index == result[0] && length > searchStrings[result[1]].length()) { | |
105 | result[0]= index; | |
106 | result[1]= i; | |
95 | // For compatibility this will throw a NullPointerException like the old implementation | |
96 | // (instead of an IllegalArgumentException what would be the result from MultiStringMatcher.indexOf) | |
97 | // and mimic the strange result for empty search string match from the old method. | |
98 | Objects.requireNonNull(searchStrings); | |
99 | for (String searchString : searchStrings) { | |
100 | Objects.requireNonNull(searchString); | |
101 | } | |
102 | if (offset < 0) { | |
103 | offset = 0; // for compatibility with old implementation | |
104 | } | |
105 | final MultiStringMatcher.Match match= MultiStringMatcher.indexOf(text, offset, searchStrings); | |
106 | if (match != null) { | |
107 | for (int i= 0; i < searchStrings.length; i++) { | |
108 | if (match.getText().equals(searchStrings[i])) { | |
109 | return new int[] { match.getOffset(), i }; | |
107 | 110 | } |
108 | 111 | } |
109 | } | |
110 | ||
111 | if (zeroIndex > -1 && result[0] == -1) { | |
112 | result[0]= 0; | |
113 | result[1]= zeroIndex; | |
114 | } | |
115 | ||
116 | return result; | |
112 | } else { | |
113 | // no match must check for empty search strings and mimic old return value | |
114 | // search reversed because we want the last empty search string | |
115 | for (int i= searchStrings.length - 1; i >= 0; i--) { | |
116 | if (searchStrings[i].length() == 0) { | |
117 | return new int[] { 0, i }; | |
118 | } | |
119 | } | |
120 | } | |
121 | return new int[] { -1, -1 }; | |
117 | 122 | } |
118 | 123 | |
119 | 124 | /** |
494 | 499 | try { |
495 | 500 | lineDelimiter= document.getLineDelimiter(0); |
496 | 501 | } catch (BadLocationException x) { |
502 | // usually impossible for the first line | |
497 | 503 | } |
498 | 504 | |
499 | 505 | if (lineDelimiter != null) |
575 | 581 | } |
576 | 582 | return null; |
577 | 583 | } |
584 | ||
585 | /** | |
586 | * Search for the first standard line delimiter in text starting at given offset. Standard line | |
587 | * delimiters are those defined in {@link #DELIMITERS}. This is a faster variant of the equal | |
588 | * | |
589 | * <pre> | |
590 | * MultiStringMatcher.indexOf(TextUtilities.DELIMITERS, text, offset) | |
591 | * </pre> | |
592 | * | |
593 | * @param text the text to be searched. Not <code>null</code>. | |
594 | * @param offset the offset in text at which to start the search | |
595 | * @return a {@link DelimiterInfo}. If no delimiter was found | |
596 | * {@link DelimiterInfo#delimiterIndex} is <code>-1</code> and | |
597 | * {@link DelimiterInfo#delimiter} is <code>null</code>. | |
598 | * @since 3.10 | |
599 | */ | |
600 | public static DelimiterInfo nextDelimiter(CharSequence text, int offset) { | |
601 | final DelimiterInfo info= new DelimiterInfo(); | |
602 | char ch; | |
603 | final int length= text.length(); | |
604 | for (int i= offset; i < length; i++) { | |
605 | ch= text.charAt(i); | |
606 | if (ch == '\r') { | |
607 | info.delimiterIndex= i; | |
608 | if (i + 1 < length && text.charAt(i + 1) == '\n') { | |
609 | info.delimiter= DELIMITERS[2]; | |
610 | break; | |
611 | } | |
612 | info.delimiter= DELIMITERS[1]; | |
613 | break; | |
614 | } else if (ch == '\n') { | |
615 | info.delimiterIndex= i; | |
616 | info.delimiter= DELIMITERS[0]; | |
617 | break; | |
618 | } | |
619 | } | |
620 | if (info.delimiter == null) { | |
621 | info.delimiterIndex= -1; | |
622 | } else { | |
623 | info.delimiterLength= info.delimiter.length(); | |
624 | } | |
625 | return info; | |
626 | } | |
578 | 627 | } |
26 | 26 | * delimiters to subclasses. Assuming that '\n' is the only line delimiter, this abstract |
27 | 27 | * implementation defines the following line scheme: |
28 | 28 | * <ul> |
29 | * <li> "" -> [0,0] | |
30 | * <li> "a" -> [0,1] | |
31 | * <li> "\n" -> [0,1], [1,0] | |
32 | * <li> "a\n" -> [0,2], [2,0] | |
33 | * <li> "a\nb" -> [0,2], [2,1] | |
34 | * <li> "a\nbc\n" -> [0,2], [2,3], [5,0] | |
29 | * <li> "" -> [0,0] | |
30 | * <li> "a" -> [0,1] | |
31 | * <li> "\n" -> [0,1], [1,0] | |
32 | * <li> "a\n" -> [0,2], [2,0] | |
33 | * <li> "a\nb" -> [0,2], [2,1] | |
34 | * <li> "a\nbc\n" -> [0,2], [2,3], [5,0] | |
35 | 35 | * </ul> |
36 | 36 | * <p> |
37 | 37 | * This class must be subclassed. |
207 | 207 | * This means that for offsets smaller than the length, the following holds: |
208 | 208 | * </p> |
209 | 209 | * <p> |
210 | * <code>line.offset <= offset < line.offset + offset.length</code>. | |
210 | * <code>line.offset <= offset < line.offset + offset.length</code>. | |
211 | 211 | * </p> |
212 | 212 | * <p> |
213 | 213 | * If <code>offset</code> is the document length, then this is true: |
1 | 1 | Bundle-ManifestVersion: 2 |
2 | 2 | Bundle-Name: %pluginName |
3 | 3 | Bundle-SymbolicName: org.eclipse.text.quicksearch;singleton:=true |
4 | Bundle-Version: 1.0.0.qualifier | |
4 | Bundle-Version: 1.0.100.qualifier | |
5 | 5 | Bundle-Activator: org.eclipse.text.quicksearch.internal.ui.QuickSearchActivator |
6 | 6 | Require-Bundle: org.eclipse.ui;bundle-version="[3.113.0,4.0.0)", |
7 | 7 | org.eclipse.core.resources;bundle-version="[3.13.0,4.0.0)", |
19 | 19 | Export-Package: org.eclipse.text.quicksearch.internal.core;x-internal:=true, |
20 | 20 | org.eclipse.text.quicksearch.internal.core.pathmatch;x-internal:=true, |
21 | 21 | org.eclipse.text.quicksearch.internal.core.preferences;x-internal:=true, |
22 | org.eclipse.text.quicksearch.internal.core.priority;x-internal:=true, | |
23 | org.eclipse.text.quicksearch.internal.ui;x-internal:=true, | |
22 | org.eclipse.text.quicksearch.internal.core.priority;x-friends:="org.eclipse.text.quicksearch.tests", | |
23 | org.eclipse.text.quicksearch.internal.ui;x-friends:="org.eclipse.text.quicksearch.tests", | |
24 | 24 | org.eclipse.text.quicksearch.internal.util;x-internal:=true |
25 | 25 | Import-Package: org.eclipse.core.runtime;version="3.5.0", |
26 | 26 | org.eclipse.core.runtime.jobs, |
14 | 14 | providerName= Eclipse.org |
15 | 15 | searchMenu.label= Se&arch |
16 | 16 | quickSearch.label= Quick Search |
17 | quickSearch.ellipsis= Quick Search... | |
17 | quickSearch.ellipsis= &Quick Search... | |
18 | 18 | quickSearch.tooltip=Search for a text pattern in the workspace |
19 | quickAccess.category.label=File content |
106 | 106 | name="%quickSearch.label"> |
107 | 107 | </page> |
108 | 108 | </extension> |
109 | <extension | |
110 | point="org.eclipse.ui.quickAccess"> | |
111 | <computer | |
112 | class="org.eclipse.text.quicksearch.internal.ui.QuickSearchQuickAccessComputer" | |
113 | name="%quickAccess.category.label" | |
114 | requiresUIAccess="false"> | |
115 | </computer> | |
116 | </extension> | |
109 | 117 | |
110 | 118 | </plugin> |
0 | <?xml version="1.0" encoding="UTF-8"?> | |
1 | <!-- Copyright (c) 2012, 2014. 2019 Eclipse Foundation and others. All rights | |
2 | reserved. This program and the accompanying materials are made available | |
3 | under the terms of the Eclipse Distribution License v2.0 which accompanies | |
4 | this distribution, and is available at http://www.eclipse.org/org/documents/edl-v20.php | |
5 | ||
6 | SPDX-License-Identifier: EPL-2.0 | |
7 | ||
8 | Contributors: Igor Fedorenko - initial implementation | |
9 | Pivotal Inc - copy adapted for quicksearch bundle | |
10 | --> | |
11 | <project xmlns="http://maven.apache.org/POM/4.0.0" | |
12 | xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | |
13 | xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | |
14 | <modelVersion>4.0.0</modelVersion> | |
15 | <parent> | |
16 | <artifactId>eclipse.platform.text</artifactId> | |
17 | <groupId>eclipse.platform.text</groupId> | |
18 | <version>4.13.0-SNAPSHOT</version> | |
19 | </parent> | |
20 | <groupId>org.eclipse.core</groupId> | |
21 | <artifactId>org.eclipse.text.quicksearch</artifactId> | |
22 | <version>1.0.0-SNAPSHOT</version> | |
23 | <packaging>eclipse-plugin</packaging> | |
24 | ||
25 | <properties> | |
26 | <skipAPIAnalysis>true</skipAPIAnalysis> <!-- https://bugs.eclipse.org/bugs/show_bug.cgi?id=548518#c41 --> | |
27 | </properties> | |
28 | </project> |
+1
-1
194 | 194 | if (isTrivial()) { |
195 | 195 | return Arrays.asList(); |
196 | 196 | } else { |
197 | List<TextRange> ranges = new ArrayList<QuickTextQuery.TextRange>(); | |
197 | List<TextRange> ranges = new ArrayList<>(); | |
198 | 198 | Matcher matcher = pattern.matcher(text); |
199 | 199 | while (matcher.find()) { |
200 | 200 | int start = matcher.start(); |
+4
-2
38 | 38 | * Keeps track of currently found matches. Items are added as they are found and may also |
39 | 39 | * be removed when the query changed and they become invalid. |
40 | 40 | */ |
41 | private Set<LineItem> matches = new HashSet<LineItem>(2000); | |
41 | private Set<LineItem> matches = new HashSet<>(2000); | |
42 | 42 | |
43 | 43 | /** |
44 | 44 | * Scheduling rule used by Jobs that work on the matches collection. |
242 | 242 | if (!query.isTrivial()) { |
243 | 243 | walker.init(); //Reinitialize the walker work queue to its starting state |
244 | 244 | walker.resume(); //Allow walker to resume when we release the scheduling rule. |
245 | } else { | |
246 | walker.stop(); | |
245 | 247 | } |
246 | 248 | } |
247 | 249 | } |
305 | 307 | //Walker can be null if job was canceled because dialog closed. But stuff like |
306 | 308 | //the job that shows 'Searching ...' doesn't instantly stop and may still |
307 | 309 | //be asking the incremental update job whether its done. |
308 | return walker!=null && walker.isDone(); | |
310 | return /*(incrementalUpdate != null && incrementalUpdate.getState() != Job.NONE) ||*/ (walker!=null && walker.isDone()); | |
309 | 311 | } |
310 | 312 | |
311 | 313 | public void requestMoreResults() { |
+11
-2
58 | 58 | } |
59 | 59 | |
60 | 60 | protected void init() { |
61 | queue = new PriorityQueue<ResourceWalker.QItem>(); | |
61 | queue = new PriorityQueue<>(); | |
62 | 62 | queue.add(new QItem(0, ResourcesPlugin.getWorkspace().getRoot())); |
63 | 63 | } |
64 | 64 | |
89 | 89 | } |
90 | 90 | |
91 | 91 | /** |
92 | * Request that the walker stops walking at the next reasonable opportunity and drop | |
93 | * all pending workitems. The walker cannot be resumed and must be reinitialized. | |
94 | */ | |
95 | public void stop() { | |
96 | this.queue = null; | |
97 | this.suspend = false; | |
98 | } | |
99 | ||
100 | /** | |
92 | 101 | * Request the walker to be restarted... i.e. begin walking the resource tree from |
93 | 102 | * the initial state. |
94 | 103 | */ |
95 | 104 | |
96 | 105 | /** |
97 | * Request that the walker be resumed. This clears the 'supsend' state if it is set | |
106 | * Request that the walker be resumed. This clears the 'suspend' state if it is set | |
98 | 107 | * and ensures that the Job is scheduled. |
99 | 108 | */ |
100 | 109 | public void resume() { |
+1
-1
73 | 73 | */ |
74 | 74 | private String[] parseStringList(String raw) { |
75 | 75 | String[] elements = raw.split("[,\n]"); //$NON-NLS-1$ |
76 | List<String> list = new ArrayList<String>(elements.length); | |
76 | List<String> list = new ArrayList<>(elements.length); | |
77 | 77 | for (String e : elements) { |
78 | 78 | e = e.trim(); |
79 | 79 | if (!e.isEmpty()) { |
+23
-45
11 | 11 | *******************************************************************************/ |
12 | 12 | package org.eclipse.text.quicksearch.internal.core.priority; |
13 | 13 | |
14 | import java.net.URI; | |
15 | import java.util.HashSet; | |
16 | import java.util.Set; | |
17 | ||
18 | 14 | import org.eclipse.core.resources.IContainer; |
19 | import org.eclipse.core.resources.IProject; | |
20 | 15 | import org.eclipse.core.resources.IResource; |
21 | import org.eclipse.core.resources.ResourcesPlugin; | |
16 | import org.eclipse.core.resources.IWorkspaceRoot; | |
17 | import org.eclipse.core.runtime.IPath; | |
22 | 18 | import org.eclipse.text.quicksearch.internal.core.preferences.QuickSearchPreferences; |
23 | 19 | |
24 | 20 | /** |
65 | 61 | "bin", "build", "target" //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
66 | 62 | }; |
67 | 63 | |
68 | public Set<IResource> ignoredResources = null; | |
69 | ||
70 | 64 | @Override |
71 | 65 | public double priority(IResource r) { |
72 | 66 | if (r!=null && r.isAccessible()) { |
73 | 67 | if (ignoreDerived && r.isDerived()) { |
74 | 68 | return PRIORITY_IGNORE; |
75 | 69 | } |
76 | if (ignoredResources!=null && ignoredResources.contains(r)) { | |
70 | if (isIgnoredLinkedContainer(r)) { | |
77 | 71 | return PRIORITY_IGNORE; |
78 | 72 | } |
79 | 73 | String name = r.getName(); |
98 | 92 | } |
99 | 93 | |
100 | 94 | /** |
95 | * We want to avoid searching the same files / folders twice in cases where users have 'overlapping projects'. | |
96 | * I.e a project contains folders that are actually correspond to other projects also imported in the workspace. | |
97 | * <p> | |
98 | * See https://issuetracker.springsource.com/browse/STS-3783 | |
99 | */ | |
100 | private boolean isIgnoredLinkedContainer(IResource resource) { | |
101 | if (!(resource instanceof IContainer) || !resource.isLinked(IResource.NONE)) { | |
102 | return false; | |
103 | } | |
104 | ||
105 | IPath location = resource.getLocation(); | |
106 | if (location == null) { | |
107 | return true; | |
108 | } | |
109 | IWorkspaceRoot root = resource.getWorkspace().getRoot(); | |
110 | IContainer linkTarget = root.getContainerForLocation(location); | |
111 | return linkTarget != null; | |
112 | } | |
113 | ||
114 | /** | |
101 | 115 | * Initialize some configurable settings from an instance of QuickSearchPreferences |
102 | 116 | */ |
103 | 117 | public void configure(QuickSearchPreferences preferences) { |
113 | 127 | if (pref!=null) { |
114 | 128 | this.ignoredPrefixes = pref; |
115 | 129 | } |
116 | computeIgnoredFolders(); | |
117 | 130 | } |
118 | 131 | |
119 | /** | |
120 | * We want to avoid searchin the same files / folders twice in cases where users have 'overlapping projects'. | |
121 | * I.e a project contains folders that are actually correspond to other projects also imported in the workspace. | |
122 | * <p> | |
123 | * See https://issuetracker.springsource.com/browse/STS-3783 | |
124 | * <p> | |
125 | * This method computes a set of folders to ignore. | |
126 | */ | |
127 | private void computeIgnoredFolders() { | |
128 | //TODO: Hopefully this won't take too long to compute. Otherwise we may need to look at ways of caching it. | |
129 | // it probably doesn't change that often. | |
130 | IProject[] allprojects = ResourcesPlugin.getWorkspace().getRoot().getProjects(); | |
131 | for (IProject p : allprojects) { | |
132 | if (p.isAccessible()) { | |
133 | URI location = p.getLocationURI(); | |
134 | if (location!=null) { | |
135 | IContainer[] containers = ResourcesPlugin.getWorkspace().getRoot().findContainersForLocationURI(location); | |
136 | if (containers!=null) { | |
137 | for (IContainer folder : containers) { | |
138 | if (!folder.equals(p)) { | |
139 | ignore(folder); | |
140 | } | |
141 | } | |
142 | } | |
143 | } | |
144 | } | |
145 | } | |
146 | } | |
147 | ||
148 | private void ignore(IContainer folder) { | |
149 | if (ignoredResources==null) { | |
150 | ignoredResources = new HashSet<IResource>(); | |
151 | } | |
152 | ignoredResources.add(folder); | |
153 | } | |
154 | 132 | } |
+2
-2
144 | 144 | */ |
145 | 145 | private PrioriTree ensureChild(String segment) { |
146 | 146 | if (children==null) { |
147 | children = new HashMap<String, PrioriTree>(); | |
147 | children = new HashMap<>(); | |
148 | 148 | } |
149 | 149 | PrioriTree child = children.get(segment); |
150 | 150 | if (child==null) { |
177 | 177 | |
178 | 178 | /** |
179 | 179 | * Locate tree node corresponding to a given path. |
180 | * @param fullPath | |
180 | * @param path | |
181 | 181 | * @return The node or null if no corresponding node exists in the tree. |
182 | 182 | */ |
183 | 183 | private PrioriTree lookup(IPath path) { |
+1
-0
39 | 39 | public static String QuickSearchDialog_caseInsensitive_label; |
40 | 40 | public static String QuickSearchDialog_patternHint; |
41 | 41 | public static String QuickTextSearch_updateMatchesJob; |
42 | public static String quickAccessMatch; | |
42 | 43 | |
43 | 44 | static { |
44 | 45 | // initialize resource bundle |
+21
-10
28 | 28 | import org.eclipse.ui.IEditorInput; |
29 | 29 | import org.eclipse.ui.IEditorPart; |
30 | 30 | import org.eclipse.ui.IEditorReference; |
31 | import org.eclipse.ui.ISelectionService; | |
31 | 32 | import org.eclipse.ui.IWorkbenchPage; |
32 | 33 | import org.eclipse.ui.IWorkbenchWindow; |
33 | 34 | import org.eclipse.ui.PartInitException; |
94 | 95 | } |
95 | 96 | |
96 | 97 | private Collection<IFile> getOpenFiles() { |
98 | if (window == null) { | |
99 | return Collections.emptyList(); | |
100 | } | |
97 | 101 | try { |
98 | 102 | IWorkbenchPage page = window.getActivePage(); |
99 | 103 | if (page!=null) { |
100 | Collection<IFile> files = new ArrayList<IFile>(); | |
104 | Collection<IFile> files = new ArrayList<>(); | |
101 | 105 | IEditorReference[] editors = page.getEditorReferences(); |
102 | 106 | if (editors!=null) { |
103 | 107 | for (IEditorReference editor : editors) { |
104 | 108 | try { |
105 | 109 | IEditorInput input = editor.getEditorInput(); |
106 | 110 | if (input!=null) { |
107 | IFile file = (IFile) input.getAdapter(IFile.class); | |
111 | IFile file = input.getAdapter(IFile.class); | |
108 | 112 | if (file != null) { |
109 | 113 | files.add(file); |
110 | 114 | } |
132 | 136 | * @return IFile or null if there is no current editor or the editor isn't associated to a file. |
133 | 137 | */ |
134 | 138 | private IFile getActiveFile() { |
139 | if (window == null) { | |
140 | return null; | |
141 | } | |
135 | 142 | IWorkbenchPage page = window.getActivePage(); |
136 | 143 | if (page!=null) { |
137 | 144 | IEditorPart editor = page.getActiveEditor(); |
138 | 145 | if (editor!=null) { |
139 | 146 | IEditorInput input = editor.getEditorInput(); |
140 | 147 | if (input!=null) { |
141 | return (IFile) input.getAdapter(IFile.class); | |
148 | return input.getAdapter(IFile.class); | |
142 | 149 | } |
143 | 150 | } |
144 | 151 | } |
150 | 157 | * a Structured selection (e.g. in navigator or project/package explorer) |
151 | 158 | */ |
152 | 159 | private Collection<IResource> getSelectedResources() { |
153 | ISelection _s = window.getSelectionService().getSelection(); | |
154 | if (_s!=null && _s instanceof IStructuredSelection) { | |
155 | IStructuredSelection s = (IStructuredSelection) _s; | |
156 | if (s!=null && !s.isEmpty()) { | |
157 | Object[] elements = s.toArray(); | |
158 | List<IResource> resources = new ArrayList<IResource>(elements.length); | |
160 | if (window == null) { | |
161 | return Collections.emptyList(); | |
162 | } | |
163 | ISelectionService selectionService = window.getSelectionService(); | |
164 | ISelection selection = selectionService.getSelection(); | |
165 | if (selection instanceof IStructuredSelection) { | |
166 | IStructuredSelection structuredSelection = (IStructuredSelection) selection; | |
167 | if (!structuredSelection.isEmpty()) { | |
168 | Object[] elements = structuredSelection.toArray(); | |
169 | List<IResource> resources = new ArrayList<>(elements.length); | |
159 | 170 | for (Object e : elements) { |
160 | 171 | if (e instanceof IResource) { |
161 | 172 | resources.add((IResource) e); |
162 | 173 | } else if (e instanceof IAdaptable) { |
163 | 174 | IAdaptable ae = (IAdaptable) e; |
164 | IResource r = (IResource) ae.getAdapter(IResource.class); | |
175 | IResource r = ae.getAdapter(IResource.class); | |
165 | 176 | if (r!=null) { |
166 | 177 | resources.add(r); |
167 | 178 | } |
+22
-29
85 | 85 | import org.eclipse.swt.events.TraverseEvent; |
86 | 86 | import org.eclipse.swt.events.TraverseListener; |
87 | 87 | import org.eclipse.swt.graphics.Color; |
88 | import org.eclipse.swt.graphics.FontMetrics; | |
89 | import org.eclipse.swt.graphics.GC; | |
90 | 88 | import org.eclipse.swt.graphics.Image; |
91 | 89 | import org.eclipse.swt.graphics.Point; |
92 | 90 | import org.eclipse.swt.graphics.Rectangle; |
196 | 194 | public IStatus runInUIThread(IProgressMonitor mon) { |
197 | 195 | if (!mon.isCanceled() && progressLabel!=null && !progressLabel.isDisposed()) { |
198 | 196 | if (searcher==null || !searcher.isActive()) { |
199 | progressLabel.setText(""); //$NON-NLS-1$ | |
197 | progressLabel.setText(EMPTY_STRING); | |
200 | 198 | } else { |
201 | 199 | progressLabel.setText(NLS.bind(Messages.QuickSearchDialog_searching, currentFileInfo(searcher.getCurrentFile(), animate))); |
202 | 200 | animate = (animate+1)%4; |
232 | 230 | cell.setText(text.getString()); |
233 | 231 | cell.setStyleRanges(text.getStyleRanges()); |
234 | 232 | } else { |
235 | cell.setText(""); //$NON-NLS-1$ | |
233 | cell.setText(EMPTY_STRING); | |
236 | 234 | cell.setStyleRanges(null); |
237 | 235 | } |
238 | 236 | cell.setImage(getBlankImage()); |
270 | 268 | }; |
271 | 269 | cell.setStyleRanges(styleRanges); |
272 | 270 | } else { |
273 | cell.setText(""); //$NON-NLS-1$ | |
271 | cell.setText(EMPTY_STRING); | |
274 | 272 | cell.setStyleRanges(null); |
275 | 273 | } |
276 | 274 | cell.setImage(getBlankImage()); |
419 | 417 | if (initialPatternText==null) { |
420 | 418 | String lastSearch = settings.get(DIALOG_LAST_QUERY); |
421 | 419 | if (lastSearch==null) { |
422 | lastSearch = ""; //$NON-NLS-1$ | |
420 | lastSearch = EMPTY_STRING; | |
423 | 421 | } |
424 | 422 | pattern.setText(lastSearch); |
425 | pattern.setSelection(0, lastSearch.length()); | |
423 | pattern.selectAll(); | |
426 | 424 | } |
427 | 425 | if (settings.get(DIALOG_PATH_FILTER)!=null) { |
428 | 426 | String filter = settings.get(DIALOG_PATH_FILTER); |
904 | 902 | pattern.setSelection(0, 0); |
905 | 903 | break; |
906 | 904 | case FULL_SELECTION: |
907 | pattern.setSelection(0, initialPatternText.length()); | |
905 | pattern.selectAll(); | |
908 | 906 | break; |
909 | 907 | } |
910 | 908 | |
937 | 935 | } |
938 | 936 | |
939 | 937 | private void createDetailsArea(Composite parent) { |
940 | details = new StyledText(parent, SWT.MULTI+SWT.READ_ONLY+SWT.BORDER+SWT.H_SCROLL); | |
938 | details = new StyledText(parent, SWT.MULTI+SWT.READ_ONLY+SWT.BORDER+SWT.H_SCROLL+SWT.V_SCROLL); | |
941 | 939 | details.setFont(JFaceResources.getFont(TEXT_FONT)); |
942 | 940 | |
943 | 941 | list.addSelectionChangedListener(new ISelectionChangedListener() { |
962 | 960 | } |
963 | 961 | IStructuredSelection sel = (IStructuredSelection) list.getSelection(); |
964 | 962 | if (sel==null || sel.isEmpty()) { |
965 | details.setText(""); //$NON-NLS-1$ | |
963 | details.setText(EMPTY_STRING); | |
966 | 964 | } else { |
967 | 965 | //Not empty selection |
966 | final int context = 100; // number of lines before and after match to include in preview | |
968 | 967 | int numLines = computeLines(); |
969 | 968 | if (numLines > 0) { |
970 | 969 | LineItem item = (LineItem) sel.getFirstElement(); |
972 | 971 | if (document!=null) { |
973 | 972 | try { |
974 | 973 | int line = item.getLineNumber()-1; //in document lines are 0 based. In search 1 based. |
975 | int start = document.getLineOffset(Math.max(line-(numLines-1)/2, 0)); | |
974 | int contextStartLine = Math.max(line-(numLines-1)/2 - context, 0); | |
975 | int start = document.getLineOffset(contextStartLine); | |
976 | 976 | int end = document.getLength(); |
977 | 977 | try { |
978 | IRegion lineInfo = document.getLineInformation(line + numLines/2); | |
978 | IRegion lineInfo = document.getLineInformation(line + numLines/2 + context); | |
979 | 979 | end = lineInfo.getOffset() + lineInfo.getLength(); |
980 | 980 | } catch (BadLocationException e) { |
981 | 981 | //Presumably line number is past the end of document. |
985 | 985 | StyledString styledString = highlightMatches(document.get(start, end-start)); |
986 | 986 | details.setText(styledString.getString()); |
987 | 987 | details.setStyleRanges(styledString.getStyleRanges()); |
988 | ||
988 | details.setTopIndex(Math.max(line - contextStartLine - numLines/2, 0)); | |
989 | 989 | return; |
990 | 990 | } catch (BadLocationException e) { |
991 | 991 | } |
993 | 993 | } |
994 | 994 | } |
995 | 995 | //empty selection or some error: |
996 | details.setText(""); //$NON-NLS-1$ | |
997 | } | |
998 | } | |
999 | ||
1000 | /** | |
1001 | * Computes how much lines of text can be displayed in the details section based on | |
1002 | * its current height and font metrics. | |
996 | details.setText(EMPTY_STRING); | |
997 | } | |
998 | } | |
999 | ||
1000 | /** | |
1001 | * Computes how many lines of text can be displayed in the details section. | |
1003 | 1002 | */ |
1004 | 1003 | private int computeLines() { |
1005 | 1004 | if (details!=null && !details.isDisposed()) { |
1006 | GC gc = new GC(details); | |
1007 | try { | |
1008 | FontMetrics fm = gc.getFontMetrics(); | |
1009 | int itemH = fm.getHeight(); | |
1010 | int areaH = details.getClientArea().height; | |
1011 | return (areaH+itemH-1) / itemH; | |
1012 | } finally { | |
1013 | gc.dispose(); | |
1014 | } | |
1005 | int lineHeight = details.getLineHeight(); | |
1006 | int areaHeight = details.getClientArea().height; | |
1007 | return (areaHeight + lineHeight - 1) / lineHeight; | |
1015 | 1008 | } |
1016 | 1009 | return 0; |
1017 | 1010 | } |
+120
-0
0 | /******************************************************************************* | |
1 | * Copyright (c) 2019 Red Hat Inc. | |
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 | * https://www.eclipse.org/legal/epl-2.0/ | |
6 | * | |
7 | * SPDX-License-Identifier: EPL-2.0 | |
8 | *******************************************************************************/ | |
9 | package org.eclipse.text.quicksearch.internal.ui; | |
10 | ||
11 | import java.util.ArrayList; | |
12 | import java.util.Collections; | |
13 | import java.util.List; | |
14 | ||
15 | import org.eclipse.core.runtime.IProgressMonitor; | |
16 | import org.eclipse.jface.resource.ImageDescriptor; | |
17 | import org.eclipse.jface.text.TextSelection; | |
18 | import org.eclipse.osgi.util.NLS; | |
19 | import org.eclipse.text.quicksearch.internal.core.LineItem; | |
20 | import org.eclipse.text.quicksearch.internal.core.QuickTextQuery; | |
21 | import org.eclipse.text.quicksearch.internal.core.QuickTextSearchRequestor; | |
22 | import org.eclipse.text.quicksearch.internal.core.QuickTextSearcher; | |
23 | import org.eclipse.text.quicksearch.internal.core.priority.PriorityFunction; | |
24 | import org.eclipse.ui.IEditorPart; | |
25 | import org.eclipse.ui.PartInitException; | |
26 | import org.eclipse.ui.PlatformUI; | |
27 | import org.eclipse.ui.ide.IDE; | |
28 | import org.eclipse.ui.quickaccess.IQuickAccessComputer; | |
29 | import org.eclipse.ui.quickaccess.IQuickAccessComputerExtension; | |
30 | import org.eclipse.ui.quickaccess.QuickAccessElement; | |
31 | import org.eclipse.ui.texteditor.ITextEditor; | |
32 | ||
33 | public class QuickSearchQuickAccessComputer extends QuickTextSearchRequestor implements IQuickAccessComputer, IQuickAccessComputerExtension { | |
34 | ||
35 | private static final int MAX_ENTRIES = 20; | |
36 | private static final long TIMEOUT = 200; | |
37 | private PriorityFunction priorities; | |
38 | ||
39 | public QuickSearchQuickAccessComputer() { | |
40 | priorities = new QuickSearchContext(PlatformUI.getWorkbench().getActiveWorkbenchWindow()).createPriorityFun(); | |
41 | } | |
42 | ||
43 | @Override public QuickAccessElement[] computeElements(String query, IProgressMonitor monitor) { | |
44 | List<LineItem> matches = Collections.synchronizedList(new ArrayList<>()); | |
45 | QuickTextSearcher searcher = new QuickTextSearcher(new QuickTextQuery("", false), priorities, 100, new QuickTextSearchRequestor() { //$NON-NLS-1$ | |
46 | @Override public void add(LineItem match) { | |
47 | matches.add(match); | |
48 | } | |
49 | ||
50 | @Override public void clear() { | |
51 | matches.clear(); | |
52 | } | |
53 | ||
54 | @Override public void revoke(LineItem line) { | |
55 | matches.remove(line); | |
56 | } | |
57 | }); | |
58 | searcher.setMaxResults(MAX_ENTRIES); | |
59 | searcher.setQuery(new QuickTextQuery(query, false), true); | |
60 | long start = System.currentTimeMillis(); | |
61 | while (matches.size() < 20 && !searcher.isDone() && System.currentTimeMillis() - start < TIMEOUT) { | |
62 | try { | |
63 | Thread.sleep(100); | |
64 | } catch (InterruptedException e) { | |
65 | QuickSearchActivator.log(e); | |
66 | } | |
67 | } | |
68 | searcher.cancel(); | |
69 | return matches.stream().map(LineItemQuickAccessElement::new).toArray(QuickAccessElement[]::new); | |
70 | } | |
71 | ||
72 | @Override public QuickAccessElement[] computeElements() { | |
73 | return new QuickAccessElement[0]; | |
74 | } | |
75 | ||
76 | @Override public void resetState() { | |
77 | // stateless | |
78 | ||
79 | } | |
80 | ||
81 | @Override public boolean needsRefresh() { | |
82 | return false; | |
83 | } | |
84 | ||
85 | private class LineItemQuickAccessElement extends QuickAccessElement { | |
86 | ||
87 | private final LineItem item; | |
88 | ||
89 | public LineItemQuickAccessElement(LineItem item) { | |
90 | this.item = item; | |
91 | } | |
92 | ||
93 | @Override public String getLabel() { | |
94 | return NLS.bind(Messages.quickAccessMatch, item.getText(), item.getFile().getName()); | |
95 | } | |
96 | ||
97 | @Override public ImageDescriptor getImageDescriptor() { | |
98 | return null; | |
99 | } | |
100 | ||
101 | @Override public String getId() { | |
102 | return item.getFile().getFullPath().toString() + '[' + item.getOffset() + ':' + (item.getOffset() + item.getText().length() - 1) + ']'; | |
103 | } | |
104 | ||
105 | @Override public void execute() { | |
106 | IEditorPart part; | |
107 | try { | |
108 | part = IDE.openEditor(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage(), item.getFile()); | |
109 | if (part instanceof ITextEditor) { | |
110 | ((ITextEditor) part).getSelectionProvider().setSelection(new TextSelection(item.getOffset(), item.getText().length())); | |
111 | } | |
112 | } catch (PartInitException e) { | |
113 | QuickSearchActivator.log(e); | |
114 | } | |
115 | } | |
116 | ||
117 | } | |
118 | ||
119 | } |
+4
-3
7 | 7 | QuickSearchPreferencesPage_Ignored_Names=Ignored Names |
8 | 8 | QuickSearchDialog_Open=&Open |
9 | 9 | QuickSearchDialog_Refresh=&Refresh |
10 | QuickSearchDialog_In=in: | |
10 | QuickSearchDialog_In=&in: | |
11 | 11 | QuickSearchDialog_InTooltip=Search in (comma-separated list of '.gitignore' style inclusion patterns) |
12 | 12 | QuickSearchDialog_line=Line |
13 | 13 | QuickSearchDialog_text=Text |
19 | 19 | QuickSearchDialog_title=Quick Search |
20 | 20 | QuickSearchDialog_caseSensitive_label=Case SENSITIVE |
21 | 21 | QuickSearchDialog_caseInsensitive_label=Case INSENSITIVE |
22 | QuickSearchDialog_patternHint=Pattern (? = any character, * = any string) | |
23 | QuickTextSearch_updateMatchesJob=Update matches⏎ | |
22 | QuickSearchDialog_patternHint=&Pattern (? = any character, * = any string) | |
23 | QuickTextSearch_updateMatchesJob=Update matches | |
24 | quickAccessMatch=`{0}` in {1}⏎ |
+3
-5
0 | 0 | /******************************************************************************* |
1 | * Copyright (c) 2000, 2008, 2013-2019 IBM Corporation and others. | |
1 | * Copyright (c) 2000, 2019 IBM Corporation and others. | |
2 | 2 | * All rights reserved. This program and the accompanying materials |
3 | 3 | * are made available under the terms of the Eclipse Public License v2.0 |
4 | 4 | * which accompanies this distribution, and is available at |
25 | 25 | import org.eclipse.core.runtime.IPath; |
26 | 26 | import org.eclipse.core.runtime.NullProgressMonitor; |
27 | 27 | import org.eclipse.jface.text.IDocument; |
28 | import org.eclipse.search.internal.ui.SearchPlugin; | |
29 | 28 | import org.eclipse.text.quicksearch.internal.ui.QuickSearchActivator; |
30 | 29 | import org.eclipse.ui.IEditorInput; |
31 | 30 | import org.eclipse.ui.IEditorPart; |
48 | 47 | * |
49 | 48 | * @author Kris De Volder |
50 | 49 | */ |
51 | @SuppressWarnings("restriction") | |
52 | 50 | public class DocumentFetcher { |
53 | 51 | |
54 | 52 | private Map<IFile, IDocument> dirtyEditors; |
133 | 131 | * @return returns a map from IFile to IDocument for all open, dirty editors. |
134 | 132 | */ |
135 | 133 | private Map<IFile, IDocument> evalNonFileBufferDocuments() { |
136 | Map<IFile, IDocument> result= new HashMap<IFile, IDocument>(); | |
137 | IWorkbench workbench= SearchPlugin.getDefault().getWorkbench(); | |
134 | Map<IFile, IDocument> result= new HashMap<>(); | |
135 | IWorkbench workbench= PlatformUI.getWorkbench(); | |
138 | 136 | IWorkbenchWindow[] windows= workbench.getWorkbenchWindows(); |
139 | 137 | for (int i= 0; i < windows.length; i++) { |
140 | 138 | IWorkbenchPage[] pages= windows[i].getPages(); |
1 | 1 | Bundle-ManifestVersion: 2 |
2 | 2 | Bundle-Name: %pluginName |
3 | 3 | Bundle-SymbolicName: org.eclipse.text.quicksearch.tests |
4 | Bundle-Version: 1.0.0.qualifier | |
4 | Bundle-Version: 1.0.100.qualifier | |
5 | 5 | Require-Bundle: org.eclipse.core.runtime, |
6 | 6 | org.eclipse.text.quicksearch, |
7 | 7 | org.eclipse.core.resources, |
18 | 18 | <parent> |
19 | 19 | <artifactId>tests-pom</artifactId> |
20 | 20 | <groupId>eclipse.platform.text</groupId> |
21 | <version>4.13.0-SNAPSHOT</version> | |
21 | <version>4.14.0-SNAPSHOT</version> | |
22 | 22 | <relativePath>../tests-pom/</relativePath> |
23 | 23 | </parent> |
24 | 24 | <groupId>org.eclipse.text</groupId> |
25 | 25 | <artifactId>org.eclipse.text.quicksearch.tests</artifactId> |
26 | <version>1.0.0-SNAPSHOT</version> | |
26 | <version>1.0.100-SNAPSHOT</version> | |
27 | 27 | <packaging>eclipse-test-plugin</packaging> |
28 | 28 | <properties> |
29 | 29 | <testSuite>${project.artifactId}</testSuite> |
+64
-0
0 | /******************************************************************************* | |
1 | * Copyright (c) 2019 Julian Honnen | |
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 | * Julian Honnen <julian.honnen@vector.com> - initial API and implementation | |
12 | *******************************************************************************/ | |
13 | package org.eclipse.text.quicksearch.tests; | |
14 | ||
15 | import static org.junit.Assert.assertEquals; | |
16 | import static org.junit.Assert.assertNotEquals; | |
17 | ||
18 | import org.eclipse.core.resources.IFolder; | |
19 | import org.eclipse.core.resources.IProject; | |
20 | import org.eclipse.core.resources.IWorkspaceRoot; | |
21 | import org.eclipse.core.resources.ResourcesPlugin; | |
22 | import org.eclipse.text.quicksearch.internal.core.priority.DefaultPriorityFunction; | |
23 | import org.eclipse.text.quicksearch.internal.core.priority.PriorityFunction; | |
24 | import org.eclipse.text.quicksearch.internal.ui.QuickSearchActivator; | |
25 | import org.junit.Before; | |
26 | import org.junit.Test; | |
27 | ||
28 | public class DefaultPriorityFunctionTest { | |
29 | ||
30 | private DefaultPriorityFunction fPriorityFunction; | |
31 | ||
32 | @Before | |
33 | public void setup() { | |
34 | fPriorityFunction = new DefaultPriorityFunction(); | |
35 | fPriorityFunction.configure(QuickSearchActivator.getDefault().getPreferences()); | |
36 | } | |
37 | ||
38 | @Test | |
39 | public void testIgnoreLinkedContainers() throws Exception { | |
40 | IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); | |
41 | IProject p1 = root.getProject("p1"); | |
42 | p1.create(null); | |
43 | p1.open(null); | |
44 | IProject p2 = root.getProject("p2"); | |
45 | p2.create(null); | |
46 | p2.open(null); | |
47 | ||
48 | IFolder f1 = p1.getFolder("f1"); | |
49 | f1.create(true, true, null); | |
50 | ||
51 | IFolder linkedp1 = p2.getFolder("p1"); | |
52 | linkedp1.createLink(p1.getLocationURI(), 0, null); | |
53 | ||
54 | IFolder linkedF1 = p2.getFolder("f1"); | |
55 | linkedF1.createLink(f1.getLocationURI(), 0, null); | |
56 | ||
57 | assertEquals(PriorityFunction.PRIORITY_IGNORE, fPriorityFunction.priority(linkedp1), 1.0); | |
58 | assertNotEquals(PriorityFunction.PRIORITY_IGNORE, fPriorityFunction.priority(p1), 1.0); | |
59 | assertEquals(PriorityFunction.PRIORITY_IGNORE, fPriorityFunction.priority(linkedF1), 1.0); | |
60 | assertNotEquals(PriorityFunction.PRIORITY_IGNORE, fPriorityFunction.priority(f1), 1.0); | |
61 | } | |
62 | ||
63 | } |
0 | Manifest-Version: 1.0 | |
1 | Bundle-ManifestVersion: 2 | |
2 | Bundle-Name: %Plugin.name | |
3 | Bundle-SymbolicName: org.eclipse.text.tests | |
4 | Bundle-Version: 3.12.300.qualifier | |
5 | Bundle-Vendor: %Plugin.providerName | |
6 | Bundle-Localization: plugin | |
7 | Export-Package: | |
8 | org.eclipse.text.tests, | |
9 | org.eclipse.text.tests.link, | |
10 | org.eclipse.text.tests.templates | |
11 | Require-Bundle: | |
12 | org.eclipse.core.commands;bundle-version="[3.5.0,4.0.0)", | |
13 | org.eclipse.core.runtime;bundle-version="[3.5.0,4.0.0)", | |
14 | org.eclipse.text;bundle-version="[3.6.3,4.0.0)", | |
15 | org.junit;bundle-version="4.12.0" | |
16 | Bundle-RequiredExecutionEnvironment: JavaSE-1.8 | |
17 | Eclipse-BundleShape: dir | |
18 | Import-Package: com.ibm.icu.text, | |
19 | com.ibm.icu.util | |
20 | Automatic-Module-Name: org.eclipse.text.tests | |
0 | Manifest-Version: 1.0 | |
1 | Bundle-ManifestVersion: 2 | |
2 | Bundle-Name: %Plugin.name | |
3 | Bundle-SymbolicName: org.eclipse.text.tests | |
4 | Bundle-Version: 3.12.400.qualifier | |
5 | Bundle-Vendor: %Plugin.providerName | |
6 | Bundle-Localization: plugin | |
7 | Export-Package: | |
8 | org.eclipse.text.tests, | |
9 | org.eclipse.text.tests.link, | |
10 | org.eclipse.text.tests.templates | |
11 | Require-Bundle: | |
12 | org.eclipse.core.commands;bundle-version="[3.5.0,4.0.0)", | |
13 | org.eclipse.core.runtime;bundle-version="[3.5.0,4.0.0)", | |
14 | org.eclipse.text;bundle-version="[3.6.3,4.0.0)", | |
15 | org.junit;bundle-version="4.12.0" | |
16 | Bundle-RequiredExecutionEnvironment: JavaSE-1.8 | |
17 | Eclipse-BundleShape: dir | |
18 | Import-Package: com.ibm.icu.text, | |
19 | com.ibm.icu.util | |
20 | Automatic-Module-Name: org.eclipse.text.tests |
13 | 13 | <parent> |
14 | 14 | <artifactId>tests-pom</artifactId> |
15 | 15 | <groupId>eclipse.platform.text</groupId> |
16 | <version>4.13.0-SNAPSHOT</version> | |
16 | <version>4.14.0-SNAPSHOT</version> | |
17 | 17 | <relativePath>../tests-pom/</relativePath> |
18 | 18 | </parent> |
19 | 19 | <groupId>org.eclipse.text</groupId> |
20 | 20 | <artifactId>org.eclipse.text.tests</artifactId> |
21 | <version>3.12.300-SNAPSHOT</version> | |
21 | <version>3.12.400-SNAPSHOT</version> | |
22 | 22 | <packaging>eclipse-test-plugin</packaging> |
23 | 23 | <properties> |
24 | 24 | <testSuite>${project.artifactId}</testSuite> |
29 | 29 | public ExpectedException thrown = ExpectedException.none(); |
30 | 30 | |
31 | 31 | private static Match run(String text, String... needles) { |
32 | return MultiStringMatcher.indexOf(text, 0, needles); | |
32 | return run(text, 0, needles); | |
33 | 33 | } |
34 | 34 | |
35 | 35 | private static Match run(String text, int offset, String... needles) { |
36 | return MultiStringMatcher.indexOf(text, offset, needles); | |
36 | return run(new TestCharSequence(text), offset, needles); | |
37 | } | |
38 | ||
39 | private static Match run(TestCharSequence text, int offset, String... needles) { | |
40 | Match result = MultiStringMatcher.indexOf(text, offset, needles); | |
41 | assertEquals("Algorithm backtracked", 0, text.getBackTrack()); | |
42 | return result; | |
37 | 43 | } |
38 | 44 | |
39 | 45 | private static void test(Match m, String expected, int index) { |
448 | 454 | thrown.expect(IllegalStateException.class); |
449 | 455 | b.build(); |
450 | 456 | } |
457 | ||
458 | @Test | |
459 | public void scan001() throws Exception { | |
460 | TestCharSequence text = new TestCharSequence("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"); | |
461 | Match m = run(text, 0, "x", "xx", "xxx", "xxxx"); | |
462 | test(m, "xxxx", 0); | |
463 | assertEquals("Scanned too far", 3, text.getLastIndex()); | |
464 | } | |
465 | ||
466 | @Test | |
467 | public void scan002() throws Exception { | |
468 | TestCharSequence text = new TestCharSequence("ddcababababababcabxdd"); | |
469 | Match m = run(text, 0, "ca", "cabx", "ababc"); | |
470 | test(m, "ca", 2); | |
471 | assertEquals("Scanned too far", 5, text.getLastIndex()); | |
472 | } | |
473 | ||
474 | @Test | |
475 | public void scan003() throws Exception { | |
476 | TestCharSequence text = new TestCharSequence("ddcabarbarazz"); | |
477 | Match m = run(text, 0, "a", "cabby", "barbara"); | |
478 | test(m, "a", 3); | |
479 | assertEquals("Scanned too far", 5, text.getLastIndex()); | |
480 | } | |
481 | ||
482 | private static class TestCharSequence implements CharSequence { | |
483 | ||
484 | private final String value; | |
485 | ||
486 | private int lastIndex = -1; | |
487 | ||
488 | private int backtrack = 0; | |
489 | ||
490 | public TestCharSequence(String value) { | |
491 | this.value = value; | |
492 | } | |
493 | ||
494 | @Override | |
495 | public int length() { | |
496 | return value.length(); | |
497 | } | |
498 | ||
499 | @Override | |
500 | public char charAt(int index) { | |
501 | if (index < lastIndex) { | |
502 | backtrack = Math.min(backtrack, index - lastIndex); | |
503 | } | |
504 | lastIndex = index; | |
505 | return value.charAt(index); | |
506 | } | |
507 | ||
508 | @Override | |
509 | public CharSequence subSequence(int start, int end) { | |
510 | throw new UnsupportedOperationException(); | |
511 | } | |
512 | ||
513 | public int getLastIndex() { | |
514 | return lastIndex; | |
515 | } | |
516 | ||
517 | public int getBackTrack() { | |
518 | return backtrack; | |
519 | } | |
520 | } | |
451 | 521 | } |
0 | 0 | /******************************************************************************* |
1 | * Copyright (c) 2000, 2013 IBM Corporation and others. | |
1 | * Copyright (c) 2000, 2019 IBM Corporation and others. | |
2 | 2 | * |
3 | 3 | * This program and the accompanying materials |
4 | 4 | * are made available under the terms of the Eclipse Public License 2.0 |
14 | 14 | |
15 | 15 | import static org.junit.Assert.assertEquals; |
16 | 16 | import static org.junit.Assert.assertFalse; |
17 | import static org.junit.Assert.fail; | |
17 | 18 | |
18 | 19 | import java.util.ArrayList; |
19 | 20 | import java.util.Iterator; |
22 | 23 | import org.junit.Assert; |
23 | 24 | import org.junit.Test; |
24 | 25 | |
26 | import org.eclipse.jface.text.AbstractLineTracker.DelimiterInfo; | |
25 | 27 | import org.eclipse.jface.text.BadLocationException; |
26 | 28 | import org.eclipse.jface.text.Document; |
27 | 29 | import org.eclipse.jface.text.DocumentEvent; |
43 | 45 | |
44 | 46 | private final class DocumentListener implements IDocumentListener { |
45 | 47 | @Override |
46 | public void documentAboutToBeChanged(DocumentEvent event) {} | |
48 | public void documentAboutToBeChanged(DocumentEvent event) { /* not used */ } | |
47 | 49 | @Override |
48 | 50 | public void documentChanged(DocumentEvent event) { |
49 | 51 | fEvents.add(event); |
93 | 95 | |
94 | 96 | private final class DocumentListener implements IDocumentListener { |
95 | 97 | @Override |
96 | public void documentAboutToBeChanged(DocumentEvent event) {} | |
98 | public void documentAboutToBeChanged(DocumentEvent event) { /* not used */ } | |
97 | 99 | @Override |
98 | 100 | public void documentChanged(DocumentEvent event) { |
99 | 101 | event= new DocumentEvent(event.getDocument(), event.getOffset(), event.getLength(), event.getText()); |
137 | 139 | } |
138 | 140 | |
139 | 141 | |
140 | /** | |
141 | * Constructor for UtilitiesTest. | |
142 | * | |
143 | * @param name the name | |
144 | */ | |
145 | 142 | private static DocumentEvent createRandomEvent(IDocument document, int maxLength, char character) { |
146 | 143 | |
147 | 144 | int index0= (int) (Math.random() * (maxLength + 1)); |
280 | 277 | } |
281 | 278 | |
282 | 279 | @Test |
280 | @SuppressWarnings("deprecation") | |
283 | 281 | public void testIndexOf() { |
284 | 282 | int[] result; |
285 | result= TextUtilities.indexOf(new String[] {"a", "ab", "abc"}, "xxxxxxxxxx", 0); | |
283 | result = TextUtilities.indexOf(new String[0], "xxxxxxxxxx", 0); | |
286 | 284 | assertEquals(-1, result[0]); |
287 | 285 | assertEquals(-1, result[1]); |
288 | 286 | |
289 | result= TextUtilities.indexOf(new String[] {"a", "ab", "abc"}, "foobarabcd", 0); | |
287 | result = TextUtilities.indexOf(new String[] { "a", "ab", "abc" }, "xxxxxxxxxx", 0); | |
288 | assertEquals(-1, result[0]); | |
289 | assertEquals(-1, result[1]); | |
290 | ||
291 | result = TextUtilities.indexOf(new String[] { "a", "ab", "abc" }, "foobarabcd", 0); | |
290 | 292 | assertEquals(4, result[0]); |
291 | 293 | assertEquals(0, result[1]); |
292 | } | |
293 | ||
294 | ||
295 | result = TextUtilities.indexOf(new String[] { "ab", "ab" }, "foobarabcd", 0); | |
296 | assertEquals(6, result[0]); | |
297 | assertEquals(0, result[1]); | |
298 | ||
299 | result = TextUtilities.indexOf(new String[] { "", "ab", "abc" }, "foobarabcd", 0); | |
300 | assertEquals(6, result[0]); | |
301 | assertEquals(2, result[1]); | |
302 | ||
303 | result = TextUtilities.indexOf(new String[] { "arac", "", "fuu" }, "foobarabcd", 0); | |
304 | assertEquals(0, result[0]); | |
305 | assertEquals(1, result[1]); | |
306 | ||
307 | result = TextUtilities.indexOf(new String[] { "", "" }, "foobarabcd", 0); | |
308 | assertEquals(0, result[0]); | |
309 | assertEquals(1, result[1]); | |
310 | ||
311 | result = TextUtilities.indexOf(new String[] { "" }, "foobarabcd", 5); | |
312 | // looks strange that searching from offset 5 returns match offset 0 but that is | |
313 | // how it was implemented | |
314 | assertEquals(0, result[0]); | |
315 | assertEquals(0, result[1]); | |
316 | ||
317 | result = TextUtilities.indexOf(new String[] { "abc" }, "foobarabcd", -5); | |
318 | assertEquals(6, result[0]); | |
319 | assertEquals(0, result[1]); | |
320 | ||
321 | result = TextUtilities.indexOf(new String[] { "abc" }, "foobarabcd", 20); | |
322 | assertEquals(-1, result[0]); | |
323 | assertEquals(-1, result[1]); | |
324 | ||
325 | try { | |
326 | TextUtilities.indexOf(null, "foobarabcd", 0); | |
327 | fail("Exception not thrown"); | |
328 | } catch (NullPointerException ex) { | |
329 | // expected | |
330 | } | |
331 | ||
332 | try { | |
333 | TextUtilities.indexOf(new String[] { "abc", null }, "foobarabcd", 0); | |
334 | fail("Exception not thrown"); | |
335 | } catch (NullPointerException ex) { | |
336 | // expected | |
337 | } | |
338 | ||
339 | try { | |
340 | TextUtilities.indexOf(new String[] { "abc" }, null, 0); | |
341 | fail("Exception not thrown"); | |
342 | } catch (NullPointerException ex) { | |
343 | // expected | |
344 | } | |
345 | } | |
346 | ||
347 | @Test | |
348 | public void testNextDelimiter() { | |
349 | DelimiterInfo result; | |
350 | result = TextUtilities.nextDelimiter("abc\ndef", 0); | |
351 | assertEquals(3, result.delimiterIndex); | |
352 | assertEquals("\n", result.delimiter); | |
353 | ||
354 | result = TextUtilities.nextDelimiter("abc\ndef", 5); | |
355 | assertEquals(-1, result.delimiterIndex); | |
356 | assertEquals(null, result.delimiter); | |
357 | ||
358 | result = TextUtilities.nextDelimiter("abc\rdef\n123", 0); | |
359 | assertEquals(3, result.delimiterIndex); | |
360 | assertEquals("\r", result.delimiter); | |
361 | ||
362 | result = TextUtilities.nextDelimiter("abc+\r\ndef\n123", 0); | |
363 | assertEquals(4, result.delimiterIndex); | |
364 | assertEquals("\r\n", result.delimiter); | |
365 | ||
366 | result = TextUtilities.nextDelimiter("abc~>\r\r\ndef\n123", 0); | |
367 | assertEquals(5, result.delimiterIndex); | |
368 | assertEquals("\r", result.delimiter); | |
369 | ||
370 | result = TextUtilities.nextDelimiter("\nabc~>\r\r\ndef\n123", 0); | |
371 | assertEquals(0, result.delimiterIndex); | |
372 | assertEquals("\n", result.delimiter); | |
373 | ||
374 | result = TextUtilities.nextDelimiter("abc~>123\r\n", 0); | |
375 | assertEquals(8, result.delimiterIndex); | |
376 | assertEquals("\r\n", result.delimiter); | |
377 | ||
378 | result = TextUtilities.nextDelimiter("abc~>\r\r\ndef\n123", 9); | |
379 | assertEquals(11, result.delimiterIndex); | |
380 | assertEquals("\n", result.delimiter); | |
381 | ||
382 | result = TextUtilities.nextDelimiter("", 0); | |
383 | assertEquals(-1, result.delimiterIndex); | |
384 | assertEquals(null, result.delimiter); | |
385 | ||
386 | result = TextUtilities.nextDelimiter("abc123", 0); | |
387 | assertEquals(-1, result.delimiterIndex); | |
388 | assertEquals(null, result.delimiter); | |
389 | } | |
294 | 390 | } |
1 | 1 | Bundle-ManifestVersion: 2 |
2 | 2 | Bundle-Name: %pluginName |
3 | 3 | Bundle-SymbolicName: org.eclipse.ui.editors; singleton:=true |
4 | Bundle-Version: 3.12.0.qualifier | |
4 | Bundle-Version: 3.13.0.qualifier | |
5 | 5 | Bundle-Activator: org.eclipse.ui.internal.editors.text.EditorsPlugin |
6 | 6 | Bundle-ActivationPolicy: lazy |
7 | 7 | Bundle-Vendor: %providerName |
11 | 11 | org.eclipse.ui.editors.text.templates, |
12 | 12 | org.eclipse.ui.internal.editors.quickdiff;x-internal:=true, |
13 | 13 | org.eclipse.ui.internal.editors.text;x-internal:=true, |
14 | org.eclipse.ui.internal.editors.text.codemining.annotation;x-internal:=true, | |
14 | 15 | org.eclipse.ui.internal.texteditor;x-internal:=true, |
15 | 16 | org.eclipse.ui.texteditor |
16 | 17 | Require-Bundle: |
20 | 21 | org.eclipse.ui.ide;bundle-version="[3.5.0,4.0.0)", |
21 | 22 | org.eclipse.ui;bundle-version="[3.5.0,4.0.0)", |
22 | 23 | org.eclipse.jface.text;bundle-version="[3.8.0,4.0.0)", |
23 | org.eclipse.ui.workbench.texteditor;bundle-version="[3.13.0,4.0.0)", | |
24 | org.eclipse.ui.workbench;bundle-version="[3.117.0,4.0.0)", | |
25 | org.eclipse.ui.workbench.texteditor;bundle-version="[3.14.0,4.0.0)", | |
24 | 26 | org.eclipse.core.filebuffers;visibility:=reexport;bundle-version="[3.5.0,4.0.0)", |
25 | 27 | org.eclipse.core.resources;bundle-version="[3.5.0,4.0.0)", |
26 | org.eclipse.core.filesystem;bundle-version="[1.2.0,2.0.0)" | |
28 | org.eclipse.core.filesystem;bundle-version="[1.2.0,2.0.0)", | |
29 | org.eclipse.jdt.annotation;bundle-version="2.2";resolution:=optional | |
27 | 30 | Bundle-RequiredExecutionEnvironment: JavaSE-1.8 |
28 | 31 | Import-Package: com.ibm.icu.text |
29 | 32 | Automatic-Module-Name: org.eclipse.ui.editors |
119 | 119 | preferenceKeywords.tabWidth= tab width |
120 | 120 | preferenceKeywords.lineNumber= line numbers |
121 | 121 | preferenceKeywords.printMargin= print margin |
122 | preferenceKeywords.annotationCodeMining= annotation code mining marker error warning info | |
122 | 123 | preferenceKeywords.annotations= annotations vertical ruler overview colors text editor |
123 | 124 | preferenceKeywords.quickdiff= quick diff compare reference colors text editor changes |
124 | 125 | preferenceKeywords.accessibility= accessibility caret cursor quick diff text editor ruler |
226 | 226 | <keywordReference id="org.eclipse.ui.editors.tabWidth"/> |
227 | 227 | <keywordReference id="org.eclipse.ui.editors.lineNumber"/> |
228 | 228 | <keywordReference id="org.eclipse.ui.editors.printMargin"/> |
229 | <keywordReference id="org.eclipse.ui.editors.annotationCodeMining"/> | |
229 | 230 | </page> |
230 | 231 | <page |
231 | 232 | name="%PreferencePages.Annotations" |
285 | 286 | <keyword |
286 | 287 | label="%preferenceKeywords.printMargin" |
287 | 288 | id="org.eclipse.ui.editors.printMargin"/> |
289 | <keyword | |
290 | label="%preferenceKeywords.annotationCodeMining" | |
291 | id="org.eclipse.ui.editors.annotationCodeMining"/> | |
288 | 292 | <keyword |
289 | 293 | label="%preferenceKeywords.annotations" |
290 | 294 | id="org.eclipse.ui.editors.annotations"/> |
1062 | 1066 | |
1063 | 1067 | </extension> |
1064 | 1068 | |
1069 | <extension | |
1070 | point="org.eclipse.ui.workbench.texteditor.codeMiningProviders"> | |
1071 | <codeMiningProvider | |
1072 | class="org.eclipse.ui.internal.editors.text.codemining.annotation.AnnotationCodeMiningProvider" | |
1073 | id="org.eclipse.ui.internal.editors.annotationCodeMiningProvider"> | |
1074 | <enabledWhen> | |
1075 | <with | |
1076 | variable="editorInput"> | |
1077 | <adapt | |
1078 | type="org.eclipse.core.resources.IFile"> | |
1079 | <test | |
1080 | property="org.eclipse.core.resources.contentTypeId" | |
1081 | value="org.eclipse.core.runtime.text" | |
1082 | args="kindOf"> | |
1083 | </test> | |
1084 | </adapt> | |
1085 | </with> | |
1086 | </enabledWhen> | |
1087 | </codeMiningProvider> | |
1088 | </extension> | |
1065 | 1089 | </plugin> |
0 | <?xml version="1.0" encoding="UTF-8"?> | |
1 | <!-- | |
2 | Copyright (c) 2012, 2015 Eclipse Foundation and others. | |
3 | All rights reserved. This program and the accompanying materials | |
4 | are made available under the terms of the Eclipse Distribution License v1.0 | |
5 | which accompanies this distribution, and is available at | |
6 | http://www.eclipse.org/org/documents/edl-v10.php | |
7 | ||
8 | Contributors: | |
9 | Igor Fedorenko - initial implementation | |
10 | --> | |
11 | <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | |
12 | <modelVersion>4.0.0</modelVersion> | |
13 | <parent> | |
14 | <artifactId>eclipse.platform.text</artifactId> | |
15 | <groupId>eclipse.platform.text</groupId> | |
16 | <version>4.13.0-SNAPSHOT</version> | |
17 | </parent> | |
18 | <groupId>org.eclipse.ui</groupId> | |
19 | <artifactId>org.eclipse.ui.editors</artifactId> | |
20 | <version>3.12.0-SNAPSHOT</version> | |
21 | <packaging>eclipse-plugin</packaging> | |
22 | </project> |
98 | 98 | } |
99 | 99 | } |
100 | 100 | }; |
101 | ||
101 | ||
102 | 102 | prefs.addPreferenceChangeListener(fPreferenceChangeListener); |
103 | 103 | } |
104 | 104 |
92 | 92 | * To access the general preference from another plug-in use a |
93 | 93 | * {@link org.eclipse.ui.texteditor.ChainedPreferenceStore}: |
94 | 94 | * </p> |
95 | * | |
95 | * | |
96 | 96 | * <pre> |
97 | 97 | * List stores= new ArrayList(3); |
98 | 98 | * stores.add(YourPlugin.getDefault().getPreferenceStore()); |
117 | 117 | * To access the general preference from another plug-in use a |
118 | 118 | * {@link org.eclipse.ui.texteditor.ChainedPreferenceStore}: |
119 | 119 | * </p> |
120 | * | |
120 | * | |
121 | 121 | * <pre> |
122 | 122 | * List stores= new ArrayList(3); |
123 | 123 | * stores.add(YourPlugin.getDefault().getPreferenceStore()); |
145 | 145 | |
146 | 146 | /** |
147 | 147 | * Returns the preferences of this plug-in. |
148 | * | |
148 | * | |
149 | 149 | * @return the plug-in preferences |
150 | 150 | * @see org.eclipse.core.runtime.Plugin#getPluginPreferences() |
151 | 151 | * @deprecated As of 3.5, replaced by {@link #getPreferenceStore()} |
47 | 47 | |
48 | 48 | /** |
49 | 49 | * Action group for encoding actions. |
50 | * | |
50 | * | |
51 | 51 | * @since 2.0 |
52 | 52 | * @deprecated As of 3.1, encoding needs to be changed via properties dialog. This class is planned |
53 | 53 | * for removal after March 2021 (see bug#544309 for details). |
+1
-1
151 | 151 | /** |
152 | 152 | * Collect the files to process. This method may show a dialog to ask the user. |
153 | 153 | * Subclasses may extend or reimplement. |
154 | * | |
154 | * | |
155 | 155 | * @param resources selected resources |
156 | 156 | * @return the files to process, can be <code>null</code> |
157 | 157 | */ |
+1
-1
59 | 59 | * @since 3.1 |
60 | 60 | */ |
61 | 61 | public class FileBufferOperationHandler extends AbstractHandler { |
62 | ||
62 | ||
63 | 63 | private IFileBufferOperation fFileBufferOperation; |
64 | 64 | private IWorkbenchWindow fWindow; |
65 | 65 | private IResource[] fResources; |
+1
-1
74 | 74 | * @since 3.6 |
75 | 75 | */ |
76 | 76 | String ACCESSIBILITY_PREFERENCE_PAGE= PREFIX + "accessibility_preference_page_context"; //$NON-NLS-1$ |
77 | ||
77 | ||
78 | 78 | } |
54 | 54 | |
55 | 55 | /** |
56 | 56 | * Creates a new text editor. |
57 | * | |
57 | * | |
58 | 58 | * @see #initializeEditor() |
59 | 59 | * @see #initializeKeyBindingScopes() |
60 | 60 | */ |
+2
-2
61 | 61 | /** |
62 | 62 | * Creates a new context type registry and registers all context types contributed for the given |
63 | 63 | * registry ID. |
64 | * | |
64 | * | |
65 | 65 | * @param registryId the registry ID |
66 | 66 | * @since 3.5 |
67 | 67 | */ |
80 | 80 | |
81 | 81 | /** |
82 | 82 | * Registers all context types contributed for the given registry ID. |
83 | * | |
83 | * | |
84 | 84 | * @param registryId the registry ID |
85 | 85 | * @since 3.5 |
86 | 86 | */ |
+2
-2
0 | 0 | /******************************************************************************* |
1 | * Copyright (c) 2000, 2018 IBM Corporation and others. | |
1 | * Copyright (c) 2000, 2019 IBM Corporation and others. | |
2 | 2 | * |
3 | 3 | * This program and the accompanying materials |
4 | 4 | * are made available under the terms of the Eclipse Public License 2.0 |
416 | 416 | * - byte order mark is not valid for UTF-8 |
417 | 417 | */ |
418 | 418 | private static boolean isUTF8BOM(String encoding, IStorage storage) throws CoreException { |
419 | if (storage instanceof IFile && StandardCharsets.UTF_8.name().equals(encoding)) { //$NON-NLS-1$ | |
419 | if (storage instanceof IFile && StandardCharsets.UTF_8.name().equals(encoding)) { | |
420 | 420 | IFile file= (IFile) storage; |
421 | 421 | IContentDescription description= file.getContentDescription(); |
422 | 422 | if (description != null) { |
+3
-3
100 | 100 | @Override |
101 | 101 | protected Composite createSelectionButtonGroup(Composite parent) { |
102 | 102 | Composite buttonGroup= super.createSelectionButtonGroup(parent); |
103 | ||
103 | ||
104 | 104 | final Button button = new Button(buttonGroup, SWT.CHECK); |
105 | 105 | ((GridLayout) buttonGroup.getLayout()).numColumns++; |
106 | 106 | button.setText(TextEditorMessages.ConvertLineDelimitersAction_show_only_text_files); |
113 | 113 | refresh(); |
114 | 114 | } |
115 | 115 | }); |
116 | ||
116 | ||
117 | 117 | return buttonGroup; |
118 | 118 | } |
119 | 119 | }; |
125 | 125 | } |
126 | 126 | return null; |
127 | 127 | } |
128 | ||
128 | ||
129 | 129 | private String getDialogTitle() { |
130 | 130 | return NLSUtility.format(TextEditorMessages.ConvertLineDelimitersAction_dialog_title, fLabel); |
131 | 131 | } |
+2
-0
21 | 21 | import org.eclipse.jface.resource.ColorRegistry; |
22 | 22 | |
23 | 23 | import org.eclipse.ui.PlatformUI; |
24 | import org.eclipse.ui.internal.editors.text.codemining.annotation.AnnotationCodeMiningPreferenceConstants; | |
24 | 25 | import org.eclipse.ui.internal.texteditor.ITextEditorThemeConstants; |
25 | 26 | |
26 | 27 | import org.eclipse.ui.texteditor.AbstractDecoratedTextEditorPreferenceConstants; |
41 | 42 | IPreferenceStore store= EditorsPlugin.getDefault().getPreferenceStore(); |
42 | 43 | TextEditorPreferenceConstants.initializeDefaultValues(store); |
43 | 44 | migrateOverviewRulerPreference(store); |
45 | AnnotationCodeMiningPreferenceConstants.initializeDefaultValues(store); | |
44 | 46 | } |
45 | 47 | |
46 | 48 | public static void setThemeBasedPreferences(IPreferenceStore store, boolean fireEvent) { |
+2
-2
213 | 213 | messageLabel.setFont(font); |
214 | 214 | return messageComposite; |
215 | 215 | } |
216 | ||
216 | ||
217 | 217 | /** |
218 | 218 | * Creates page for hover preferences. |
219 | 219 | * |
349 | 349 | } |
350 | 350 | |
351 | 351 | }); |
352 | ||
352 | ||
353 | 353 | fQuickDiffProviderNote= createNoteComposite(parent.getFont(), editorComposite, TextEditorMessages.QuickDiffConfigurationBlock_referenceProviderNoteTitle, |
354 | 354 | TextEditorMessages.QuickDiffConfigurationBlock_referenceProviderNoteMessage); |
355 | 355 | gd= new GridData(SWT.BEGINNING, SWT.FILL, false, true); |
+4
-4
254 | 254 | gc.dispose(); |
255 | 255 | return width; |
256 | 256 | } |
257 | ||
257 | ||
258 | 258 | /** |
259 | 259 | * Returns a boolean indicating whether the passed tree element should be at |
260 | 260 | * LEAST gray-checked. Note that this method does not consider whether it |
676 | 676 | listViewer.setAllChecked(selection); |
677 | 677 | }); |
678 | 678 | } |
679 | ||
679 | ||
680 | 680 | public void refresh() { |
681 | 681 | //Potentially long operation - show a busy cursor |
682 | 682 | BusyIndicator.showWhile(treeViewer.getControl().getDisplay(), () -> { |
850 | 850 | |
851 | 851 | // Update the store before the hierarchy to prevent updating parents |
852 | 852 | // before all of the children are done |
853 | ||
853 | ||
854 | 854 | for (Entry<IContainer, List<Object>> entry : items.entrySet()) { |
855 | 855 | Object key = entry.getKey(); |
856 | 856 | primeHierarchyForSelection(key, selectedNodes); |
857 | 857 | checkedStateStore.put(key, entry.getValue()); |
858 | 858 | } |
859 | ||
859 | ||
860 | 860 | |
861 | 861 | // Update the checked tree items. Since each tree item has a selected |
862 | 862 | // item, all the tree items will be gray checked. |
+2
-2
90 | 90 | fResourceGroup.refresh(); |
91 | 91 | setSelection(fInput, fAcceptableLocationsFilter); |
92 | 92 | } |
93 | ||
93 | ||
94 | 94 | public IResource[] getSelectedResources() { |
95 | 95 | List<Object> items= fResourceGroup.getAllCheckedListItems(); |
96 | 96 | return items.toArray(new IResource[items.size()]); |
220 | 220 | selectTypesButton.addSelectionListener(listener); |
221 | 221 | selectTypesButton.setFont(font); |
222 | 222 | setButtonLayoutData(selectTypesButton); |
223 | ||
223 | ||
224 | 224 | return buttonComposite; |
225 | 225 | } |
226 | 226 |
+49
-7
0 | 0 | /******************************************************************************* |
1 | * Copyright (c) 2000, 2018 IBM Corporation and others. | |
1 | * Copyright (c) 2000, 2019 IBM Corporation and others. | |
2 | 2 | * |
3 | 3 | * This program and the accompanying materials |
4 | 4 | * are made available under the terms of the Eclipse Public License 2.0 |
73 | 73 | import org.eclipse.ui.dialogs.PreferencesUtil; |
74 | 74 | import org.eclipse.ui.internal.editors.text.OverlayPreferenceStore.OverlayKey; |
75 | 75 | import org.eclipse.ui.internal.editors.text.TextEditorDefaultsPreferencePage.EnumeratedDomain.EnumValue; |
76 | import org.eclipse.ui.internal.editors.text.codemining.annotation.AnnotationCodeMiningPreferenceConstants; | |
76 | 77 | |
77 | 78 | import org.eclipse.ui.texteditor.AbstractDecoratedTextEditorPreferenceConstants; |
78 | 79 | import org.eclipse.ui.texteditor.AbstractTextEditor; |
576 | 577 | |
577 | 578 | /** |
578 | 579 | * Sets or clears the error message. If not <code>null</code>, the OK button is disabled. |
579 | * | |
580 | * | |
580 | 581 | * @param errorMessage the error message, or <code>null</code> to clear |
581 | 582 | * @since 3.0 |
582 | 583 | */ |
731 | 732 | overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.INT, AbstractDecoratedTextEditorPreferenceConstants.EDITOR_TAB_WIDTH)); |
732 | 733 | overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.BOOLEAN, AbstractTextEditor.PREFERENCE_WORD_WRAP_ENABLED)); |
733 | 734 | overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.BOOLEAN, AbstractDecoratedTextEditorPreferenceConstants.EDITOR_SPACES_FOR_TABS)); |
735 | overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.BOOLEAN, AbstractDecoratedTextEditorPreferenceConstants.EDITOR_DELETE_SPACES_AS_TABS)); | |
734 | 736 | |
735 | 737 | overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.STRING, AbstractDecoratedTextEditorPreferenceConstants.EDITOR_PRINT_MARGIN_COLOR)); |
736 | 738 | overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.INT, AbstractDecoratedTextEditorPreferenceConstants.EDITOR_PRINT_MARGIN_COLUMN)); |
768 | 770 | overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.BOOLEAN, AbstractDecoratedTextEditorPreferenceConstants.EDITOR_TEXT_DRAG_AND_DROP_ENABLED)); |
769 | 771 | overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.BOOLEAN, AbstractDecoratedTextEditorPreferenceConstants.EDITOR_SHOW_TEXT_HOVER_AFFORDANCE)); |
770 | 772 | overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.INT, AbstractDecoratedTextEditorPreferenceConstants.EDITOR_HOVER_ENRICH_MODE)); |
773 | ||
774 | overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.INT, AnnotationCodeMiningPreferenceConstants.SHOW_ANNOTATION_CODE_MINING_LEVEL)); | |
775 | overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.INT, AnnotationCodeMiningPreferenceConstants.SHOW_ANNOTATION_CODE_MINING_MAX)); | |
771 | 776 | |
772 | 777 | overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.BOOLEAN, AbstractDecoratedTextEditorPreferenceConstants.EDITOR_SHOW_LEADING_SPACES)); |
773 | 778 | overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.BOOLEAN, AbstractDecoratedTextEditorPreferenceConstants.EDITOR_SHOW_ENCLOSED_SPACES)); |
853 | 858 | |
854 | 859 | label= TextEditorMessages.TextEditorPreferencePage_convertTabsToSpaces; |
855 | 860 | Preference spacesForTabs= new Preference(AbstractDecoratedTextEditorPreferenceConstants.EDITOR_SPACES_FOR_TABS, label, null); |
856 | addCheckBox(appearanceComposite, spacesForTabs, new BooleanDomain(), 0); | |
857 | ||
861 | final Button spacesForTabsButton= addCheckBox(appearanceComposite, spacesForTabs, new BooleanDomain(), 0); | |
862 | ||
863 | label= TextEditorMessages.TextEditorDefaultsPreferencePage_deleteSpacesAsTabs; | |
864 | Preference deleteSpacesAsTabs= new Preference(AbstractDecoratedTextEditorPreferenceConstants.EDITOR_DELETE_SPACES_AS_TABS, label, null); | |
865 | final Button deleteSpacesAsTabsButton= addCheckBox(appearanceComposite, deleteSpacesAsTabs, new BooleanDomain(), 0); | |
866 | createDependency(spacesForTabsButton, spacesForTabs, new Control[] { deleteSpacesAsTabsButton }); | |
858 | 867 | |
859 | 868 | label= TextEditorMessages.TextEditorPreferencePage_highlightCurrentLine; |
860 | 869 | Preference highlightCurrentLine= new Preference(AbstractDecoratedTextEditorPreferenceConstants.EDITOR_CURRENT_LINE, label, null); |
870 | 879 | final IntegerDomain printMarginDomain= new IntegerDomain(20, 200); |
871 | 880 | final Control[] printMarginControls= addTextField(appearanceComposite, printMarginColumn, printMarginDomain, 15, 20); |
872 | 881 | createDependency(showPrintMarginButton, showPrintMargin, printMarginControls); |
873 | ||
882 | ||
874 | 883 | label= TextEditorMessages.TextEditorPreferencePage_printMarginAllowOverride; |
875 | 884 | Preference printMarginAllowOverride= new Preference(AbstractDecoratedTextEditorPreferenceConstants.EDITOR_PRINT_MARGIN_ALLOW_OVERRIDE, label, null); |
876 | 885 | final Button showPrintMarginAllowOverride= addCheckBox(appearanceComposite, printMarginAllowOverride, new BooleanDomain(), 0); |
934 | 943 | label= TextEditorMessages.TextEditorDefaultsPreferencePage_smartHomeEnd; |
935 | 944 | Preference smartHomeEnd= new Preference(AbstractDecoratedTextEditorPreferenceConstants.EDITOR_SMART_HOME_END, label, null); |
936 | 945 | addCheckBox(appearanceComposite, smartHomeEnd, new BooleanDomain(), 0); |
946 | ||
947 | label= TextEditorMessages.TextEditorDefaultsPreferencePage_codeMinings_show; | |
948 | String description= TextEditorMessages.TextEditorDefaultsPreferencePage_codeMinings_description; | |
949 | Preference showCodeMinings= new Preference(AnnotationCodeMiningPreferenceConstants.SHOW_ANNOTATION_CODE_MINING_LEVEL, label, description); | |
950 | EnumeratedDomain codeMiningsDomain= new EnumeratedDomain(); | |
951 | codeMiningsDomain.addValue(new EnumValue(AnnotationCodeMiningPreferenceConstants.SHOW_ANNOTATION_CODE_MINING_LEVEL__NONE, TextEditorMessages.TextEditorDefaultsPreferencePage_codeMinings_none)); | |
952 | codeMiningsDomain.addValue(new EnumValue(AnnotationCodeMiningPreferenceConstants.SHOW_ANNOTATION_CODE_MINING_LEVEL__ERROR, TextEditorMessages.TextEditorDefaultsPreferencePage_codeMinings_error)); | |
953 | codeMiningsDomain.addValue(new EnumValue(AnnotationCodeMiningPreferenceConstants.SHOW_ANNOTATION_CODE_MINING_LEVEL__ERROR_WARNING, | |
954 | TextEditorMessages.TextEditorDefaultsPreferencePage_codeMinings_ErrorWarnings)); | |
955 | codeMiningsDomain.addValue(new EnumValue(AnnotationCodeMiningPreferenceConstants.SHOW_ANNOTATION_CODE_MINING_LEVEL__ERROR_WARNING_INFO, | |
956 | TextEditorMessages.TextEditorDefaultsPreferencePage_codeMinings_ErrorWarningsInfo)); | |
957 | final Control[] showCodeMiningsControls= addCombo(appearanceComposite, showCodeMinings, codeMiningsDomain, 0); | |
958 | ||
959 | label= TextEditorMessages.TextEditorDefaultsPreferencePage_codeMinings_max; | |
960 | description= TextEditorMessages.TextEditorDefaultsPreferencePage_codeMinings_max_description; | |
961 | Preference maxCodeMinings= new Preference(AnnotationCodeMiningPreferenceConstants.SHOW_ANNOTATION_CODE_MINING_MAX, label, description); | |
962 | IntegerDomain maxCodeMiningsDomain= new IntegerDomain(0, 99999); | |
963 | Control[] maxCodeMiningsControls= addTextField(appearanceComposite, maxCodeMinings, maxCodeMiningsDomain, 15, 20); | |
964 | ||
965 | final SelectionListener codeMiningsListener= new SelectionAdapter() { | |
966 | @Override | |
967 | public void widgetSelected(SelectionEvent e) { | |
968 | final int showCodeMiningsSetting= fOverlayStore.getInt(showCodeMinings.getKey()); | |
969 | boolean enabled= showCodeMiningsSetting != AnnotationCodeMiningPreferenceConstants.SHOW_ANNOTATION_CODE_MINING_LEVEL__NONE; | |
970 | for (Control control : maxCodeMiningsControls) { | |
971 | control.setEnabled(enabled); | |
972 | } | |
973 | } | |
974 | }; | |
975 | ||
976 | ((Combo) showCodeMiningsControls[1]).addSelectionListener(codeMiningsListener); | |
977 | fMasterSlaveListeners.add(codeMiningsListener); | |
978 | ||
937 | 979 | |
938 | 980 | addFiller(appearanceComposite, 2); |
939 | 981 | |
1048 | 1090 | int dimensions= 10; |
1049 | 1091 | Image image= new Image(tableComposite.getParent().getDisplay(), dimensions, dimensions); |
1050 | 1092 | GC gc= new GC(image); |
1051 | // Draw color preview | |
1093 | // Draw color preview | |
1052 | 1094 | gc.setBackground(color); |
1053 | 1095 | gc.fillRectangle(0, 0, dimensions, dimensions); |
1054 | 1096 | // Draw outline around color preview |
1417 | 1459 | |
1418 | 1460 | /** |
1419 | 1461 | * Returns the currently selected item in the Appearance Color Options Table. |
1420 | * | |
1462 | * | |
1421 | 1463 | * @return {@link ColorEntry} the ColorEntry representing the currently selected item in the |
1422 | 1464 | * table |
1423 | 1465 | */ |
+10
-1
0 | 0 | /******************************************************************************* |
1 | * Copyright (c) 2000, 2018 IBM Corporation and others. | |
1 | * Copyright (c) 2000, 2019 IBM Corporation and others. | |
2 | 2 | * |
3 | 3 | * This program and the accompanying materials |
4 | 4 | * are made available under the terms of the Eclipse Public License 2.0 |
136 | 136 | |
137 | 137 | public static String TextEditorDefaultsPreferencePage_carriageReturn; |
138 | 138 | public static String TextEditorDefaultsPreferencePage_transparencyLevel; |
139 | public static String TextEditorDefaultsPreferencePage_codeMinings_description; | |
140 | public static String TextEditorDefaultsPreferencePage_codeMinings_error; | |
141 | public static String TextEditorDefaultsPreferencePage_codeMinings_ErrorWarnings; | |
142 | public static String TextEditorDefaultsPreferencePage_codeMinings_ErrorWarningsInfo; | |
143 | public static String TextEditorDefaultsPreferencePage_codeMinings_max; | |
144 | public static String TextEditorDefaultsPreferencePage_codeMinings_max_description; | |
145 | public static String TextEditorDefaultsPreferencePage_codeMinings_none; | |
146 | public static String TextEditorDefaultsPreferencePage_codeMinings_show; | |
139 | 147 | public static String TextEditorDefaultsPreferencePage_configureWhitespaceCharacterPainterProperties; |
148 | public static String TextEditorDefaultsPreferencePage_deleteSpacesAsTabs; | |
140 | 149 | public static String TextEditorDefaultsPreferencePage_enclosed; |
141 | 150 | public static String TextEditorDefaultsPreferencePage_enrichHoverMode; |
142 | 151 | public static String TextEditorDefaultsPreferencePage_enrichHover_immediately; |
+10
-1
0 | 0 | ############################################################################### |
1 | # Copyright (c) 2000, 2018 IBM Corporation and others. | |
1 | # Copyright (c) 2000, 2019 IBM Corporation and others. | |
2 | 2 | # |
3 | 3 | # This program and the accompanying materials |
4 | 4 | # are made available under the terms of the Eclipse Public License 2.0 |
38 | 38 | TextEditorPreferencePage_accessibility_useSaturatedColorsInOverviewRuler=U&se saturated colors in overview ruler |
39 | 39 | TextEditorDefaultsPreferencePage_carriageReturn=Carriage Return ( \u00a4 ) |
40 | 40 | TextEditorDefaultsPreferencePage_transparencyLevel=&Transparency level (0 is transparent and 255 is opaque): |
41 | TextEditorDefaultsPreferencePage_codeMinings_description=How annotations should be shown in-line in text editors which support code minings | |
42 | TextEditorDefaultsPreferencePage_codeMinings_error=Errors only | |
43 | TextEditorDefaultsPreferencePage_codeMinings_ErrorWarnings=Errors and Warnings | |
44 | TextEditorDefaultsPreferencePage_codeMinings_ErrorWarningsInfo=Errors, Warnings and Infos | |
45 | TextEditorDefaultsPreferencePage_codeMinings_max=Maximum annotations shown: | |
46 | TextEditorDefaultsPreferencePage_codeMinings_max_description=Limits the number of shown annotations to prevent performance issues | |
47 | TextEditorDefaultsPreferencePage_codeMinings_none=None | |
48 | TextEditorDefaultsPreferencePage_codeMinings_show=Show code minings &for problem annotations: | |
41 | 49 | TextEditorDefaultsPreferencePage_configureWhitespaceCharacterPainterProperties=Configure visibility of whitespace characters in different regions of a line of text: |
50 | TextEditorDefaultsPreferencePage_deleteSpacesAsTabs=Remove &multiple spaces on backspace/delete | |
42 | 51 | TextEditorDefaultsPreferencePage_enclosed=Enclosed |
43 | 52 | TextEditorDefaultsPreferencePage_enrichHoverMode=When mouse mo&ved into hover: |
44 | 53 | TextEditorDefaultsPreferencePage_enrichHover_afterDelay=Enrich after delay |
+69
-0
0 | /******************************************************************************* | |
1 | # * Copyright (c) 2018 Altran Netherlands B.V. 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 | * Niko Stotz (Altran Netherlands B.V.) - initial implementation | |
12 | *******************************************************************************/ | |
13 | package org.eclipse.ui.internal.editors.text.codemining.annotation; | |
14 | ||
15 | import java.util.function.Consumer; | |
16 | ||
17 | import org.eclipse.jdt.annotation.NonNullByDefault; | |
18 | import org.eclipse.jdt.annotation.Nullable; | |
19 | ||
20 | import org.eclipse.swt.custom.StyledText; | |
21 | import org.eclipse.swt.events.MouseEvent; | |
22 | import org.eclipse.swt.graphics.Color; | |
23 | import org.eclipse.swt.graphics.GC; | |
24 | import org.eclipse.swt.graphics.Point; | |
25 | import org.eclipse.swt.graphics.Rectangle; | |
26 | ||
27 | import org.eclipse.jface.text.BadLocationException; | |
28 | import org.eclipse.jface.text.IDocument; | |
29 | import org.eclipse.jface.text.codemining.ICodeMiningProvider; | |
30 | import org.eclipse.jface.text.codemining.LineHeaderCodeMining; | |
31 | import org.eclipse.jface.text.source.Annotation; | |
32 | import org.eclipse.jface.text.source.IAnnotationAccessExtension; | |
33 | ||
34 | /** | |
35 | * Draws an Annotation's text and icon as Line header code mining. | |
36 | * | |
37 | * @since 3.13 | |
38 | */ | |
39 | @NonNullByDefault | |
40 | public class AnnotationCodeMining extends LineHeaderCodeMining { | |
41 | private final Annotation annotation; | |
42 | ||
43 | private final IAnnotationAccessExtension annotationAccess; | |
44 | ||
45 | public AnnotationCodeMining(IAnnotationAccessExtension annotationAccess, Annotation annotation, int lineNumber, IDocument document, ICodeMiningProvider provider, | |
46 | @Nullable Consumer<MouseEvent> action) throws BadLocationException { | |
47 | super(lineNumber, document, provider, action); | |
48 | this.annotationAccess= annotationAccess; | |
49 | ||
50 | setLabel(sanitizeLabel(annotation.getText())); | |
51 | ||
52 | this.annotation= annotation; | |
53 | } | |
54 | ||
55 | private static String sanitizeLabel(String label) { | |
56 | return label.replace('\r', ' ').replace('\n', ' '); | |
57 | } | |
58 | ||
59 | @Override | |
60 | @SuppressWarnings("null") | |
61 | public Point draw(GC gc, StyledText textWidget, Color color, int x, int y) { | |
62 | final int width= 16; | |
63 | annotationAccess.paint(this.annotation, gc, textWidget, new Rectangle(x, y, width, 16)); | |
64 | final Point result= super.draw(gc, textWidget, color, x + width, y); | |
65 | result.x+= width; | |
66 | return result; | |
67 | } | |
68 | } |
+239
-0
0 | /******************************************************************************* | |
1 | * Copyright (c) 2019 Altran Netherlands B.V. 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 | * Niko Stotz (Altran Netherlands B.V.) - initial implementation | |
12 | *******************************************************************************/ | |
13 | package org.eclipse.ui.internal.editors.text.codemining.annotation; | |
14 | ||
15 | import java.util.Arrays; | |
16 | import java.util.Iterator; | |
17 | import java.util.LinkedHashMap; | |
18 | import java.util.Map; | |
19 | import java.util.Objects; | |
20 | import java.util.Spliterator; | |
21 | import java.util.Spliterators; | |
22 | import java.util.function.Function; | |
23 | import java.util.function.Predicate; | |
24 | import java.util.stream.Stream; | |
25 | import java.util.stream.StreamSupport; | |
26 | ||
27 | import org.eclipse.jdt.annotation.NonNullByDefault; | |
28 | import org.eclipse.jdt.annotation.Nullable; | |
29 | ||
30 | import org.eclipse.core.resources.IMarker; | |
31 | ||
32 | import org.eclipse.jface.text.quickassist.IQuickFixableAnnotation; | |
33 | import org.eclipse.jface.text.source.Annotation; | |
34 | import org.eclipse.jface.text.source.IAnnotationAccessExtension; | |
35 | import org.eclipse.jface.text.source.IAnnotationPresentation; | |
36 | ||
37 | import org.eclipse.ui.texteditor.MarkerAnnotation; | |
38 | ||
39 | /** | |
40 | * Filters and arranges Annotations that are suitable as code minings. Takes user preferences into | |
41 | * account. | |
42 | * | |
43 | * @since 3.13 | |
44 | */ | |
45 | @NonNullByDefault | |
46 | public class AnnotationCodeMiningFilter { | |
47 | /** | |
48 | * Callback to locate an Annotation inside the editor. | |
49 | */ | |
50 | public interface Locator { | |
51 | public @Nullable Integer getOffset(Annotation annotation); | |
52 | ||
53 | public @Nullable Integer getLine(Annotation annotation); | |
54 | } | |
55 | ||
56 | final private IAnnotationAccessExtension annotationAccess; | |
57 | ||
58 | final private AnnotationCodeMiningPreferences preferences= new AnnotationCodeMiningPreferences(); | |
59 | ||
60 | final private Stream<Annotation> annotations; | |
61 | ||
62 | public AnnotationCodeMiningFilter(IAnnotationAccessExtension annotationAccess, Annotation[]... annotations) { | |
63 | this.annotationAccess= annotationAccess; | |
64 | this.annotations= Arrays.stream(annotations).flatMap(Arrays::stream); | |
65 | } | |
66 | ||
67 | public AnnotationCodeMiningFilter(IAnnotationAccessExtension annotationAccess, Iterator<Annotation> annotations) { | |
68 | this.annotationAccess= annotationAccess; | |
69 | this.annotations= StreamSupport.stream(Spliterators.spliteratorUnknownSize(annotations, Spliterator.ORDERED), false); | |
70 | } | |
71 | ||
72 | /** | |
73 | * Checks if there are any suitable annotations. | |
74 | */ | |
75 | public boolean isEmpty() { | |
76 | return !filterReTrigger(annotations).findAny().isPresent(); | |
77 | } | |
78 | ||
79 | /** | |
80 | * Returns all suitable annotations. | |
81 | */ | |
82 | public Stream<Annotation> sortDistinctLimit(Locator locator) { | |
83 | return limit(distinct(locator, sort(locator, filterShown(filterReTrigger(annotations))))); | |
84 | } | |
85 | ||
86 | /** | |
87 | * Filters suitable annotations to decide whether we need to re-trigger code minings. | |
88 | */ | |
89 | private Stream<Annotation> filterReTrigger(Stream<Annotation> anns) { | |
90 | return anns | |
91 | .filter(this::isTypeProcessable) | |
92 | .filter(this::isPaintable) | |
93 | .filter(this::isInScope); | |
94 | } | |
95 | ||
96 | private boolean isTypeProcessable(Annotation a) { | |
97 | return a instanceof MarkerAnnotation || | |
98 | a instanceof IQuickFixableAnnotation || | |
99 | a instanceof IAnnotationPresentation; | |
100 | } | |
101 | ||
102 | private boolean isPaintable(Annotation a) { | |
103 | // workaround for https://bugs.eclipse.org/bugs/show_bug.cgi?id=552760 | |
104 | // (NPE on JavaAnnotationImageProvider.getQuickFixErrorImage(): No Display) | |
105 | try { | |
106 | return annotationAccess.isPaintable(a); | |
107 | } catch (NullPointerException e) { | |
108 | return false; | |
109 | } | |
110 | } | |
111 | ||
112 | private boolean isInScope(Annotation a) { | |
113 | return isError(a) || isWarning(a) || isInfo(a); | |
114 | } | |
115 | ||
116 | /** | |
117 | * Filters suitable annotations to show. | |
118 | */ | |
119 | private Stream<Annotation> filterShown(Stream<Annotation> anns) { | |
120 | return anns | |
121 | .filter(a -> !a.isMarkedDeleted()) | |
122 | .filter(this::isEnabled); | |
123 | } | |
124 | ||
125 | private boolean isEnabled(Annotation a) { | |
126 | if (isError(a)) { | |
127 | return preferences.isErrorEnabled(); | |
128 | } else if (isWarning(a)) { | |
129 | return preferences.isWarningEnabled(); | |
130 | } else if (isInfo(a)) { | |
131 | return preferences.isInfoEnabled(); | |
132 | } else { | |
133 | return false; | |
134 | } | |
135 | } | |
136 | ||
137 | /** | |
138 | * Sorts annotations based on 1) position in text, 2) layer, 3) severity, 4) text. | |
139 | */ | |
140 | private Stream<Annotation> sort(Locator locator, Stream<Annotation> anns) { | |
141 | return anns.sorted((a, b) -> { | |
142 | int resultPosition= comparePosition(locator, a, b); | |
143 | if (resultPosition != 0) { | |
144 | return resultPosition; | |
145 | } | |
146 | ||
147 | final int resultLayer= compareLayer(a, b); | |
148 | if (resultLayer != 0) { | |
149 | return resultLayer; | |
150 | } | |
151 | ||
152 | final int resultSeverity= compareSeverity(a, b); | |
153 | if (resultSeverity != 0) { | |
154 | return resultSeverity; | |
155 | } | |
156 | ||
157 | return a.getText().compareTo(b.getText()); | |
158 | }); | |
159 | } | |
160 | ||
161 | private int comparePosition(Locator locator, Annotation a, Annotation b) { | |
162 | final Integer aOffset= locator.getOffset(a); | |
163 | final Integer bOffset= locator.getOffset(b); | |
164 | ||
165 | if (aOffset == null || bOffset == null) { | |
166 | return 0; | |
167 | } | |
168 | ||
169 | int resultPosition= Integer.compare(aOffset, bOffset); | |
170 | return resultPosition; | |
171 | } | |
172 | ||
173 | private int compareLayer(Annotation a, Annotation b) { | |
174 | final int resultPriority= Integer.compare(annotationAccess.getLayer(a), annotationAccess.getLayer(b)); | |
175 | return resultPriority; | |
176 | } | |
177 | ||
178 | private int compareSeverity(Annotation a, Annotation b) { | |
179 | final int resultSeverity= Integer.compare(getSeverity(a), getSeverity(b)); | |
180 | return resultSeverity; | |
181 | } | |
182 | ||
183 | private int getSeverity(Annotation a) { | |
184 | if (isError(a)) { | |
185 | return IMarker.SEVERITY_ERROR; | |
186 | } else if (isWarning(a)) { | |
187 | return IMarker.SEVERITY_WARNING; | |
188 | } else if (isInfo(a)) { | |
189 | return IMarker.SEVERITY_INFO; | |
190 | } else { | |
191 | return -1; | |
192 | } | |
193 | } | |
194 | ||
195 | /** | |
196 | * Assures annotations are distinct by line and text. Required, as sometimes the same message is | |
197 | * shown at the same place from different annotations. | |
198 | */ | |
199 | @SuppressWarnings("null") | |
200 | private Stream<Annotation> distinct(Locator locator, Stream<Annotation> anns) { | |
201 | return anns | |
202 | .filter(distinctByKey(a -> { | |
203 | final Integer line= locator.getLine(a); | |
204 | if (line == null) { | |
205 | return null; | |
206 | } | |
207 | String key= line + a.getText(); | |
208 | ||
209 | return key; | |
210 | })) | |
211 | .filter(Objects::nonNull); | |
212 | } | |
213 | ||
214 | /** | |
215 | * Limits annotations to user-defined amount. | |
216 | */ | |
217 | private Stream<Annotation> limit(Stream<Annotation> anns) { | |
218 | return anns.limit(preferences.getMaxMinings()); | |
219 | } | |
220 | ||
221 | private boolean isInfo(Annotation a) { | |
222 | return annotationAccess.isSubtype(a.getType(), "org.eclipse.ui.workbench.texteditor.info"); //$NON-NLS-1$ | |
223 | } | |
224 | ||
225 | private boolean isWarning(Annotation a) { | |
226 | return annotationAccess.isSubtype(a.getType(), "org.eclipse.ui.workbench.texteditor.warning"); //$NON-NLS-1$ | |
227 | } | |
228 | ||
229 | private boolean isError(Annotation a) { | |
230 | return annotationAccess.isSubtype(a.getType(), "org.eclipse.ui.workbench.texteditor.error"); //$NON-NLS-1$ | |
231 | } | |
232 | ||
233 | @SuppressWarnings("null") | |
234 | public static <T> Predicate<T> distinctByKey(Function<? super T, Object> keyExtractor) { | |
235 | Map<Object, Boolean> seen= new LinkedHashMap<>(); | |
236 | return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null; | |
237 | } | |
238 | } |
+136
-0
0 | /******************************************************************************* | |
1 | * Copyright (c) 2019 Altran Netherlands B.V. 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 | * Niko Stotz (Altran Netherlands B.V.) - initial implementation | |
12 | *******************************************************************************/ | |
13 | package org.eclipse.ui.internal.editors.text.codemining.annotation; | |
14 | ||
15 | import org.eclipse.jface.preference.IPreferenceStore; | |
16 | ||
17 | import org.eclipse.ui.internal.editors.text.EditorsPlugin; | |
18 | ||
19 | /** | |
20 | * Preference constants used for the annotation code mining preference store. | |
21 | * | |
22 | * @since 3.13 | |
23 | * @noinstantiate This class is not intended to be instantiated by clients. | |
24 | * @noextend This class is not intended to be subclassed by clients. | |
25 | */ | |
26 | public class AnnotationCodeMiningPreferenceConstants { | |
27 | private AnnotationCodeMiningPreferenceConstants() { | |
28 | ||
29 | } | |
30 | ||
31 | /** | |
32 | * A named preference that controls which {@link org.eclipse.jface.text.source.Annotation | |
33 | * Annotations} level should be shown as code minings. | |
34 | * <p> | |
35 | * Value is of type <code>Integer</code>. | |
36 | * </p> | |
37 | * | |
38 | * @since 3.13 | |
39 | */ | |
40 | public final static String SHOW_ANNOTATION_CODE_MINING_LEVEL= "showAnnotationAsCodeMiningLevel"; //$NON-NLS-1$ | |
41 | ||
42 | /** | |
43 | * Value for {@link #SHOW_ANNOTATION_CODE_MINING_LEVEL} to show no annotation code minings. | |
44 | * | |
45 | * @since 3.13 | |
46 | */ | |
47 | public final static int SHOW_ANNOTATION_CODE_MINING_LEVEL__NONE= 0b0; | |
48 | ||
49 | /** | |
50 | * Value for {@link #SHOW_ANNOTATION_CODE_MINING_LEVEL} to show info annotation code minings. | |
51 | * | |
52 | * @since 3.13 | |
53 | */ | |
54 | public final static int SHOW_ANNOTATION_CODE_MINING_LEVEL__INFO= 0b10; | |
55 | ||
56 | /** | |
57 | * Value for {@link #SHOW_ANNOTATION_CODE_MINING_LEVEL} to show warning annotation code minings. | |
58 | * | |
59 | * @since 3.13 | |
60 | */ | |
61 | public final static int SHOW_ANNOTATION_CODE_MINING_LEVEL__WARNING= 0b100; | |
62 | ||
63 | /** | |
64 | * Value for {@link #SHOW_ANNOTATION_CODE_MINING_LEVEL} to show error annotation code minings. | |
65 | * | |
66 | * @since 3.13 | |
67 | */ | |
68 | public final static int SHOW_ANNOTATION_CODE_MINING_LEVEL__ERROR= 0b1000; | |
69 | ||
70 | /** | |
71 | * Value for {@link #SHOW_ANNOTATION_CODE_MINING_LEVEL} to show error and warning annotation | |
72 | * code minings. | |
73 | * | |
74 | * @since 3.13 | |
75 | */ | |
76 | public final static int SHOW_ANNOTATION_CODE_MINING_LEVEL__ERROR_WARNING= SHOW_ANNOTATION_CODE_MINING_LEVEL__ERROR | |
77 | | SHOW_ANNOTATION_CODE_MINING_LEVEL__WARNING; | |
78 | ||
79 | /** | |
80 | * Value for {@link #SHOW_ANNOTATION_CODE_MINING_LEVEL} to show error, warning, and info | |
81 | * annotation code minings. | |
82 | * | |
83 | * @since 3.13 | |
84 | */ | |
85 | public final static int SHOW_ANNOTATION_CODE_MINING_LEVEL__ERROR_WARNING_INFO= SHOW_ANNOTATION_CODE_MINING_LEVEL__ERROR | |
86 | | SHOW_ANNOTATION_CODE_MINING_LEVEL__WARNING | |
87 | | SHOW_ANNOTATION_CODE_MINING_LEVEL__INFO; | |
88 | ||
89 | /** | |
90 | * Default value for {@link #SHOW_ANNOTATION_CODE_MINING_LEVEL}. | |
91 | * | |
92 | * @since 3.13 | |
93 | */ | |
94 | public final static int SHOW_ANNOTATION_CODE_MINING_LEVEL__DEFAULT= SHOW_ANNOTATION_CODE_MINING_LEVEL__NONE; | |
95 | ||
96 | /** | |
97 | * A named preference that controls how many {@link org.eclipse.jface.text.source.Annotation | |
98 | * Annotations}s should be shown at most as code minings. | |
99 | * <p> | |
100 | * Value is of type <code>Integer</code>. | |
101 | * </p> | |
102 | * | |
103 | * @since 3.13 | |
104 | */ | |
105 | public final static String SHOW_ANNOTATION_CODE_MINING_MAX= "showAnnotationAsCodeMiningMax"; //$NON-NLS-1$ | |
106 | ||
107 | /** | |
108 | * Default value for {@link #SHOW_ANNOTATION_CODE_MINING_MAX}. | |
109 | * | |
110 | * @since 3.13 | |
111 | */ | |
112 | public final static int SHOW_ANNOTATION_CODE_MINING_MAX__DEFAULT= 100; | |
113 | ||
114 | /** | |
115 | * Returns the Generic Editor preference store. | |
116 | * | |
117 | * @return the Generic Editor preference store | |
118 | */ | |
119 | public static IPreferenceStore getPreferenceStore() { | |
120 | return EditorsPlugin.getDefault().getPreferenceStore(); | |
121 | } | |
122 | ||
123 | /** | |
124 | * Initializes the given preference store with the default values. | |
125 | * | |
126 | * @param store the preference store to be initialized | |
127 | * | |
128 | * @since 3.13 | |
129 | */ | |
130 | public static void initializeDefaultValues(IPreferenceStore store) { | |
131 | store.setDefault(SHOW_ANNOTATION_CODE_MINING_LEVEL, SHOW_ANNOTATION_CODE_MINING_LEVEL__DEFAULT); | |
132 | store.setDefault(SHOW_ANNOTATION_CODE_MINING_MAX, SHOW_ANNOTATION_CODE_MINING_MAX__DEFAULT); | |
133 | } | |
134 | ||
135 | } |
+97
-0
0 | /******************************************************************************* | |
1 | * Copyright (c) 2019 Altran Netherlands B.V. 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 | * Niko Stotz (Altran Netherlands B.V.) - initial implementation | |
12 | *******************************************************************************/ | |
13 | package org.eclipse.ui.internal.editors.text.codemining.annotation; | |
14 | ||
15 | import org.eclipse.jdt.annotation.Nullable; | |
16 | ||
17 | import org.eclipse.jface.preference.IPreferenceStore; | |
18 | ||
19 | /** | |
20 | * Simplifies access to user preferences related to Annotation-based code minings. | |
21 | * | |
22 | * <p> | |
23 | * All methods fall back to defaults if the preference store is unavailable. | |
24 | * </p> | |
25 | * | |
26 | * <p> | |
27 | * The following preferences are available: | |
28 | * </p> | |
29 | * | |
30 | * <dl> | |
31 | * <dt>show infos <i>(default: <code>false</code>)</i></dt> | |
32 | * <dd>Whether INFO-level annotations should be shown as code minings.</dd> | |
33 | * | |
34 | * <dt>show warnings <i>(default: <code>false</code>)</i></dt> | |
35 | * <dd>Whether WARNING-level annotations should be shown as code minings.</dd> | |
36 | * | |
37 | * <dt>show errors <i>(default: <code>false</code>)</i></dt> | |
38 | * <dd>Whether ERROR-level annotations should be shown as code minings.</dd> | |
39 | * | |
40 | * <dt>Maximum annotations shown <i>(default: <code>100</code>)</i></dt> | |
41 | * <dd>How many annotations should be shown at most as code minings. Mainly to prevent bad editor | |
42 | * performance.</dd> | |
43 | * </dl> | |
44 | * | |
45 | * @since 3.13 | |
46 | */ | |
47 | public class AnnotationCodeMiningPreferences { | |
48 | private IPreferenceStore preferenceStore; | |
49 | ||
50 | public boolean isInfoEnabled() { | |
51 | return (getLevel() & AnnotationCodeMiningPreferenceConstants.SHOW_ANNOTATION_CODE_MINING_LEVEL__INFO) > 0; | |
52 | } | |
53 | ||
54 | public boolean isWarningEnabled() { | |
55 | return (getLevel() & AnnotationCodeMiningPreferenceConstants.SHOW_ANNOTATION_CODE_MINING_LEVEL__WARNING) > 0; | |
56 | } | |
57 | ||
58 | public boolean isErrorEnabled() { | |
59 | return (getLevel() & AnnotationCodeMiningPreferenceConstants.SHOW_ANNOTATION_CODE_MINING_LEVEL__ERROR) > 0; | |
60 | } | |
61 | ||
62 | public boolean isEnabled() { | |
63 | final IPreferenceStore node= getPreferences(); | |
64 | if (node == null) { | |
65 | return false; | |
66 | } | |
67 | ||
68 | final int max= getMaxMinings(); | |
69 | ||
70 | return max > 0 && getLevel() > 0; | |
71 | } | |
72 | ||
73 | int getLevel() { | |
74 | IPreferenceStore node= getPreferences(); | |
75 | ||
76 | return node != null | |
77 | ? node.getInt(AnnotationCodeMiningPreferenceConstants.SHOW_ANNOTATION_CODE_MINING_LEVEL) | |
78 | : AnnotationCodeMiningPreferenceConstants.SHOW_ANNOTATION_CODE_MINING_LEVEL__DEFAULT; | |
79 | } | |
80 | ||
81 | int getMaxMinings() { | |
82 | final IPreferenceStore node= getPreferences(); | |
83 | ||
84 | return node != null | |
85 | ? node.getInt(AnnotationCodeMiningPreferenceConstants.SHOW_ANNOTATION_CODE_MINING_MAX) | |
86 | : AnnotationCodeMiningPreferenceConstants.SHOW_ANNOTATION_CODE_MINING_MAX__DEFAULT; | |
87 | } | |
88 | ||
89 | protected @Nullable IPreferenceStore getPreferences() { | |
90 | if (preferenceStore == null) { | |
91 | preferenceStore= AnnotationCodeMiningPreferenceConstants.getPreferenceStore(); | |
92 | } | |
93 | ||
94 | return preferenceStore; | |
95 | } | |
96 | } |
+342
-0
0 | /******************************************************************************* | |
1 | * Copyright (c) 2018 Altran Netherlands B.V. 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 | * Niko Stotz (Altran Netherlands B.V.) - initial implementation | |
12 | *******************************************************************************/ | |
13 | package org.eclipse.ui.internal.editors.text.codemining.annotation; | |
14 | ||
15 | import java.util.Collections; | |
16 | import java.util.List; | |
17 | import java.util.Objects; | |
18 | import java.util.concurrent.CompletableFuture; | |
19 | import java.util.function.Consumer; | |
20 | import java.util.stream.Collectors; | |
21 | import java.util.stream.Stream; | |
22 | ||
23 | import org.eclipse.jdt.annotation.NonNullByDefault; | |
24 | import org.eclipse.jdt.annotation.Nullable; | |
25 | ||
26 | import org.eclipse.swt.events.MouseEvent; | |
27 | ||
28 | import org.eclipse.core.runtime.Assert; | |
29 | import org.eclipse.core.runtime.IProgressMonitor; | |
30 | import org.eclipse.core.runtime.IStatus; | |
31 | import org.eclipse.core.runtime.Status; | |
32 | ||
33 | import org.eclipse.jface.preference.IPreferenceStore; | |
34 | import org.eclipse.jface.util.IPropertyChangeListener; | |
35 | import org.eclipse.jface.util.PropertyChangeEvent; | |
36 | ||
37 | import org.eclipse.jface.text.BadLocationException; | |
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.AbstractCodeMining; | |
42 | import org.eclipse.jface.text.codemining.AbstractCodeMiningProvider; | |
43 | import org.eclipse.jface.text.codemining.ICodeMining; | |
44 | import org.eclipse.jface.text.quickassist.IQuickAssistAssistant; | |
45 | import org.eclipse.jface.text.quickassist.IQuickFixableAnnotation; | |
46 | import org.eclipse.jface.text.source.Annotation; | |
47 | import org.eclipse.jface.text.source.AnnotationModelEvent; | |
48 | import org.eclipse.jface.text.source.IAnnotationAccess; | |
49 | import org.eclipse.jface.text.source.IAnnotationAccessExtension; | |
50 | import org.eclipse.jface.text.source.IAnnotationModel; | |
51 | import org.eclipse.jface.text.source.IAnnotationModelListener; | |
52 | import org.eclipse.jface.text.source.IAnnotationModelListenerExtension; | |
53 | import org.eclipse.jface.text.source.ISourceViewerExtension2; | |
54 | import org.eclipse.jface.text.source.ISourceViewerExtension3; | |
55 | import org.eclipse.jface.text.source.ISourceViewerExtension5; | |
56 | ||
57 | import org.eclipse.ui.internal.editors.text.EditorsPlugin; | |
58 | ||
59 | import org.eclipse.ui.editors.text.EditorsUI; | |
60 | ||
61 | /** | |
62 | * Shows <i>info</i>, <i>warning</i>, and <i>error</i> Annotations as line header code minings. | |
63 | * | |
64 | * <p> | |
65 | * If the annotation is quickfixable, clicking on the code mining triggers the quickfix. | |
66 | * </p> | |
67 | * <p> | |
68 | * The user can configure which and how many Annotations should be shown in preferences. | |
69 | * </p> | |
70 | * <p> | |
71 | * Works out-of-the-box for all code mining-enabled text editors. | |
72 | * </p> | |
73 | * | |
74 | * @since 3.13 | |
75 | * @see org.eclipse.ui.internal.editors.text.codemining.annotation.AnnotationCodeMiningPreferences | |
76 | */ | |
77 | @NonNullByDefault | |
78 | public class AnnotationCodeMiningProvider extends AbstractCodeMiningProvider | |
79 | implements AnnotationCodeMiningFilter.Locator { | |
80 | ||
81 | /** | |
82 | * Updates code minings after changes to preferences. | |
83 | */ | |
84 | private class PropertyChangeListener implements IPropertyChangeListener { | |
85 | ||
86 | @Override | |
87 | public void propertyChange(PropertyChangeEvent event) { | |
88 | switch (event.getProperty()) { | |
89 | case AnnotationCodeMiningPreferenceConstants.SHOW_ANNOTATION_CODE_MINING_LEVEL: | |
90 | case AnnotationCodeMiningPreferenceConstants.SHOW_ANNOTATION_CODE_MINING_MAX: | |
91 | getCodeMiningViewer().updateCodeMinings(); | |
92 | break; | |
93 | default: | |
94 | // ignore | |
95 | } | |
96 | } | |
97 | } | |
98 | ||
99 | /** | |
100 | * Updates code minings after changes to annotations. | |
101 | */ | |
102 | private class AnnotationModelListener implements IAnnotationModelListener, IAnnotationModelListenerExtension { | |
103 | @Override | |
104 | public void modelChanged(@Nullable IAnnotationModel model) { | |
105 | // ignore | |
106 | } | |
107 | ||
108 | @Override | |
109 | public void modelChanged(@SuppressWarnings("null") AnnotationModelEvent event) { | |
110 | if (viewer == null) { | |
111 | return; | |
112 | } | |
113 | ||
114 | if (!event.isValid() || event.isEmpty()) { | |
115 | return; | |
116 | } | |
117 | ||
118 | AnnotationCodeMiningFilter filter= new AnnotationCodeMiningFilter(getAnnotationAccess(), | |
119 | event.getAddedAnnotations(), event.getRemovedAnnotations(), event.getChangedAnnotations()); | |
120 | ||
121 | if (!filter.isEmpty()) { | |
122 | getCodeMiningViewer().updateCodeMinings(); | |
123 | } | |
124 | } | |
125 | } | |
126 | ||
127 | private @Nullable ITextViewer viewer= null; | |
128 | ||
129 | private @Nullable AnnotationModelListener annotationModelListener= null; | |
130 | ||
131 | private @Nullable PropertyChangeListener propertyChangeListener= null; | |
132 | ||
133 | private @Nullable IAnnotationAccessExtension annotationAccess= null; | |
134 | ||
135 | @Override | |
136 | @SuppressWarnings("null") | |
137 | public CompletableFuture<List<? extends ICodeMining>> provideCodeMinings(ITextViewer viewer, IProgressMonitor monitor) { | |
138 | if (!(viewer instanceof ISourceViewerExtension5)) { | |
139 | throw new IllegalArgumentException("Cannot attach to TextViewer without code mining support"); //$NON-NLS-1$ | |
140 | } | |
141 | ||
142 | if (!new AnnotationCodeMiningPreferences().isEnabled()) { | |
143 | return CompletableFuture.completedFuture(Collections.emptyList()); | |
144 | } | |
145 | ||
146 | this.viewer= viewer; | |
147 | ||
148 | final IAnnotationAccess annotationAccess= getAdapter(IAnnotationAccess.class); | |
149 | if (!(annotationAccess instanceof IAnnotationAccessExtension)) { | |
150 | throw new IllegalStateException("annotationAccess must implement IAnnotationAccessExtension"); //$NON-NLS-1$ | |
151 | } | |
152 | this.annotationAccess= (IAnnotationAccessExtension) annotationAccess; | |
153 | ||
154 | return provideCodeMiningsInternal(monitor); | |
155 | } | |
156 | ||
157 | @Override | |
158 | public void dispose() { | |
159 | unregisterPropertyChangeListener(); | |
160 | unregisterAnnotationModelListener(); | |
161 | ||
162 | this.viewer= null; | |
163 | ||
164 | super.dispose(); | |
165 | } | |
166 | ||
167 | @Override | |
168 | @SuppressWarnings("boxing") | |
169 | public @Nullable Integer getLine(Annotation annotation) { | |
170 | Integer offset= getOffset(annotation); | |
171 | if (offset == null) { | |
172 | return null; | |
173 | } | |
174 | ||
175 | try { | |
176 | return getDocument().getLineOfOffset(offset); | |
177 | } catch (BadLocationException e) { | |
178 | return null; | |
179 | } | |
180 | } | |
181 | ||
182 | @Override | |
183 | @SuppressWarnings("boxing") | |
184 | public @Nullable Integer getOffset(Annotation annotation) { | |
185 | final Position position= getAnnotationModel().getPosition(annotation); | |
186 | if (position == null) { | |
187 | return null; | |
188 | } | |
189 | ||
190 | return position.getOffset(); | |
191 | } | |
192 | ||
193 | private CompletableFuture<List<? extends ICodeMining>> provideCodeMiningsInternal(IProgressMonitor monitor) { | |
194 | return CompletableFuture.supplyAsync(() -> { | |
195 | if (!checkAnnotationModelAvailable()) { | |
196 | return Collections.emptyList(); | |
197 | } | |
198 | ||
199 | registerAnnotationModelListener(); | |
200 | registerPropertyChangeListener(); | |
201 | ||
202 | final Stream<Annotation> annotations= getAnnotations(); | |
203 | final List<AbstractCodeMining> codeMinings= createCodeMinings(annotations, monitor); | |
204 | ||
205 | return codeMinings; | |
206 | }); | |
207 | } | |
208 | ||
209 | private void registerAnnotationModelListener() { | |
210 | if (annotationModelListener == null) { | |
211 | annotationModelListener= new AnnotationModelListener(); | |
212 | getAnnotationModel().addAnnotationModelListener(annotationModelListener); | |
213 | } | |
214 | } | |
215 | ||
216 | private void unregisterAnnotationModelListener() { | |
217 | if (this.annotationModelListener != null) { | |
218 | getAnnotationModel().removeAnnotationModelListener(annotationModelListener); | |
219 | this.annotationModelListener= null; | |
220 | } | |
221 | } | |
222 | ||
223 | private void registerPropertyChangeListener() { | |
224 | if (propertyChangeListener == null) { | |
225 | final @Nullable IPreferenceStore store= new AnnotationCodeMiningPreferences().getPreferences(); | |
226 | if (store != null) { | |
227 | propertyChangeListener= new PropertyChangeListener(); | |
228 | store.addPropertyChangeListener(propertyChangeListener); | |
229 | } | |
230 | } | |
231 | } | |
232 | ||
233 | private void unregisterPropertyChangeListener() { | |
234 | if (this.propertyChangeListener != null) { | |
235 | final @Nullable IPreferenceStore store= new AnnotationCodeMiningPreferences().getPreferences(); | |
236 | if (store != null) { | |
237 | store.removePropertyChangeListener(propertyChangeListener); | |
238 | } | |
239 | this.propertyChangeListener= null; | |
240 | } | |
241 | } | |
242 | ||
243 | private Stream<Annotation> getAnnotations() { | |
244 | return new AnnotationCodeMiningFilter(getAnnotationAccess(), getAnnotationModel().getAnnotationIterator()) | |
245 | .sortDistinctLimit(this); | |
246 | } | |
247 | ||
248 | private List<AbstractCodeMining> createCodeMinings(Stream<Annotation> annotations, IProgressMonitor monitor) { | |
249 | @SuppressWarnings("null") | |
250 | final Stream<AbstractCodeMining> result= annotations | |
251 | .filter(m -> !monitor.isCanceled()) | |
252 | .map(this::createCodeMining) | |
253 | .filter(Objects::nonNull); | |
254 | return result.collect(Collectors.toList()); | |
255 | } | |
256 | ||
257 | @SuppressWarnings("boxing") | |
258 | private @Nullable AbstractCodeMining createCodeMining(Annotation annotation) { | |
259 | final Integer lineNumber= getLine(annotation); | |
260 | ||
261 | if (lineNumber == null) { | |
262 | return null; | |
263 | } | |
264 | ||
265 | try { | |
266 | final Consumer<MouseEvent> action= createAction(annotation); | |
267 | return new AnnotationCodeMining(getAnnotationAccess(), annotation, lineNumber, getDocument(), this, action); | |
268 | } catch (BadLocationException e) { | |
269 | return null; | |
270 | } | |
271 | } | |
272 | ||
273 | /** | |
274 | * The action selects the text attached to the Annotation and activates quickfixes. | |
275 | */ | |
276 | private @Nullable Consumer<MouseEvent> createAction(Annotation annotation) { | |
277 | if (!(annotation instanceof IQuickFixableAnnotation) || !(getTextViewer() instanceof ISourceViewerExtension3)) { | |
278 | return null; | |
279 | } | |
280 | ||
281 | final Position position= getAnnotationModel().getPosition(annotation); | |
282 | if (position == null) { | |
283 | return null; | |
284 | } | |
285 | ||
286 | return (e -> { | |
287 | final IQuickFixableAnnotation quickFixableAnnotation= (IQuickFixableAnnotation) annotation; | |
288 | if (!quickFixableAnnotation.isQuickFixableStateSet() || !quickFixableAnnotation.isQuickFixable()) { | |
289 | return; | |
290 | } | |
291 | ||
292 | final IQuickAssistAssistant quickAssistAssistant= ((ISourceViewerExtension3) getTextViewer()).getQuickAssistAssistant(); | |
293 | if (quickAssistAssistant == null) { | |
294 | return; | |
295 | } | |
296 | ||
297 | if (!quickAssistAssistant.canFix(annotation)) { | |
298 | return; | |
299 | } | |
300 | ||
301 | getTextViewer().setSelectedRange(position.getOffset(), position.getLength()); | |
302 | ||
303 | final String message= quickAssistAssistant.showPossibleQuickAssists(); | |
304 | ||
305 | if (message != null) { | |
306 | EditorsPlugin.getDefault().getLog().log(new Status(IStatus.ERROR, EditorsUI.PLUGIN_ID, message)); | |
307 | } | |
308 | ||
309 | }); | |
310 | } | |
311 | ||
312 | private boolean checkAnnotationModelAvailable() { | |
313 | return viewer != null && getAnnotationViewer().getVisualAnnotationModel() != null; | |
314 | } | |
315 | ||
316 | private IAnnotationModel getAnnotationModel() { | |
317 | return getAnnotationViewer().getVisualAnnotationModel(); | |
318 | } | |
319 | ||
320 | private ITextViewer getTextViewer() { | |
321 | Assert.isNotNull(viewer); | |
322 | return viewer; | |
323 | } | |
324 | ||
325 | private ISourceViewerExtension5 getCodeMiningViewer() { | |
326 | return (ISourceViewerExtension5) getTextViewer(); | |
327 | } | |
328 | ||
329 | private ISourceViewerExtension2 getAnnotationViewer() { | |
330 | return (ISourceViewerExtension2) getTextViewer(); | |
331 | } | |
332 | ||
333 | private IDocument getDocument() { | |
334 | return getTextViewer().getDocument(); | |
335 | } | |
336 | ||
337 | private IAnnotationAccessExtension getAnnotationAccess() { | |
338 | Assert.isNotNull(annotationAccess); | |
339 | return annotationAccess; | |
340 | } | |
341 | } |
+4
-4
80 | 80 | private Font fStatusTextFont; |
81 | 81 | /** |
82 | 82 | * The color of the optional status text label or <code>null</code> if none. |
83 | * | |
83 | * | |
84 | 84 | * @since 3.6 |
85 | 85 | */ |
86 | 86 | private Color fStatusTextForegroundColor; |
207 | 207 | Assert.isLegal(bg != null); |
208 | 208 | Assert.isLegal(fg != null); |
209 | 209 | Assert.isLegal(factor >= 0f && factor <= 1f); |
210 | ||
210 | ||
211 | 211 | float complement= 1f - factor; |
212 | 212 | return new RGB( |
213 | 213 | (int) (complement * bg.red + factor * fg.red), |
215 | 215 | (int) (complement * bg.blue + factor * fg.blue) |
216 | 216 | ); |
217 | 217 | } |
218 | ||
218 | ||
219 | 219 | /* |
220 | 220 | * @see org.eclipse.jface.text.IInformationControlExtension2#setInput(java.lang.Object) |
221 | 221 | */ |
255 | 255 | if (fStatusTextForegroundColor != null && !fStatusTextForegroundColor.isDisposed()) |
256 | 256 | fStatusTextForegroundColor.dispose(); |
257 | 257 | fStatusTextForegroundColor= null; |
258 | ||
258 | ||
259 | 259 | fTextFont= null; |
260 | 260 | fShell= null; |
261 | 261 | fText= null; |
+64
-27
0 | 0 | /******************************************************************************* |
1 | * Copyright (c) 2000, 2018 IBM Corporation and others. | |
1 | * Copyright (c) 2000, 2019 IBM Corporation and others. | |
2 | 2 | * |
3 | 3 | * This program and the accompanying materials |
4 | 4 | * are made available under the terms of the Eclipse Public License 2.0 |
120 | 120 | import org.eclipse.ui.IEditorInput; |
121 | 121 | import org.eclipse.ui.IEditorPart; |
122 | 122 | import org.eclipse.ui.IFileEditorInput; |
123 | import org.eclipse.ui.IPageLayout; | |
123 | 124 | import org.eclipse.ui.IURIEditorInput; |
124 | 125 | import org.eclipse.ui.IWorkbenchActionConstants; |
125 | 126 | import org.eclipse.ui.IWorkbenchCommandConstants; |
150 | 151 | import org.eclipse.ui.operations.NonLocalUndoUserApprover; |
151 | 152 | import org.eclipse.ui.part.FileEditorInput; |
152 | 153 | import org.eclipse.ui.part.IShowInSource; |
154 | import org.eclipse.ui.part.IShowInTargetList; | |
153 | 155 | import org.eclipse.ui.part.ShowInContext; |
154 | 156 | import org.eclipse.ui.views.markers.MarkerViewUtil; |
155 | 157 | |
223 | 225 | |
224 | 226 | /** |
225 | 227 | * Preference key that controls whether to use saturated colors in the overview ruler. |
226 | * | |
228 | * | |
227 | 229 | * @since 3.8 |
228 | 230 | */ |
229 | 231 | private static final String USE_SATURATED_COLORS_IN_OVERVIEW_RULER= AbstractDecoratedTextEditorPreferenceConstants.USE_SATURATED_COLORS_IN_OVERVIEW_RULER; |
311 | 313 | * @since 3.6 |
312 | 314 | */ |
313 | 315 | private boolean fIsComingFromGotoMarker= false; |
314 | ||
316 | ||
315 | 317 | /** |
316 | 318 | * Tells whether editing the current derived editor input is allowed. |
317 | 319 | * @since 3.3 |
339 | 341 | |
340 | 342 | /** |
341 | 343 | * Creates a new text editor. |
342 | * | |
344 | * | |
343 | 345 | * @see #initializeEditor() |
344 | 346 | * @see #initializeKeyBindingScopes() |
345 | 347 | */ |
652 | 654 | |
653 | 655 | /** |
654 | 656 | * Checks if the preference to use saturated colors is enabled for the overview ruler. |
655 | * | |
657 | * | |
656 | 658 | * @return <code>true</code> if the saturated colors preference is enabled, <code>false</code> |
657 | 659 | * otherwise |
658 | 660 | * @since 3.8 |
853 | 855 | return; |
854 | 856 | } |
855 | 857 | |
856 | if (AbstractDecoratedTextEditorPreferenceConstants.EDITOR_SPACES_FOR_TABS.equals(property)) { | |
858 | if (AbstractDecoratedTextEditorPreferenceConstants.EDITOR_SPACES_FOR_TABS.equals(property) | |
859 | || AbstractDecoratedTextEditorPreferenceConstants.EDITOR_DELETE_SPACES_AS_TABS.equals(property)) { | |
857 | 860 | if (isTabsToSpacesConversionEnabled()) |
858 | 861 | installTabsToSpacesConverter(); |
859 | 862 | else |
958 | 961 | if (fSourceViewerDecorationSupport == null) { |
959 | 962 | fSourceViewerDecorationSupport= new SourceViewerDecorationSupport(viewer, getOverviewRuler(), getAnnotationAccess(), getSharedColors()); |
960 | 963 | configureSourceViewerDecorationSupport(fSourceViewerDecorationSupport); |
961 | ||
964 | ||
962 | 965 | // Fix for overridden print margin column, see https://bugs.eclipse.org/468307 |
963 | 966 | if (!getPreferenceStore().getBoolean(PRINT_MARGIN_ALLOW_OVERRIDE)) |
964 | 967 | fSourceViewerDecorationSupport.setMarginPainterPreferenceKeys(PRINT_MARGIN, PRINT_MARGIN_COLOR, PRINT_MARGIN_COLUMN); |
1264 | 1267 | // Override print action to provide additional options |
1265 | 1268 | if (getAction(ITextEditorActionConstants.PRINT).isEnabled() && getSourceViewer() instanceof ITextViewerExtension8) |
1266 | 1269 | createPrintAction(); |
1267 | ||
1270 | ||
1268 | 1271 | action= new ResourceAction(TextEditorMessages.getBundleForConstructedKeys(), "Editor.ShowChangeRulerInformation.", IAction.AS_PUSH_BUTTON) { //$NON-NLS-1$ |
1269 | 1272 | @Override |
1270 | 1273 | public void run() { |
1287 | 1290 | /** |
1288 | 1291 | * Opens a sticky change ruler hover for the caret line. Does nothing if no change hover is |
1289 | 1292 | * available. |
1290 | * | |
1293 | * | |
1291 | 1294 | * @since 3.5 |
1292 | 1295 | */ |
1293 | 1296 | private void showChangeRulerInformation() { |
1294 | 1297 | IVerticalRuler ruler= getVerticalRuler(); |
1295 | 1298 | if (!(ruler instanceof CompositeRuler) || fLineColumn == null) |
1296 | 1299 | return; |
1297 | ||
1300 | ||
1298 | 1301 | CompositeRuler compositeRuler= (CompositeRuler)ruler; |
1299 | 1302 | |
1300 | 1303 | // fake a mouse move (some hovers rely on this to determine the hovered line): |
1301 | 1304 | int x= fLineColumn.getControl().getLocation().x; |
1302 | ||
1305 | ||
1303 | 1306 | ISourceViewer sourceViewer= getSourceViewer(); |
1304 | 1307 | StyledText textWidget= sourceViewer.getTextWidget(); |
1305 | 1308 | int caretOffset= textWidget.getCaretOffset(); |
1306 | 1309 | int caretLine= textWidget.getLineAtOffset(caretOffset); |
1307 | 1310 | int y= textWidget.getLinePixel(caretLine); |
1308 | ||
1311 | ||
1309 | 1312 | compositeRuler.setLocationOfLastMouseButtonActivity(x, y); |
1310 | ||
1313 | ||
1311 | 1314 | IAnnotationHover hover= fLineColumn.getHover(); |
1312 | 1315 | showFocusedRulerHover(hover, sourceViewer, caretOffset); |
1313 | 1316 | } |
1315 | 1318 | /** |
1316 | 1319 | * Opens a sticky annotation ruler hover for the caret line. Does nothing if no annotation hover |
1317 | 1320 | * is available. |
1318 | * | |
1321 | * | |
1319 | 1322 | * @since 3.6 |
1320 | 1323 | */ |
1321 | 1324 | private void showRulerAnnotationInformation() { |
1322 | 1325 | ISourceViewer sourceViewer= getSourceViewer(); |
1323 | 1326 | IAnnotationHover hover= getSourceViewerConfiguration().getAnnotationHover(sourceViewer); |
1324 | 1327 | int caretOffset= sourceViewer.getTextWidget().getCaretOffset(); |
1325 | ||
1328 | ||
1326 | 1329 | showFocusedRulerHover(hover, sourceViewer, caretOffset); |
1327 | 1330 | } |
1328 | 1331 | |
1329 | 1332 | /** |
1330 | 1333 | * Shows a focused hover at the specified offset. |
1331 | 1334 | * Does nothing if <code>hover</code> is <code>null</code> or cannot be shown. |
1332 | * | |
1335 | * | |
1333 | 1336 | * @param hover the hover to be shown, can be <code>null</code> |
1334 | 1337 | * @param sourceViewer the source viewer |
1335 | 1338 | * @param caretOffset the caret offset |
1336 | * | |
1339 | * | |
1337 | 1340 | * @since 3.6 |
1338 | 1341 | */ |
1339 | 1342 | private void showFocusedRulerHover(IAnnotationHover hover, ISourceViewer sourceViewer, int caretOffset) { |
1340 | 1343 | if (hover == null) |
1341 | 1344 | return; |
1342 | ||
1345 | ||
1343 | 1346 | int modelCaretOffset= widgetOffset2ModelOffset(sourceViewer, caretOffset); |
1344 | 1347 | if (modelCaretOffset == -1) |
1345 | 1348 | return; |
1346 | ||
1349 | ||
1347 | 1350 | IDocument document= sourceViewer.getDocument(); |
1348 | 1351 | if (document == null) |
1349 | 1352 | return; |
1350 | ||
1353 | ||
1351 | 1354 | try { |
1352 | 1355 | int line= document.getLineOfOffset(modelCaretOffset); |
1353 | 1356 | if (fInformationPresenter == null) { |
1425 | 1428 | |
1426 | 1429 | if (MarkerAnnotationPreferences.class.equals(adapter)) |
1427 | 1430 | return (T) EditorsPlugin.getDefault().getMarkerAnnotationPreferences(); |
1431 | ||
1432 | if (IShowInTargetList.class.equals(adapter)) | |
1433 | return (T) getShowInTargetList(); | |
1428 | 1434 | |
1429 | 1435 | return super.getAdapter(adapter); |
1430 | 1436 | |
1632 | 1638 | * Overrides the default behavior by showing a more advanced error dialog in case of encoding |
1633 | 1639 | * problems. |
1634 | 1640 | * </p> |
1635 | * | |
1641 | * | |
1636 | 1642 | * @param title the dialog title |
1637 | 1643 | * @param message the message to display |
1638 | 1644 | * @param exception the exception to handle |
1650 | 1656 | final int saveAsUTF8ButtonId= IDialogConstants.OK_ID + IDialogConstants.CANCEL_ID + 1; |
1651 | 1657 | final int selectUnmappableCharButtonId= saveAsUTF8ButtonId + 1; |
1652 | 1658 | final Charset charset= getCharset(); |
1653 | ||
1659 | ||
1654 | 1660 | ErrorDialog errorDialog= new ErrorDialog(getSite().getShell(), title, message, status, IStatus.ERROR) { |
1655 | 1661 | |
1656 | 1662 | @Override |
1714 | 1720 | |
1715 | 1721 | /** |
1716 | 1722 | * Returns the charset of the current editor input. |
1717 | * | |
1723 | * | |
1718 | 1724 | * @return the charset of the current editor input or <code>null</code> if it fails |
1719 | 1725 | * @since 3.6 |
1720 | 1726 | */ |
2016 | 2022 | |
2017 | 2023 | /** |
2018 | 2024 | * Selects and reveals the given offset and length in the given editor part. |
2019 | * | |
2025 | * | |
2020 | 2026 | * @param editor the editor part |
2021 | 2027 | * @param offset the offset |
2022 | 2028 | * @param length the length |
2087 | 2093 | } |
2088 | 2094 | |
2089 | 2095 | /** |
2096 | * Creates and returns the list of target part IDs for the Show In menu | |
2097 | * | |
2098 | * @return the 'Show In' target part IDs | |
2099 | * @since 3.13 | |
2100 | */ | |
2101 | protected String[] createShowInTargetList() { | |
2102 | return new String[] { IPageLayout.ID_MINIMAP_VIEW }; | |
2103 | } | |
2104 | ||
2105 | /** | |
2106 | * Returns the Show In target list | |
2107 | * | |
2108 | * @return the IShowInTargetList adapter, or <code>null</code> if no targets are listed | |
2109 | */ | |
2110 | private IShowInTargetList getShowInTargetList() { | |
2111 | final String[] targetList= createShowInTargetList(); | |
2112 | if (targetList != null && targetList.length > 0) { | |
2113 | return () -> targetList; | |
2114 | } | |
2115 | return null; | |
2116 | } | |
2117 | ||
2118 | /** | |
2090 | 2119 | * Returns the preference page ids of the preference pages to be shown when executing the |
2091 | 2120 | * preferences action from the editor context menu. The first page will be selected. |
2092 | 2121 | * <p> |
2093 | 2122 | * Subclasses may extend or replace. |
2094 | 2123 | * </p> |
2095 | * | |
2124 | * | |
2096 | 2125 | * @return the preference page ids to show, may be empty |
2097 | 2126 | * @since 3.1 |
2098 | 2127 | */ |
2116 | 2145 | * <p> |
2117 | 2146 | * Subclasses may extend or replace. |
2118 | 2147 | * </p> |
2119 | * | |
2148 | * | |
2120 | 2149 | * @return the preference page ids to show, may be empty |
2121 | 2150 | * @since 3.1 |
2122 | 2151 | */ |
2134 | 2163 | * <p> |
2135 | 2164 | * Subclasses may extend or replace. |
2136 | 2165 | * </p> |
2137 | * | |
2166 | * | |
2138 | 2167 | * @return the preference page ids to show, may be empty |
2139 | 2168 | * @since 3.4 |
2140 | 2169 | */ |
2231 | 2260 | protected boolean isTabsToSpacesConversionEnabled() { |
2232 | 2261 | return getPreferenceStore() != null && getPreferenceStore().getBoolean(AbstractDecoratedTextEditorPreferenceConstants.EDITOR_SPACES_FOR_TABS); |
2233 | 2262 | } |
2263 | ||
2264 | /** | |
2265 | * @since 3.13 | |
2266 | */ | |
2267 | @Override | |
2268 | protected boolean isSpacesAsTabsDeletionEnabled() { | |
2269 | return getPreferenceStore() != null && getPreferenceStore().getBoolean(AbstractDecoratedTextEditorPreferenceConstants.EDITOR_DELETE_SPACES_AS_TABS); | |
2270 | } | |
2234 | 2271 | } |
+35
-21
0 | 0 | /******************************************************************************* |
1 | * Copyright (c) 2000, 2018 IBM Corporation and others. | |
1 | * Copyright (c) 2000, 2019 IBM Corporation and others. | |
2 | 2 | * |
3 | 3 | * This program and the accompanying materials |
4 | 4 | * are made available under the terms of the Eclipse Public License 2.0 |
90 | 90 | public final static String EDITOR_SPACES_FOR_TABS= "spacesForTabs"; //$NON-NLS-1$ |
91 | 91 | |
92 | 92 | /** |
93 | * A named preference that specifies if the editor removes multiple spaces on delete/backspace | |
94 | * key as if they were tabs. Only relevant when {@link #EDITOR_SPACES_FOR_TABS} preference is | |
95 | * set to <code>true</code>. | |
96 | * <p> | |
97 | * Value is of type <code>Boolean</code>. If <code>true</code>, the editor removes multiple | |
98 | * spaces. | |
99 | * </p> | |
100 | * | |
101 | * @since 3.13 | |
102 | */ | |
103 | public final static String EDITOR_DELETE_SPACES_AS_TABS= "removeSpacesAsTabs"; //$NON-NLS-1$ | |
104 | ||
105 | /** | |
93 | 106 | * A named preference that holds the size of the editor's undo history. |
94 | 107 | * <p> |
95 | 108 | * Value is of type <code>int</code>: 0 or positive int value specifying the size of |
135 | 148 | * <p> |
136 | 149 | * The preference value is of type <code>boolean</code>. |
137 | 150 | * </p> |
138 | * | |
151 | * | |
139 | 152 | * @noreference This field is not intended to be referenced by clients. |
140 | 153 | */ |
141 | 154 | public final static String EDITOR_PRINT_MARGIN_ALLOW_OVERRIDE= "printMarginAllowOverride"; //$NON-NLS-1$ |
201 | 214 | * <p> |
202 | 215 | * The preference value is of type <code>Boolean</code>. |
203 | 216 | * </p> |
204 | * | |
217 | * | |
205 | 218 | * @since 3.12 |
206 | 219 | */ |
207 | 220 | public final static String EDITOR_SHOW_CARET_OFFSET= AbstractTextEditor.PREFERENCE_SHOW_CARET_OFFSET; |
212 | 225 | * <p> |
213 | 226 | * The preference value is of type <code>Boolean</code>. |
214 | 227 | * </p> |
215 | * | |
228 | * | |
216 | 229 | * @since 3.12 |
217 | 230 | */ |
218 | 231 | public final static String EDITOR_SHOW_SELECTION_SIZE= AbstractTextEditor.PREFERENCE_SHOW_SELECTION_SIZE; |
224 | 237 | * The preference value is of type <code>String</code>. A RGB color value encoded as a string |
225 | 238 | * using class <code>PreferenceConverter</code>. |
226 | 239 | * </p> |
227 | * | |
240 | * | |
228 | 241 | * @see org.eclipse.jface.resource.StringConverter |
229 | 242 | * @see PreferenceConverter |
230 | 243 | * @see #EDITOR_LINE_NUMBER_RULER |
297 | 310 | * <p> |
298 | 311 | * Value is of type <code>Boolean</code>. If <code>true</code>, saturated colors are used |
299 | 312 | * </p> |
300 | * | |
313 | * | |
301 | 314 | * @since 3.8 |
302 | 315 | * @see org.eclipse.jface.text.source.IOverviewRulerExtension#setUseSaturatedColors(boolean) |
303 | 316 | */ |
398 | 411 | * <p> |
399 | 412 | * The preference value is of type <code>Boolean</code>. |
400 | 413 | * </p> |
401 | * | |
414 | * | |
402 | 415 | * @since 3.5 |
403 | 416 | */ |
404 | 417 | public final static String EDITOR_HYPERLINK_COLOR_SYSTEM_DEFAULT= DefaultHyperlinkPresenter.HYPERLINK_COLOR_SYSTEM_DEFAULT; |
444 | 457 | * <p> |
445 | 458 | * Value is of type <code>Boolean</code>. |
446 | 459 | * </p> |
447 | * | |
460 | * | |
448 | 461 | * <p> |
449 | 462 | * The following preferences can be used for fine-grained configuration when enabled. |
450 | 463 | * </p> |
462 | 475 | * <li>{@link #EDITOR_SHOW_LINE_FEED}</li> |
463 | 476 | * <li>{@link #EDITOR_WHITESPACE_CHARACTER_ALPHA_VALUE}</li> |
464 | 477 | * </ul> |
465 | * | |
478 | * | |
466 | 479 | * @since 3.3 |
467 | 480 | */ |
468 | 481 | public static final String EDITOR_SHOW_WHITESPACE_CHARACTERS= AbstractTextEditor.PREFERENCE_SHOW_WHITESPACE_CHARACTERS; |
473 | 486 | * <p> |
474 | 487 | * Value is of type <code>Boolean</code>. |
475 | 488 | * </p> |
476 | * | |
489 | * | |
477 | 490 | * @since 3.7 |
478 | 491 | */ |
479 | 492 | public static final String EDITOR_SHOW_LEADING_SPACES= AbstractTextEditor.PREFERENCE_SHOW_LEADING_SPACES; |
484 | 497 | * <p> |
485 | 498 | * Value is of type <code>Boolean</code>. |
486 | 499 | * </p> |
487 | * | |
500 | * | |
488 | 501 | * @since 3.7 |
489 | 502 | */ |
490 | 503 | public static final String EDITOR_SHOW_ENCLOSED_SPACES= AbstractTextEditor.PREFERENCE_SHOW_ENCLOSED_SPACES; |
495 | 508 | * <p> |
496 | 509 | * Value is of type <code>Boolean</code>. |
497 | 510 | * </p> |
498 | * | |
511 | * | |
499 | 512 | * @since 3.7 |
500 | 513 | */ |
501 | 514 | public static final String EDITOR_SHOW_TRAILING_SPACES= AbstractTextEditor.PREFERENCE_SHOW_TRAILING_SPACES; |
507 | 520 | * <p> |
508 | 521 | * Value is of type <code>Boolean</code>. |
509 | 522 | * </p> |
510 | * | |
523 | * | |
511 | 524 | * @since 3.7 |
512 | 525 | */ |
513 | 526 | public static final String EDITOR_SHOW_LEADING_IDEOGRAPHIC_SPACES= AbstractTextEditor.PREFERENCE_SHOW_LEADING_IDEOGRAPHIC_SPACES; |
519 | 532 | * <p> |
520 | 533 | * Value is of type <code>Boolean</code>. |
521 | 534 | * </p> |
522 | * | |
535 | * | |
523 | 536 | * @since 3.7 |
524 | 537 | */ |
525 | 538 | public static final String EDITOR_SHOW_ENCLOSED_IDEOGRAPHIC_SPACES= AbstractTextEditor.PREFERENCE_SHOW_ENCLOSED_IDEOGRAPHIC_SPACES; |
531 | 544 | * <p> |
532 | 545 | * Value is of type <code>Boolean</code>. |
533 | 546 | * </p> |
534 | * | |
547 | * | |
535 | 548 | * @since 3.7 |
536 | 549 | */ |
537 | 550 | public static final String EDITOR_SHOW_TRAILING_IDEOGRAPHIC_SPACES= AbstractTextEditor.PREFERENCE_SHOW_TRAILING_IDEOGRAPHIC_SPACES; |
542 | 555 | * <p> |
543 | 556 | * Value is of type <code>Boolean</code>. |
544 | 557 | * </p> |
545 | * | |
558 | * | |
546 | 559 | * @since 3.7 |
547 | 560 | */ |
548 | 561 | public static final String EDITOR_SHOW_LEADING_TABS= AbstractTextEditor.PREFERENCE_SHOW_LEADING_TABS; |
553 | 566 | * <p> |
554 | 567 | * Value is of type <code>Boolean</code>. |
555 | 568 | * </p> |
556 | * | |
569 | * | |
557 | 570 | * @since 3.7 |
558 | 571 | */ |
559 | 572 | public static final String EDITOR_SHOW_ENCLOSED_TABS= AbstractTextEditor.PREFERENCE_SHOW_ENCLOSED_TABS; |
564 | 577 | * <p> |
565 | 578 | * Value is of type <code>Boolean</code>. |
566 | 579 | * </p> |
567 | * | |
580 | * | |
568 | 581 | * @since 3.7 |
569 | 582 | */ |
570 | 583 | public static final String EDITOR_SHOW_TRAILING_TABS= AbstractTextEditor.PREFERENCE_SHOW_TRAILING_TABS; |
575 | 588 | * <p> |
576 | 589 | * Value is of type <code>Boolean</code>. |
577 | 590 | * </p> |
578 | * | |
591 | * | |
579 | 592 | * @since 3.7 |
580 | 593 | */ |
581 | 594 | public static final String EDITOR_SHOW_CARRIAGE_RETURN= AbstractTextEditor.PREFERENCE_SHOW_CARRIAGE_RETURN; |
586 | 599 | * <p> |
587 | 600 | * Value is of type <code>Boolean</code>. |
588 | 601 | * </p> |
589 | * | |
602 | * | |
590 | 603 | * @since 3.7 |
591 | 604 | */ |
592 | 605 | public static final String EDITOR_SHOW_LINE_FEED= AbstractTextEditor.PREFERENCE_SHOW_LINE_FEED; |
597 | 610 | * <p> |
598 | 611 | * Value is of type <code>Integer</code>. |
599 | 612 | * </p> |
600 | * | |
613 | * | |
601 | 614 | * @since 3.7 |
602 | 615 | */ |
603 | 616 | public static final String EDITOR_WHITESPACE_CHARACTER_ALPHA_VALUE= AbstractTextEditor.PREFERENCE_WHITESPACE_CHARACTER_ALPHA_VALUE; |
705 | 718 | |
706 | 719 | store.setDefault(AbstractDecoratedTextEditorPreferenceConstants.EDITOR_TAB_WIDTH, 4); |
707 | 720 | store.setDefault(AbstractDecoratedTextEditorPreferenceConstants.EDITOR_SPACES_FOR_TABS, false); |
721 | store.setDefault(AbstractDecoratedTextEditorPreferenceConstants.EDITOR_DELETE_SPACES_AS_TABS, false); | |
708 | 722 | |
709 | 723 | store.setDefault(AbstractDecoratedTextEditorPreferenceConstants.EDITOR_UNDO_HISTORY_SIZE, 200); |
710 | 724 |
63 | 63 | |
64 | 64 | /** |
65 | 65 | * Creates a new action for the given text editor. |
66 | * | |
66 | * | |
67 | 67 | * @param editor the text editor |
68 | 68 | * @see TextEditorAction#TextEditorAction(ResourceBundle, String, ITextEditor) |
69 | 69 | * @since 3.5 |
75 | 75 | /** |
76 | 76 | * Creates a new action for the given text editor. The action configures its visual |
77 | 77 | * representation from the given resource bundle. |
78 | * | |
78 | * | |
79 | 79 | * @param bundle the resource bundle |
80 | 80 | * @param prefix a prefix to be prepended to the various resource keys (described in |
81 | 81 | * <code>ResourceAction</code> constructor), or <code>null</code> if none |
58 | 58 | * <p> |
59 | 59 | * This class may be instantiated but is not intended for sub-classing. |
60 | 60 | * </p> |
61 | * | |
61 | * | |
62 | 62 | * @since 2.0, allowed to be subclassed since 3.5 |
63 | 63 | */ |
64 | 64 | public class SelectMarkerRulerAction extends ResourceAction implements IUpdate { |
1 | 1 | Bundle-ManifestVersion: 2 |
2 | 2 | Bundle-Name: %Plugin.name |
3 | 3 | Bundle-SymbolicName: org.eclipse.ui.editors.tests;singleton:=true |
4 | Bundle-Version: 3.11.500.qualifier | |
4 | Bundle-Version: 3.11.600.qualifier | |
5 | 5 | Bundle-Vendor: %Plugin.providerName |
6 | 6 | Bundle-Localization: plugin |
7 | 7 | Export-Package: org.eclipse.ui.editors.tests |
13 | 13 | <parent> |
14 | 14 | <artifactId>tests-pom</artifactId> |
15 | 15 | <groupId>eclipse.platform.text</groupId> |
16 | <version>4.13.0-SNAPSHOT</version> | |
16 | <version>4.14.0-SNAPSHOT</version> | |
17 | 17 | <relativePath>../tests-pom/</relativePath> |
18 | 18 | </parent> |
19 | 19 | <groupId>org.eclipse.ui</groupId> |
20 | 20 | <artifactId>org.eclipse.ui.editors.tests</artifactId> |
21 | <version>3.11.500-SNAPSHOT</version> | |
21 | <version>3.11.600-SNAPSHOT</version> | |
22 | 22 | <packaging>eclipse-test-plugin</packaging> |
23 | 23 | <properties> |
24 | 24 | <testSuite>${project.artifactId}</testSuite> |
0 | 0 | /******************************************************************************* |
1 | * Copyright (c) 2000, 2016 IBM Corporation and others. | |
1 | * Copyright (c) 2000, 2019 IBM Corporation and others. | |
2 | 2 | * |
3 | 3 | * This program and the accompanying materials |
4 | 4 | * are made available under the terms of the Eclipse Public License 2.0 |
33 | 33 | ZoomTest.class, |
34 | 34 | FileDocumentProviderTest.class, |
35 | 35 | TextFileDocumentProviderTest.class, |
36 | StatusEditorTest.class | |
36 | StatusEditorTest.class, | |
37 | LargeFileTest.class | |
37 | 38 | }) |
38 | 39 | public class EditorsTestSuite { |
39 | 40 | // see @SuiteClasses |
0 | /******************************************************************************* | |
1 | * Copyright (c) 2019 Thomas Wolf 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 | package org.eclipse.ui.editors.tests; | |
11 | ||
12 | import static org.junit.Assert.assertTrue; | |
13 | ||
14 | import java.io.BufferedWriter; | |
15 | import java.io.OutputStreamWriter; | |
16 | import java.nio.charset.StandardCharsets; | |
17 | ||
18 | import org.junit.After; | |
19 | import org.junit.Before; | |
20 | import org.junit.Test; | |
21 | ||
22 | import org.eclipse.swt.widgets.Display; | |
23 | ||
24 | import org.eclipse.core.filesystem.EFS; | |
25 | import org.eclipse.core.filesystem.IFileStore; | |
26 | ||
27 | import org.eclipse.core.resources.IFile; | |
28 | import org.eclipse.core.resources.IFolder; | |
29 | import org.eclipse.core.resources.IMarker; | |
30 | import org.eclipse.core.resources.IResource; | |
31 | ||
32 | import org.eclipse.core.filebuffers.tests.ResourceHelper; | |
33 | ||
34 | import org.eclipse.jface.preference.IPreferenceStore; | |
35 | ||
36 | import org.eclipse.ui.IEditorPart; | |
37 | import org.eclipse.ui.IWorkbench; | |
38 | import org.eclipse.ui.IWorkbenchPage; | |
39 | import org.eclipse.ui.PlatformUI; | |
40 | import org.eclipse.ui.ide.IDE; | |
41 | import org.eclipse.ui.internal.editors.text.EditorsPlugin; | |
42 | import org.eclipse.ui.intro.IIntroPart; | |
43 | ||
44 | import org.eclipse.ui.texteditor.AbstractTextEditor; | |
45 | import org.eclipse.ui.texteditor.ITextEditor; | |
46 | ||
47 | /** | |
48 | * Tests opening large files in a text editor. | |
49 | */ | |
50 | public class LargeFileTest { | |
51 | ||
52 | private IFile fLargeFile; | |
53 | ||
54 | private IPreferenceStore preferenceStore; | |
55 | ||
56 | boolean initialWordWrap; | |
57 | ||
58 | @Before | |
59 | public void setUp() throws Exception { | |
60 | IIntroPart intro = PlatformUI.getWorkbench().getIntroManager().getIntro(); | |
61 | if (intro != null) { | |
62 | PlatformUI.getWorkbench().getIntroManager().closeIntro(intro); | |
63 | } | |
64 | IFolder folder = ResourceHelper.createFolder("LargeFileTestProject/test/"); | |
65 | fLargeFile = ResourceHelper.createFile(folder, "large.txt", ""); | |
66 | IFileStore store = EFS.getLocalFileSystem().getStore(fLargeFile.getLocationURI()); | |
67 | try (BufferedWriter writer = new BufferedWriter( | |
68 | new OutputStreamWriter(store.openOutputStream(EFS.NONE, null), StandardCharsets.UTF_8))) { | |
69 | for (int i = 1; i <= 40000; i++) { | |
70 | writer.write("This is line # " + i); | |
71 | writer.newLine(); | |
72 | } | |
73 | } | |
74 | fLargeFile.refreshLocal(IResource.DEPTH_ZERO, null); | |
75 | preferenceStore = EditorsPlugin.getDefault().getPreferenceStore(); | |
76 | initialWordWrap = preferenceStore.getBoolean(AbstractTextEditor.PREFERENCE_WORD_WRAP_ENABLED); | |
77 | } | |
78 | ||
79 | @After | |
80 | public void tearDown() throws Exception { | |
81 | fLargeFile.deleteMarkers(IMarker.BOOKMARK, true, IResource.DEPTH_INFINITE); | |
82 | ResourceHelper.deleteProject("LargeFileTestProject"); | |
83 | fLargeFile= null; | |
84 | preferenceStore.setValue(AbstractTextEditor.PREFERENCE_WORD_WRAP_ENABLED, initialWordWrap); | |
85 | TestUtil.cleanUp(); | |
86 | } | |
87 | ||
88 | @Test | |
89 | public void openLargeFileWithAnnotation() throws Exception { | |
90 | IWorkbench workbench= PlatformUI.getWorkbench(); | |
91 | Display display = workbench.getDisplay(); | |
92 | IWorkbenchPage page= workbench.getActiveWorkbenchWindow().getActivePage(); | |
93 | // Set word-wrap (makes the StyledText have variable line height) | |
94 | preferenceStore.setValue(AbstractTextEditor.PREFERENCE_WORD_WRAP_ENABLED, true); | |
95 | // Let's get an idea how long it takes to open the file at all. Open the | |
96 | // file twice; the first time takes longer. | |
97 | long[] baseline = new long[1]; | |
98 | for (int i = 0; i < 2; i++) { | |
99 | baseline[0] = System.nanoTime(); | |
100 | IEditorPart part = IDE.openEditor(page, fLargeFile); | |
101 | display.asyncExec(() -> { | |
102 | baseline[0] = System.nanoTime() - baseline[0]; | |
103 | }); | |
104 | TestUtil.runEventLoop(); | |
105 | assertTrue("Expected a text editor", part instanceof ITextEditor); | |
106 | page.closeEditor(part, false); | |
107 | TestUtil.runEventLoop(); | |
108 | } | |
109 | // Create a marker on the file | |
110 | IMarker marker = fLargeFile.createMarker(IMarker.BOOKMARK); | |
111 | marker.setAttribute(IMarker.LOCATION, "line 1"); | |
112 | marker.setAttribute(IMarker.MESSAGE, "Just a test marker"); | |
113 | marker.setAttribute(IMarker.LINE_NUMBER, 1); | |
114 | marker.setAttribute(IMarker.CHAR_START, 8); | |
115 | marker.setAttribute(IMarker.CHAR_END, 12); | |
116 | marker.setAttribute(IMarker.USER_EDITABLE, false); | |
117 | TestUtil.runEventLoop(); | |
118 | // Open it again | |
119 | long[] withMarker = { System.nanoTime() }; | |
120 | IEditorPart part = IDE.openEditor(page, fLargeFile); | |
121 | display.asyncExec(() -> { | |
122 | withMarker[0] = System.nanoTime() - withMarker[0]; | |
123 | }); | |
124 | TestUtil.runEventLoop(); | |
125 | assertTrue("Expected a text editor", part instanceof ITextEditor); | |
126 | page.closeEditor(part, false); | |
127 | TestUtil.runEventLoop(); | |
128 | // Be generous here; all this timing is approximate. Fail if the attempt | |
129 | // with the marker takes more than twice as long. If the OverviewRuler | |
130 | // is badly implemented, opening with the marker will take much longer. | |
131 | assertTrue("Opening large file took too long: " + (withMarker[0] / 1000000.0f) + "ms with marker vs. " | |
132 | + (baseline[0] / 1000000.0f) + "ms without", | |
133 | withMarker[0] / 2 <= baseline[0]); | |
134 | } | |
135 | } |
+6
-6
25 | 25 | |
26 | 26 | /** |
27 | 27 | * The example java editor plug-in class. |
28 | * | |
28 | * | |
29 | 29 | * @since 3.0 |
30 | 30 | */ |
31 | 31 | public class JavaEditorExamplePlugin extends AbstractUIPlugin { |
53 | 53 | |
54 | 54 | /** |
55 | 55 | * Returns the default plug-in instance. |
56 | * | |
56 | * | |
57 | 57 | * @return the default plug-in instance |
58 | 58 | */ |
59 | 59 | public static JavaEditorExamplePlugin getDefault() { |
62 | 62 | |
63 | 63 | /** |
64 | 64 | * Return a scanner for creating Java partitions. |
65 | * | |
65 | * | |
66 | 66 | * @return a scanner for creating Java partitions |
67 | 67 | */ |
68 | 68 | public JavaPartitionScanner getJavaPartitionScanner() { |
73 | 73 | |
74 | 74 | /** |
75 | 75 | * Returns the singleton Java code scanner. |
76 | * | |
76 | * | |
77 | 77 | * @return the singleton Java code scanner |
78 | 78 | */ |
79 | 79 | public RuleBasedScanner getJavaCodeScanner() { |
84 | 84 | |
85 | 85 | /** |
86 | 86 | * Returns the singleton Java color provider. |
87 | * | |
87 | * | |
88 | 88 | * @return the singleton Java color provider |
89 | 89 | */ |
90 | 90 | public JavaColorProvider getJavaColorProvider() { |
95 | 95 | |
96 | 96 | /** |
97 | 97 | * Returns the singleton Javadoc scanner. |
98 | * | |
98 | * | |
99 | 99 | * @return the singleton Javadoc scanner |
100 | 100 | */ |
101 | 101 | public RuleBasedScanner getJavaDocScanner() { |
+1
-1
29 | 29 | |
30 | 30 | /** |
31 | 31 | * {@inheritDoc} |
32 | * | |
32 | * | |
33 | 33 | * @deprecated As of 3.4, replaced by |
34 | 34 | * {@link ITextHoverExtension2#getHoverInfo2(ITextViewer, IRegion)} |
35 | 35 | */ |
+1
-1
59 | 59 | */ |
60 | 60 | public JavaDocScanner(JavaColorProvider provider) { |
61 | 61 | super(); |
62 | ||
62 | ||
63 | 63 | setDefaultReturnToken(new Token(new TextAttribute(provider.getColor(JavaColorProvider.JAVADOC_DEFAULT)))); |
64 | 64 | |
65 | 65 | IToken keyword= new Token(new TextAttribute(provider.getColor(JavaColorProvider.JAVADOC_KEYWORD))); |
1 | 1 | Bundle-ManifestVersion: 2 |
2 | 2 | Bundle-Name: %pluginName |
3 | 3 | Bundle-SymbolicName: org.eclipse.ui.examples.javaeditor; singleton:=true |
4 | Bundle-Version: 3.2.400.qualifier | |
4 | Bundle-Version: 3.2.500.qualifier | |
5 | 5 | Bundle-Activator: org.eclipse.ui.examples.javaeditor.JavaEditorExamplePlugin |
6 | 6 | Bundle-Vendor: %providerName |
7 | 7 | Bundle-Localization: plugin |
0 | <?xml version="1.0" encoding="UTF-8"?> | |
1 | <!-- | |
2 | Copyright (c) 2012, 2013 Eclipse Foundation and others. | |
3 | All rights reserved. This program and the accompanying materials | |
4 | are made available under the terms of the Eclipse Distribution License v1.0 | |
5 | which accompanies this distribution, and is available at | |
6 | http://www.eclipse.org/org/documents/edl-v10.php | |
7 | ||
8 | Contributors: | |
9 | Igor Fedorenko - initial implementation | |
10 | --> | |
11 | <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | |
12 | <modelVersion>4.0.0</modelVersion> | |
13 | <parent> | |
14 | <artifactId>eclipse.platform.text</artifactId> | |
15 | <groupId>eclipse.platform.text</groupId> | |
16 | <version>4.13.0-SNAPSHOT</version> | |
17 | </parent> | |
18 | <groupId>org.eclipse.ui</groupId> | |
19 | <artifactId>org.eclipse.ui.examples.javaeditor</artifactId> | |
20 | <version>3.2.400-SNAPSHOT</version> | |
21 | <packaging>eclipse-plugin</packaging> | |
22 | </project> |
1 | 1 | Bundle-ManifestVersion: 2 |
2 | 2 | Bundle-Name: %Bundle-Name |
3 | 3 | Bundle-SymbolicName: org.eclipse.ui.genericeditor;singleton:=true |
4 | Bundle-Version: 1.1.500.qualifier | |
4 | Bundle-Version: 1.1.600.qualifier | |
5 | 5 | Bundle-Vendor: %Bundle-Vendor |
6 | 6 | Bundle-RequiredExecutionEnvironment: JavaSE-1.8 |
7 | 7 | Require-Bundle: org.eclipse.ui.workbench.texteditor;bundle-version="3.10.0", |
18 | 18 | plugin.properties,\ |
19 | 19 | about.html,\ |
20 | 20 | icons/,\ |
21 | resources/ | |
21 | resources/,\ | |
22 | schema/ | |
22 | 23 | |
23 | 24 | src.includes = about.html,\ |
24 | 25 | schema/ |
24 | 24 | <extension-point id="foldingReconcilers" name="%ExtPoint.foldingReconcilers" schema="schema/foldingReconcilers.exsd"/> |
25 | 25 | <extension-point id="characterPairMatchers" name="%ExtPoint.characterPairMatchers" schema="schema/characterPairMatchers.exsd"/> |
26 | 26 | <extension-point id="icons" name="%ExtPoint.iconProviders" schema="schema/icons.exsd"/> |
27 | <extension-point id="quickAssistProcessors" name="%ExtPoint.quickAssistProcessors" schema="schema/quickAssistProcessors.exsd"/> | |
27 | 28 | <extension |
28 | 29 | point="org.eclipse.ui.editors"> |
29 | 30 | <editor |
229 | 230 | class="org.eclipse.ui.internal.genericeditor.GenericEditorWithIconAssociationOverride" |
230 | 231 | id="org.eclipse.ui.internal.genericeditor.GenericEditorAssociationOverride"/> |
231 | 232 | </extension> |
233 | <extension | |
234 | point="org.eclipse.ui.genericeditor.reconcilers"> | |
235 | <reconciler | |
236 | class="org.eclipse.jface.text.codemining.CodeMiningReconciler" | |
237 | contentType="org.eclipse.core.runtime.text"> | |
238 | </reconciler> | |
239 | </extension> | |
232 | 240 | </plugin> |
0 | <?xml version="1.0" encoding="UTF-8"?> | |
1 | <!-- | |
2 | Copyright (c) 2016 Red Hat Inc. and others. | |
3 | All rights reserved. This program and the accompanying materials | |
4 | are made available under the terms of the Eclipse Distribution License v1.0 | |
5 | which accompanies this distribution, and is available at | |
6 | http://www.eclipse.org/org/documents/edl-v10.php | |
7 | ||
8 | Contributors: | |
9 | Mickael Istria (Red Hat Inc.) - initial implementation | |
10 | --> | |
11 | <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | |
12 | <modelVersion>4.0.0</modelVersion> | |
13 | <parent> | |
14 | <artifactId>eclipse.platform.text</artifactId> | |
15 | <groupId>eclipse.platform.text</groupId> | |
16 | <version>4.13.0-SNAPSHOT</version> | |
17 | </parent> | |
18 | <groupId>org.eclipse.ui</groupId> | |
19 | <artifactId>org.eclipse.ui.genericeditor</artifactId> | |
20 | <version>1.1.500-SNAPSHOT</version> | |
21 | <packaging>eclipse-plugin</packaging> | |
22 | </project> |
0 | <?xml version='1.0' encoding='UTF-8'?> | |
1 | <!-- Schema file written by PDE --> | |
2 | <schema targetNamespace="org.eclipse.ui.genericeditor" xmlns="http://www.w3.org/2001/XMLSchema"> | |
3 | <annotation> | |
4 | <appinfo> | |
5 | <meta.schema plugin="org.eclipse.ui.genericeditor" id="characterPairMatchers" name="Character pair matchers"/> | |
6 | </appinfo> | |
7 | <documentation> | |
8 | This extension point is used to contribute character pair matchers for controlling the matching brackets on a file with a given content type. | |
9 | </documentation> | |
10 | </annotation> | |
11 | ||
12 | <include schemaLocation="schema://org.eclipse.core.expressions/schema/expressionLanguage.exsd"/> | |
13 | ||
14 | <element name="extension"> | |
15 | <annotation> | |
16 | <appinfo> | |
17 | <meta.element /> | |
18 | </appinfo> | |
19 | </annotation> | |
20 | <complexType> | |
21 | <sequence minOccurs="1" maxOccurs="unbounded"> | |
22 | <element ref="characterPairMatcher"/> | |
23 | </sequence> | |
24 | <attribute name="point" type="string" use="required"> | |
25 | <annotation> | |
26 | <documentation> | |
27 | a fully qualified identifier of the target extension point | |
28 | </documentation> | |
29 | </annotation> | |
30 | </attribute> | |
31 | <attribute name="id" type="string"> | |
32 | <annotation> | |
33 | <documentation> | |
34 | an optional identifier of the extension instance | |
35 | </documentation> | |
36 | </annotation> | |
37 | </attribute> | |
38 | <attribute name="name" type="string"> | |
39 | <annotation> | |
40 | <documentation> | |
41 | an optional name of the extension instance | |
42 | </documentation> | |
43 | <appinfo> | |
44 | <meta.attribute translatable="true"/> | |
45 | </appinfo> | |
46 | </annotation> | |
47 | </attribute> | |
48 | </complexType> | |
49 | </element> | |
50 | ||
51 | <element name="characterPairMatcher"> | |
52 | <complexType> | |
53 | <sequence> | |
54 | <element ref="enabledWhen" minOccurs="0" maxOccurs="1"/> | |
55 | </sequence> | |
56 | <attribute name="class" type="string" use="required"> | |
57 | <annotation> | |
58 | <documentation> | |
59 | The fully qualified class name implementing the interface <code>org.eclipse.jface.text.source.ICharacterPairMatcher</code> | |
60 | </documentation> | |
61 | <appinfo> | |
62 | <meta.attribute kind="java" basedOn=":org.eclipse.jface.text.source.ICharacterPairMatcher"/> | |
63 | </appinfo> | |
64 | </annotation> | |
65 | </attribute> | |
66 | <attribute name="contentType" type="string" use="required"> | |
67 | <annotation> | |
68 | <documentation> | |
69 | The target content-type for this extension. Content-types are defined as extension to the org.eclipse.core.contenttype.contentTypes extension point. | |
70 | </documentation> | |
71 | <appinfo> | |
72 | <meta.attribute kind="identifier" basedOn="org.eclipse.core.contenttype.contentTypes/content-type/@id"/> | |
73 | </appinfo> | |
74 | </annotation> | |
75 | </attribute> | |
76 | </complexType> | |
77 | </element> | |
78 | ||
79 | <element name="enabledWhen"> | |
80 | <annotation> | |
81 | <documentation> | |
82 | 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: | |
83 | ||
84 | * <with variable="viewer"/> : use it if your expression requires the viewer. | |
85 | * <with variable="document"/> : use it if your expression requires the document. | |
86 | * <with variable="editor"/> : use it if your expression requires the editor (deprecated, not always set). | |
87 | * <with variable="editorInput"/> : use it if your expression requires the editor input (deprecated, not always set). | |
88 | </documentation> | |
89 | </annotation> | |
90 | <complexType> | |
91 | <choice minOccurs="0" maxOccurs="1"> | |
92 | <element ref="not"/> | |
93 | <element ref="or"/> | |
94 | <element ref="and"/> | |
95 | <element ref="instanceof"/> | |
96 | <element ref="test"/> | |
97 | <element ref="systemTest"/> | |
98 | <element ref="equals"/> | |
99 | <element ref="count"/> | |
100 | <element ref="with"/> | |
101 | <element ref="resolve"/> | |
102 | <element ref="adapt"/> | |
103 | <element ref="iterate"/> | |
104 | <element ref="reference"/> | |
105 | </choice> | |
106 | </complexType> | |
107 | </element> | |
108 | ||
109 | <annotation> | |
110 | <appinfo> | |
111 | <meta.section type="since"/> | |
112 | </appinfo> | |
113 | <documentation> | |
114 | 1.2 | |
115 | </documentation> | |
116 | </annotation> | |
117 | ||
118 | <annotation> | |
119 | <appinfo> | |
120 | <meta.section type="examples"/> | |
121 | </appinfo> | |
122 | <documentation> | |
123 | Below is an example of how to use the character pair matchers extension point: | |
124 | ||
125 | <pre> | |
126 | <extension point="org.eclipse.ui.genericeditor.characterPairMatchers"> | |
127 | <characterPairMatcher | |
128 | class="org.eclipse.ui.genericeditor.examples.TargetDefinitionCharacterPairMatchers" | |
129 | contentType="org.eclipse.pde.targetFile"> | |
130 | <enabledWhen> | |
131 | <with variable="editor"> | |
132 | <test property="org.eclipse.ui.genericeditor.examples.TargetDefinitionPropertyTester"> | |
133 | </test> | |
134 | </with> | |
135 | </enabledWhen> | |
136 | </characterPairMatcher> | |
137 | </extension> | |
138 | </pre> | |
139 | </documentation> | |
140 | </annotation> | |
141 | ||
142 | ||
143 | ||
144 | <annotation> | |
145 | <appinfo> | |
146 | <meta.section type="copyright"/> | |
147 | </appinfo> | |
148 | <documentation> | |
149 | Copyright (c) 2018 Angelo ZERR and others | |
150 | All rights reserved. This program and the accompanying materials are made available under the terms of the Eclipse Public License v2.0 which accompanies this distribution, and is available at <a href="http://www.eclipse.org/legal/epl-v20.html">http://www.eclipse.org/legal/epl-v20.html</a> | |
151 | </documentation> | |
152 | </annotation> | |
153 | ||
154 | </schema> | |
0 | <?xml version='1.0' encoding='UTF-8'?> | |
1 | <!-- Schema file written by PDE --> | |
2 | <schema targetNamespace="org.eclipse.ui.genericeditor" xmlns="http://www.w3.org/2001/XMLSchema"> | |
3 | <annotation> | |
4 | <appinfo> | |
5 | <meta.schema plugin="org.eclipse.ui.genericeditor" id="characterPairMatchers" name="Character pair matchers"/> | |
6 | </appinfo> | |
7 | <documentation> | |
8 | This extension point is used to contribute character pair matchers for controlling the matching brackets on a file with a given content type. | |
9 | </documentation> | |
10 | </annotation> | |
11 | ||
12 | <include schemaLocation="schema://org.eclipse.core.expressions/schema/expressionLanguage.exsd"/> | |
13 | ||
14 | <element name="extension"> | |
15 | <annotation> | |
16 | <appinfo> | |
17 | <meta.element /> | |
18 | </appinfo> | |
19 | </annotation> | |
20 | <complexType> | |
21 | <sequence minOccurs="1" maxOccurs="unbounded"> | |
22 | <element ref="characterPairMatcher"/> | |
23 | </sequence> | |
24 | <attribute name="point" type="string" use="required"> | |
25 | <annotation> | |
26 | <documentation> | |
27 | a fully qualified identifier of the target extension point | |
28 | </documentation> | |
29 | </annotation> | |
30 | </attribute> | |
31 | <attribute name="id" type="string"> | |
32 | <annotation> | |
33 | <documentation> | |
34 | an optional identifier of the extension instance | |
35 | </documentation> | |
36 | </annotation> | |
37 | </attribute> | |
38 | <attribute name="name" type="string"> | |
39 | <annotation> | |
40 | <documentation> | |
41 | an optional name of the extension instance | |
42 | </documentation> | |
43 | <appinfo> | |
44 | <meta.attribute translatable="true"/> | |
45 | </appinfo> | |
46 | </annotation> | |
47 | </attribute> | |
48 | </complexType> | |
49 | </element> | |
50 | ||
51 | <element name="characterPairMatcher"> | |
52 | <complexType> | |
53 | <sequence> | |
54 | <element ref="enabledWhen" minOccurs="0" maxOccurs="1"/> | |
55 | </sequence> | |
56 | <attribute name="class" type="string" use="required"> | |
57 | <annotation> | |
58 | <documentation> | |
59 | The fully qualified class name implementing the interface <code>org.eclipse.jface.text.source.ICharacterPairMatcher</code> | |
60 | </documentation> | |
61 | <appinfo> | |
62 | <meta.attribute kind="java" basedOn=":org.eclipse.jface.text.source.ICharacterPairMatcher"/> | |
63 | </appinfo> | |
64 | </annotation> | |
65 | </attribute> | |
66 | <attribute name="contentType" type="string" use="required"> | |
67 | <annotation> | |
68 | <documentation> | |
69 | The target content-type for this extension. Content-types are defined as extension to the org.eclipse.core.contenttype.contentTypes extension point. | |
70 | </documentation> | |
71 | <appinfo> | |
72 | <meta.attribute kind="identifier" basedOn="org.eclipse.core.contenttype.contentTypes/content-type/@id"/> | |
73 | </appinfo> | |
74 | </annotation> | |
75 | </attribute> | |
76 | </complexType> | |
77 | </element> | |
78 | ||
79 | <element name="enabledWhen"> | |
80 | <annotation> | |
81 | <documentation> | |
82 | 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: | |
83 | ||
84 | * <with variable="viewer"/> : use it if your expression requires the viewer. | |
85 | * <with variable="document"/> : use it if your expression requires the document. | |
86 | * <with variable="editor"/> : use it if your expression requires the editor (deprecated, not always set). | |
87 | * <with variable="editorInput"/> : use it if your expression requires the editor input (deprecated, not always set). | |
88 | </documentation> | |
89 | </annotation> | |
90 | <complexType> | |
91 | <choice minOccurs="0" maxOccurs="1"> | |
92 | <element ref="not"/> | |
93 | <element ref="or"/> | |
94 | <element ref="and"/> | |
95 | <element ref="instanceof"/> | |
96 | <element ref="test"/> | |
97 | <element ref="systemTest"/> | |
98 | <element ref="equals"/> | |
99 | <element ref="count"/> | |
100 | <element ref="with"/> | |
101 | <element ref="resolve"/> | |
102 | <element ref="adapt"/> | |
103 | <element ref="iterate"/> | |
104 | <element ref="reference"/> | |
105 | </choice> | |
106 | </complexType> | |
107 | </element> | |
108 | ||
109 | <annotation> | |
110 | <appinfo> | |
111 | <meta.section type="since"/> | |
112 | </appinfo> | |
113 | <documentation> | |
114 | 1.2 | |
115 | </documentation> | |
116 | </annotation> | |
117 | ||
118 | <annotation> | |
119 | <appinfo> | |
120 | <meta.section type="examples"/> | |
121 | </appinfo> | |
122 | <documentation> | |
123 | Below is an example of how to use the character pair matchers extension point: | |
124 | ||
125 | <pre> | |
126 | <extension point="org.eclipse.ui.genericeditor.characterPairMatchers"> | |
127 | <characterPairMatcher | |
128 | class="org.eclipse.ui.genericeditor.examples.TargetDefinitionCharacterPairMatchers" | |
129 | contentType="org.eclipse.pde.targetFile"> | |
130 | <enabledWhen> | |
131 | <with variable="editor"> | |
132 | <test property="org.eclipse.ui.genericeditor.examples.TargetDefinitionPropertyTester"> | |
133 | </test> | |
134 | </with> | |
135 | </enabledWhen> | |
136 | </characterPairMatcher> | |
137 | </extension> | |
138 | </pre> | |
139 | </documentation> | |
140 | </annotation> | |
141 | ||
142 | ||
143 | ||
144 | <annotation> | |
145 | <appinfo> | |
146 | <meta.section type="copyright"/> | |
147 | </appinfo> | |
148 | <documentation> | |
149 | Copyright (c) 2018 Angelo ZERR and others | |
150 | All rights reserved. This program and the accompanying materials are made available under the terms of the Eclipse Public License v2.0 which accompanies this distribution, and is available at <a href="http://www.eclipse.org/legal/epl-v20.html">http://www.eclipse.org/legal/epl-v20.html</a> | |
151 | </documentation> | |
152 | </annotation> | |
153 | ||
154 | </schema> |
0 | <?xml version='1.0' encoding='UTF-8'?> | |
1 | <!-- Schema file written by PDE --> | |
2 | <schema targetNamespace="org.eclipse.ui.genericeditor" xmlns="http://www.w3.org/2001/XMLSchema"> | |
3 | <annotation> | |
4 | <appinfo> | |
5 | <meta.schema plugin="org.eclipse.ui.genericeditor" id="foldingReconcilers" name="Folding reconcilers"/> | |
6 | </appinfo> | |
7 | <documentation> | |
8 | This extension point is used to contribute folding reconcilers for controlling the folding on a file with a given content type. | |
9 | </documentation> | |
10 | </annotation> | |
11 | ||
12 | <include schemaLocation="schema://org.eclipse.core.expressions/schema/expressionLanguage.exsd"/> | |
13 | ||
14 | <element name="extension"> | |
15 | <annotation> | |
16 | <appinfo> | |
17 | <meta.element /> | |
18 | </appinfo> | |
19 | </annotation> | |
20 | <complexType> | |
21 | <sequence minOccurs="1" maxOccurs="unbounded"> | |
22 | <element ref="foldingReconciler"/> | |
23 | </sequence> | |
24 | <attribute name="point" type="string" use="required"> | |
25 | <annotation> | |
26 | <documentation> | |
27 | a fully qualified identifier of the target extension point | |
28 | </documentation> | |
29 | </annotation> | |
30 | </attribute> | |
31 | <attribute name="id" type="string"> | |
32 | <annotation> | |
33 | <documentation> | |
34 | an optional identifier of the extension instance | |
35 | </documentation> | |
36 | </annotation> | |
37 | </attribute> | |
38 | <attribute name="name" type="string"> | |
39 | <annotation> | |
40 | <documentation> | |
41 | an optional name of the extension instance | |
42 | </documentation> | |
43 | <appinfo> | |
44 | <meta.attribute translatable="true"/> | |
45 | </appinfo> | |
46 | </annotation> | |
47 | </attribute> | |
48 | </complexType> | |
49 | </element> | |
50 | ||
51 | <element name="foldingReconciler"> | |
52 | <complexType> | |
53 | <sequence> | |
54 | <element ref="enabledWhen" minOccurs="0" maxOccurs="1"/> | |
55 | </sequence> | |
56 | <attribute name="class" type="string" use="required"> | |
57 | <annotation> | |
58 | <documentation> | |
59 | The fully qualified class name implementing the interface <code>org.eclipse.jface.text.reconciler.IReconciler</code> | |
60 | To manipulate folding, the implementation reconciler needs to use ProjectionAnnotation and viewer.getProjectionModel(). You can find a sample in | |
61 | org.eclipse.ui.internal.genericeditor.folding.DefaultFoldingReconciler. | |
62 | </documentation> | |
63 | <appinfo> | |
64 | <meta.attribute kind="java" basedOn=":org.eclipse.jface.text.reconciler.IReconciler"/> | |
65 | </appinfo> | |
66 | </annotation> | |
67 | </attribute> | |
68 | <attribute name="contentType" type="string" use="required"> | |
69 | <annotation> | |
70 | <documentation> | |
71 | The target content-type for this extension. Content-types are defined as extension to the org.eclipse.core.contenttype.contentTypes extension point. | |
72 | </documentation> | |
73 | <appinfo> | |
74 | <meta.attribute kind="identifier" basedOn="org.eclipse.core.contenttype.contentTypes/content-type/@id"/> | |
75 | </appinfo> | |
76 | </annotation> | |
77 | </attribute> | |
78 | </complexType> | |
79 | </element> | |
80 | ||
81 | <element name="enabledWhen"> | |
82 | <annotation> | |
83 | <documentation> | |
84 | 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: | |
85 | ||
86 | * <with variable="viewer"/> : use it if your expression requires the viewer. | |
87 | * <with variable="document"/> : use it if your expression requires the document. | |
88 | * <with variable="editor"/> : use it if your expression requires the editor (deprecated, not always set). | |
89 | * <with variable="editorInput"/> : use it if your expression requires the editor input (deprecated, not always set). | |
90 | </documentation> | |
91 | </annotation> | |
92 | <complexType> | |
93 | <choice minOccurs="0" maxOccurs="1"> | |
94 | <element ref="not"/> | |
95 | <element ref="or"/> | |
96 | <element ref="and"/> | |
97 | <element ref="instanceof"/> | |
98 | <element ref="test"/> | |
99 | <element ref="systemTest"/> | |
100 | <element ref="equals"/> | |
101 | <element ref="count"/> | |
102 | <element ref="with"/> | |
103 | <element ref="resolve"/> | |
104 | <element ref="adapt"/> | |
105 | <element ref="iterate"/> | |
106 | <element ref="reference"/> | |
107 | </choice> | |
108 | </complexType> | |
109 | </element> | |
110 | ||
111 | <annotation> | |
112 | <appinfo> | |
113 | <meta.section type="since"/> | |
114 | </appinfo> | |
115 | <documentation> | |
116 | 1.1 | |
117 | </documentation> | |
118 | </annotation> | |
119 | ||
120 | <annotation> | |
121 | <appinfo> | |
122 | <meta.section type="examples"/> | |
123 | </appinfo> | |
124 | <documentation> | |
125 | Below is an example of how to use the Folding Reconciler extension point: | |
126 | <pre> | |
127 | <extension point="org.eclipse.ui.genericeditor.foldingReconcilers"> | |
128 | <foldingReconciler | |
129 | class="org.eclipse.ui.genericeditor.examples.TargetDefinitionFoldingReconciler" | |
130 | contentType="org.eclipse.pde.targetFile"> | |
131 | <enabledWhen> | |
132 | <with variable="editor"> | |
133 | <test property="org.eclipse.ui.genericeditor.examples.TargetDefinitionPropertyTester"> | |
134 | </test> | |
135 | </with> | |
136 | </enabledWhen> | |
137 | </foldingReconciler> | |
138 | </extension> | |
139 | </pre> | |
140 | </documentation> | |
141 | </annotation> | |
142 | ||
143 | ||
144 | ||
145 | <annotation> | |
146 | <appinfo> | |
147 | <meta.section type="copyright"/> | |
148 | </appinfo> | |
149 | <documentation> | |
150 | Copyright (c) 2017 Red Hat Inc. and others | |
0 | <?xml version='1.0' encoding='UTF-8'?> | |
1 | <!-- Schema file written by PDE --> | |
2 | <schema targetNamespace="org.eclipse.ui.genericeditor" xmlns="http://www.w3.org/2001/XMLSchema"> | |
3 | <annotation> | |
4 | <appinfo> | |
5 | <meta.schema plugin="org.eclipse.ui.genericeditor" id="foldingReconcilers" name="Folding reconcilers"/> | |
6 | </appinfo> | |
7 | <documentation> | |
8 | This extension point is used to contribute folding reconcilers for controlling the folding on a file with a given content type. | |
9 | </documentation> | |
10 | </annotation> | |
11 | ||
12 | <include schemaLocation="schema://org.eclipse.core.expressions/schema/expressionLanguage.exsd"/> | |
13 | ||
14 | <element name="extension"> | |
15 | <annotation> | |
16 | <appinfo> | |
17 | <meta.element /> | |
18 | </appinfo> | |
19 | </annotation> | |
20 | <complexType> | |
21 | <sequence minOccurs="1" maxOccurs="unbounded"> | |
22 | <element ref="foldingReconciler"/> | |
23 | </sequence> | |
24 | <attribute name="point" type="string" use="required"> | |
25 | <annotation> | |
26 | <documentation> | |
27 | a fully qualified identifier of the target extension point | |
28 | </documentation> | |
29 | </annotation> | |
30 | </attribute> | |
31 | <attribute name="id" type="string"> | |
32 | <annotation> | |
33 | <documentation> | |
34 | an optional identifier of the extension instance | |
35 | </documentation> | |
36 | </annotation> | |
37 | </attribute> | |
38 | <attribute name="name" type="string"> | |
39 | <annotation> | |
40 | <documentation> | |
41 | an optional name of the extension instance | |
42 | </documentation> | |
43 | <appinfo> | |
44 | <meta.attribute translatable="true"/> | |
45 | </appinfo> | |
46 | </annotation> | |
47 | </attribute> | |
48 | </complexType> | |
49 | </element> | |
50 | ||
51 | <element name="foldingReconciler"> | |
52 | <complexType> | |
53 | <sequence> | |
54 | <element ref="enabledWhen" minOccurs="0" maxOccurs="1"/> | |
55 | </sequence> | |
56 | <attribute name="class" type="string" use="required"> | |
57 | <annotation> | |
58 | <documentation> | |
59 | The fully qualified class name implementing the interface <code>org.eclipse.jface.text.reconciler.IReconciler</code> | |
60 | To manipulate folding, the implementation reconciler needs to use ProjectionAnnotation and viewer.getProjectionModel(). You can find a sample in | |
61 | org.eclipse.ui.internal.genericeditor.folding.DefaultFoldingReconciler. | |
62 | </documentation> | |
63 | <appinfo> | |
64 | <meta.attribute kind="java" basedOn=":org.eclipse.jface.text.reconciler.IReconciler"/> | |
65 | </appinfo> | |
66 | </annotation> | |
67 | </attribute> | |
68 | <attribute name="contentType" type="string" use="required"> | |
69 | <annotation> | |
70 | <documentation> | |
71 | The target content-type for this extension. Content-types are defined as extension to the org.eclipse.core.contenttype.contentTypes extension point. | |
72 | </documentation> | |
73 | <appinfo> | |
74 | <meta.attribute kind="identifier" basedOn="org.eclipse.core.contenttype.contentTypes/content-type/@id"/> | |
75 | </appinfo> | |
76 | </annotation> | |
77 | </attribute> | |
78 | </complexType> | |
79 | </element> | |
80 | ||
81 | <element name="enabledWhen"> | |
82 | <annotation> | |
83 | <documentation> | |
84 | 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: | |
85 | ||
86 | * <with variable="viewer"/> : use it if your expression requires the viewer. | |
87 | * <with variable="document"/> : use it if your expression requires the document. | |
88 | * <with variable="editor"/> : use it if your expression requires the editor (deprecated, not always set). | |
89 | * <with variable="editorInput"/> : use it if your expression requires the editor input (deprecated, not always set). | |
90 | </documentation> | |
91 | </annotation> | |
92 | <complexType> | |
93 | <choice minOccurs="0" maxOccurs="1"> | |
94 | <element ref="not"/> | |
95 | <element ref="or"/> | |
96 | <element ref="and"/> | |
97 | <element ref="instanceof"/> | |
98 | <element ref="test"/> | |
99 | <element ref="systemTest"/> | |
100 | <element ref="equals"/> | |
101 | <element ref="count"/> | |
102 | <element ref="with"/> | |
103 | <element ref="resolve"/> | |
104 | <element ref="adapt"/> | |
105 | <element ref="iterate"/> | |
106 | <element ref="reference"/> | |
107 | </choice> | |
108 | </complexType> | |
109 | </element> | |
110 | ||
111 | <annotation> | |
112 | <appinfo> | |
113 | <meta.section type="since"/> | |
114 | </appinfo> | |
115 | <documentation> | |
116 | 1.1 | |
117 | </documentation> | |
118 | </annotation> | |
119 | ||
120 | <annotation> | |
121 | <appinfo> | |
122 | <meta.section type="examples"/> | |
123 | </appinfo> | |
124 | <documentation> | |
125 | Below is an example of how to use the Folding Reconciler extension point: | |
126 | <pre> | |
127 | <extension point="org.eclipse.ui.genericeditor.foldingReconcilers"> | |
128 | <foldingReconciler | |
129 | class="org.eclipse.ui.genericeditor.examples.TargetDefinitionFoldingReconciler" | |
130 | contentType="org.eclipse.pde.targetFile"> | |
131 | <enabledWhen> | |
132 | <with variable="editor"> | |
133 | <test property="org.eclipse.ui.genericeditor.examples.TargetDefinitionPropertyTester"> | |
134 | </test> | |
135 | </with> | |
136 | </enabledWhen> | |
137 | </foldingReconciler> | |
138 | </extension> | |
139 | </pre> | |
140 | </documentation> | |
141 | </annotation> | |
142 | ||
143 | ||
144 | ||
145 | <annotation> | |
146 | <appinfo> | |
147 | <meta.section type="copyright"/> | |
148 | </appinfo> | |
149 | <documentation> | |
150 | Copyright (c) 2017 Red Hat Inc. and others | |
151 | 151 | |
152 | 152 | This program and the accompanying materials are made available under the terms of the Eclipse Public License 2.0 which accompanies this distribution, and is available at <a href="https://www.eclipse.org/legal/epl-2.0">https://www.eclipse.org/legal/epl-v20.html</a>/ |
153 | 153 | |
154 | SPDX-License-Identifier: EPL-2.0 | |
155 | </documentation> | |
156 | </annotation> | |
157 | ||
158 | </schema> | |
154 | SPDX-License-Identifier: EPL-2.0 | |
155 | </documentation> | |
156 | </annotation> | |
157 | ||
158 | </schema> |
0 | <?xml version='1.0' encoding='UTF-8'?> | |
1 | <!-- Schema file written by PDE --> | |
2 | <schema targetNamespace="org.eclipse.ui.genericeditor" xmlns="http://www.w3.org/2001/XMLSchema"> | |
3 | <annotation> | |
4 | <appinfo> | |
5 | <meta.schema plugin="org.eclipse.ui.genericeditor" id="icons" name="GenericEditorIcons"/> | |
6 | </appinfo> | |
7 | <documentation> | |
8 | The icons extension point provides a way of linking different types of icons to a particular content type. | |
9 | </documentation> | |
10 | </annotation> | |
11 | ||
12 | <element name="extension"> | |
13 | <annotation> | |
14 | <appinfo> | |
15 | <meta.element /> | |
16 | </appinfo> | |
17 | </annotation> | |
18 | <complexType> | |
19 | <sequence> | |
20 | <element ref="icon" minOccurs="0" maxOccurs="unbounded"/> | |
21 | </sequence> | |
22 | <attribute name="point" type="string" use="required"> | |
23 | <annotation> | |
24 | <documentation> | |
25 | ||
26 | </documentation> | |
27 | </annotation> | |
28 | </attribute> | |
29 | <attribute name="id" type="string"> | |
30 | <annotation> | |
31 | <documentation> | |
32 | ||
33 | </documentation> | |
34 | </annotation> | |
35 | </attribute> | |
36 | <attribute name="name" type="string"> | |
37 | <annotation> | |
38 | <documentation> | |
39 | ||
40 | </documentation> | |
41 | <appinfo> | |
42 | <meta.attribute translatable="true"/> | |
43 | </appinfo> | |
44 | </annotation> | |
45 | </attribute> | |
46 | </complexType> | |
47 | </element> | |
48 | ||
49 | <element name="icon"> | |
50 | <annotation> | |
51 | <appinfo> | |
52 | <meta.element labelAttribute="contentType"/> | |
53 | </appinfo> | |
54 | <documentation> | |
55 | The icon to associate with a particular content type. | |
56 | </documentation> | |
57 | </annotation> | |
58 | <complexType> | |
59 | <attribute name="contentType" type="string" use="required"> | |
60 | <annotation> | |
61 | <documentation> | |
62 | The identifier of the content type with which the icons should be associated. | |
63 | </documentation> | |
64 | <appinfo> | |
65 | <meta.attribute kind="identifier" basedOn="org.eclipse.core.contenttype.contentTypes/content-type/@id"/> | |
66 | </appinfo> | |
67 | </annotation> | |
68 | </attribute> | |
69 | <attribute name="icon" type="string" use="required"> | |
70 | <annotation> | |
71 | <documentation> | |
72 | The path to the icon which should be used. | |
73 | </documentation> | |
74 | <appinfo> | |
75 | <meta.attribute kind="resource"/> | |
76 | </appinfo> | |
77 | </annotation> | |
78 | </attribute> | |
79 | </complexType> | |
80 | </element> | |
81 | ||
82 | <annotation> | |
83 | <appinfo> | |
84 | <meta.section type="since"/> | |
85 | </appinfo> | |
86 | <documentation> | |
87 | 1.1.500 | |
88 | </documentation> | |
89 | </annotation> | |
90 | ||
91 | <annotation> | |
92 | <appinfo> | |
93 | <meta.section type="examples"/> | |
94 | </appinfo> | |
95 | <documentation> | |
96 | <pre> | |
97 | <extension | |
98 | point="org.eclipse.ui.genericeditor.icons"> | |
99 | <icon | |
100 | contentType="org.eclipse.core.runtime.xml" | |
101 | icon="icons/xml_content.png" /> | |
102 | </extension> | |
103 | </pre> | |
104 | <pre> | |
105 | <extension | |
106 | point="org.eclipse.ui.genericeditor.icons"> | |
107 | <icon | |
108 | contentType="org.eclipse.core.runtime.text" | |
109 | icon="platform:/plugin/org.eclipse.ui.test/icons/text_content.png" /> | |
110 | </extension> | |
111 | </pre> | |
112 | </documentation> | |
113 | </annotation> | |
114 | ||
115 | ||
116 | ||
117 | <annotation> | |
118 | <appinfo> | |
119 | <meta.section type="copyright"/> | |
120 | </appinfo> | |
121 | <documentation> | |
122 | Copyright (c) 2019 Lakshminarayana Nekkanti(narayana.nekkanti@gmail.com) | |
123 | ||
124 | This program and the accompanying materials are made available under the | |
125 | terms of the Eclipse Public License 2.0 which is available at | |
126 | http://www.eclipse.org/legal/epl-2.0. | |
127 | ||
128 | SPDX-License-Identifier: EPL-2.0 3 | |
129 | ||
130 | Contributor | |
131 | Lakshminarayana Nekkanti - initial API and implementation | |
132 | </documentation> | |
133 | </annotation> | |
134 | ||
135 | </schema> | |
0 | <?xml version='1.0' encoding='UTF-8'?> | |
1 | <!-- Schema file written by PDE --> | |
2 | <schema targetNamespace="org.eclipse.ui.genericeditor" xmlns="http://www.w3.org/2001/XMLSchema"> | |
3 | <annotation> | |
4 | <appinfo> | |
5 | <meta.schema plugin="org.eclipse.ui.genericeditor" id="icons" name="GenericEditorIcons"/> | |
6 | </appinfo> | |
7 | <documentation> | |
8 | The icons extension point provides a way of linking different types of icons to a particular content type. | |
9 | </documentation> | |
10 | </annotation> | |
11 | ||
12 | <element name="extension"> | |
13 | <annotation> | |
14 | <appinfo> | |
15 | <meta.element /> | |
16 | </appinfo> | |
17 | </annotation> | |
18 | <complexType> | |
19 | <sequence> | |
20 | <element ref="icon" minOccurs="0" maxOccurs="unbounded"/> | |
21 | </sequence> | |
22 | <attribute name="point" type="string" use="required"> | |
23 | <annotation> | |
24 | <documentation> | |
25 | ||
26 | </documentation> | |
27 | </annotation> | |
28 | </attribute> | |
29 | <attribute name="id" type="string"> | |
30 | <annotation> | |
31 | <documentation> | |
32 | ||
33 | </documentation> | |
34 | </annotation> | |
35 | </attribute> | |
36 | <attribute name="name" type="string"> | |
37 | <annotation> | |
38 | <documentation> | |
39 | ||
40 | </documentation> | |
41 | <appinfo> | |
42 | <meta.attribute translatable="true"/> | |
43 | </appinfo> | |
44 | </annotation> | |
45 | </attribute> | |
46 | </complexType> | |
47 | </element> | |
48 | ||
49 | <element name="icon"> | |
50 | <annotation> | |
51 | <appinfo> | |
52 | <meta.element labelAttribute="contentType"/> | |
53 | </appinfo> | |
54 | <documentation> | |
55 | The icon to associate with a particular content type. | |
56 | </documentation> | |
57 | </annotation> | |
58 | <complexType> | |
59 | <attribute name="contentType" type="string" use="required"> | |
60 | <annotation> | |
61 | <documentation> | |
62 | The identifier of the content type with which the icons should be associated. | |
63 | </documentation> | |
64 | <appinfo> | |
65 | <meta.attribute kind="identifier" basedOn="org.eclipse.core.contenttype.contentTypes/content-type/@id"/> | |
66 | </appinfo> | |
67 | </annotation> | |
68 | </attribute> | |
69 | <attribute name="icon" type="string" use="required"> | |
70 | <annotation> | |
71 | <documentation> | |
72 | The path to the icon which should be used. | |
73 | </documentation> | |
74 | <appinfo> | |
75 | <meta.attribute kind="resource"/> | |
76 | </appinfo> | |
77 | </annotation> | |
78 | </attribute> | |
79 | </complexType> | |
80 | </element> | |
81 | ||
82 | <annotation> | |
83 | <appinfo> | |
84 | <meta.section type="since"/> | |
85 | </appinfo> | |
86 | <documentation> | |
87 | 1.1.500 | |
88 | </documentation> | |
89 | </annotation> | |
90 | ||
91 | <annotation> | |
92 | <appinfo> | |
93 | <meta.section type="examples"/> | |
94 | </appinfo> | |
95 | <documentation> | |
96 | <pre> | |
97 | <extension | |
98 | point="org.eclipse.ui.genericeditor.icons"> | |
99 | <icon | |
100 | contentType="org.eclipse.core.runtime.xml" | |
101 | icon="icons/xml_content.png" /> | |
102 | </extension> | |
103 | </pre> | |
104 | <pre> | |
105 | <extension | |
106 | point="org.eclipse.ui.genericeditor.icons"> | |
107 | <icon | |
108 | contentType="org.eclipse.core.runtime.text" | |
109 | icon="platform:/plugin/org.eclipse.ui.test/icons/text_content.png" /> | |
110 | </extension> | |
111 | </pre> | |
112 | </documentation> | |
113 | </annotation> | |
114 | ||
115 | ||
116 | ||
117 | <annotation> | |
118 | <appinfo> | |
119 | <meta.section type="copyright"/> | |
120 | </appinfo> | |
121 | <documentation> | |
122 | Copyright (c) 2019 Lakshminarayana Nekkanti(narayana.nekkanti@gmail.com) | |
123 | ||
124 | This program and the accompanying materials are made available under the | |
125 | terms of the Eclipse Public License 2.0 which is available at | |
126 | http://www.eclipse.org/legal/epl-2.0. | |
127 | ||
128 | SPDX-License-Identifier: EPL-2.0 3 | |
129 | ||
130 | Contributor | |
131 | Lakshminarayana Nekkanti - initial API and implementation | |
132 | </documentation> | |
133 | </annotation> | |
134 | ||
135 | </schema> |
0 | <?xml version='1.0' encoding='UTF-8'?> | |
1 | <!-- Schema file written by PDE --> | |
2 | <schema targetNamespace="org.eclipse.ui.genericeditor" xmlns="http://www.w3.org/2001/XMLSchema"> | |
3 | <annotation> | |
4 | <appinfo> | |
5 | <meta.schema plugin="org.eclipse.ui.genericeditor" id="quickAssistProcessors" name="%ExtPoint.quickAssistProcessors"/> | |
6 | </appinfo> | |
7 | <documentation> | |
8 | This extension point is used to contribute quick assist processors for quick content assist support to a given content type. | |
9 | </documentation> | |
10 | </annotation> | |
11 | ||
12 | <include schemaLocation="schema://org.eclipse.core.expressions/schema/expressionLanguage.exsd"/> | |
13 | ||
14 | <element name="extension"> | |
15 | <annotation> | |
16 | <appinfo> | |
17 | <meta.element /> | |
18 | </appinfo> | |
19 | </annotation> | |
20 | <complexType> | |
21 | <sequence minOccurs="1" maxOccurs="unbounded"> | |
22 | <element ref="quickAssistProcessor"/> | |
23 | </sequence> | |
24 | <attribute name="point" type="string" use="required"> | |
25 | <annotation> | |
26 | <documentation> | |
27 | ||
28 | </documentation> | |
29 | </annotation> | |
30 | </attribute> | |
31 | <attribute name="id" type="string"> | |
32 | <annotation> | |
33 | <documentation> | |
34 | ||
35 | </documentation> | |
36 | </annotation> | |
37 | </attribute> | |
38 | <attribute name="name" type="string"> | |
39 | <annotation> | |
40 | <documentation> | |
41 | ||
42 | </documentation> | |
43 | <appinfo> | |
44 | <meta.attribute translatable="true"/> | |
45 | </appinfo> | |
46 | </annotation> | |
47 | </attribute> | |
48 | </complexType> | |
49 | </element> | |
50 | ||
51 | <element name="quickAssistProcessor"> | |
52 | <complexType> | |
53 | <attribute name="class" type="string" use="required"> | |
54 | <annotation> | |
55 | <documentation> | |
56 | ||
57 | </documentation> | |
58 | <appinfo> | |
59 | <meta.attribute kind="java" basedOn=":org.eclipse.jface.text.quickassist.IQuickAssistProcessor"/> | |
60 | </appinfo> | |
61 | </annotation> | |
62 | </attribute> | |
63 | <attribute name="contentType" type="string" use="required"> | |
64 | <annotation> | |
65 | <documentation> | |
66 | The target content-type for this extension. Content-types are defined as extension to the org.eclipse.core.contenttype.contentTypes extension point. | |
67 | </documentation> | |
68 | <appinfo> | |
69 | <meta.attribute kind="identifier" basedOn="org.eclipse.core.contenttype.contentTypes/content-type/@id"/> | |
70 | </appinfo> | |
71 | </annotation> | |
72 | </attribute> | |
73 | </complexType> | |
74 | </element> | |
75 | ||
76 | <annotation> | |
77 | <appinfo> | |
78 | <meta.section type="since"/> | |
79 | </appinfo> | |
80 | <documentation> | |
81 | 1.1.600 | |
82 | </documentation> | |
83 | </annotation> | |
84 | ||
85 | <annotation> | |
86 | <appinfo> | |
87 | <meta.section type="examples"/> | |
88 | </appinfo> | |
89 | <documentation> | |
90 | <extension | |
91 | point="org.eclipse.ui.genericeditor.quickAssistProcessors"> | |
92 | <quickAssistProcessor | |
93 | class="org.eclipse.ui.genericeditor.tests.contributions.QuickAssistProcessor" | |
94 | contentType="org.eclipse.ui.genericeditor.tests.content-type"> | |
95 | </quickAssistProcessor> | |
96 | </extension> | |
97 | </documentation> | |
98 | </annotation> | |
99 | ||
100 | <annotation> | |
101 | <appinfo> | |
102 | <meta.section type="apiinfo"/> | |
103 | </appinfo> | |
104 | <documentation> | |
105 | This extension point does not require specific API's to use. Instead, it reuses IQuickAssistProcessor from org.jface.text.quickassist | |
106 | </documentation> | |
107 | </annotation> | |
108 | ||
109 | ||
110 | ||
111 | </schema> |
+1
-1
27 | 27 | * constructor. |
28 | 28 | */ |
29 | 29 | public class AnnotationHoverDelegate implements ITextHover { |
30 | ||
30 | ||
31 | 31 | private DefaultTextHover delegate; |
32 | 32 | private ISourceViewer viewer; |
33 | 33 |
+2
-2
34 | 34 | * A registry of auto edit strategies provided by extension |
35 | 35 | * <code>org.eclipse.ui.genericeditor.autoEditStrategy</code>. Those extensions |
36 | 36 | * are specific to a given {@link IContentType}. |
37 | * | |
37 | * | |
38 | 38 | * @since 1.1 |
39 | 39 | */ |
40 | 40 | public class AutoEditStrategyRegistry { |
59 | 59 | /** |
60 | 60 | * Get the contributed {@link IAutoEditStrategy}s that are relevant to hook |
61 | 61 | * on source viewer according to document content types. |
62 | * | |
62 | * | |
63 | 63 | * @param sourceViewer |
64 | 64 | * the source viewer we're hooking completion to. |
65 | 65 | * @param editor the text editor |
+2
-2
31 | 31 | * A registry of character pair matchers provided by extension |
32 | 32 | * <code>org.eclipse.ui.genericeditor.characterPairMatchers</code>. Those |
33 | 33 | * extensions are specific to a given {@link IContentType}. |
34 | * | |
34 | * | |
35 | 35 | * @since 1.2 |
36 | 36 | */ |
37 | 37 | public class CharacterPairMatcherRegistry { |
56 | 56 | /** |
57 | 57 | * Get the contributed {@link IPresentationReconciliers}s that are relevant to |
58 | 58 | * hook on source viewer according to document content types. |
59 | * | |
59 | * | |
60 | 60 | * @param sourceViewer the source viewer we're hooking completion to. |
61 | 61 | * @param editor the text editor |
62 | 62 | * @param contentTypes the content types of the document we're editing. |
+1
-1
28 | 28 | * A content assist processor that delegates all content assist |
29 | 29 | * operations to children provided in constructor and aggregates |
30 | 30 | * the results. |
31 | * | |
31 | * | |
32 | 32 | * @since 1.0 |
33 | 33 | */ |
34 | 34 | public class CompositeContentAssistProcessor implements IContentAssistProcessor { |
+1
-1
25 | 25 | * A quick assist processor that delegates all content assist |
26 | 26 | * operations to children provided in constructor and aggregates |
27 | 27 | * the results. |
28 | * | |
28 | * | |
29 | 29 | * @since 1.0 |
30 | 30 | */ |
31 | 31 | public class CompositeQuickAssistProcessor implements IQuickAssistProcessor { |
+4
-4
12 | 12 | *******************************************************************************/ |
13 | 13 | package org.eclipse.ui.internal.genericeditor; |
14 | 14 | |
15 | import java.util.HashMap; | |
16 | 15 | import java.util.HashSet; |
16 | import java.util.LinkedHashMap; | |
17 | 17 | import java.util.List; |
18 | 18 | import java.util.Map; |
19 | 19 | import java.util.Set; |
41 | 41 | /** |
42 | 42 | * A registry of content assist processors provided by extension <code>org.eclipse.ui.genericeditor.contentAssistProcessors</code>. |
43 | 43 | * Those extensions are specific to a given {@link IContentType}. |
44 | * | |
44 | * | |
45 | 45 | * @since 1.0 |
46 | 46 | */ |
47 | 47 | public class ContentAssistProcessorRegistry { |
129 | 129 | } |
130 | 130 | } |
131 | 131 | |
132 | private Map<IConfigurationElement, GenericContentTypeRelatedExtension<IContentAssistProcessor>> extensions = new HashMap<>(); | |
132 | private Map<IConfigurationElement, GenericContentTypeRelatedExtension<IContentAssistProcessor>> extensions = new LinkedHashMap<>(); | |
133 | 133 | private boolean outOfSync = true; |
134 | 134 | |
135 | 135 | /** |
146 | 146 | |
147 | 147 | /** |
148 | 148 | * Get the contributed {@link IContentAssistProcessor}s that are relevant to hook on source viewer according |
149 | * to document content types. | |
149 | * to document content types. | |
150 | 150 | * @param sourceViewer the source viewer we're hooking completion to. |
151 | 151 | * @param editor the text editor |
152 | 152 | * @param contentTypes the content types of the document we're editing. |
+2
-2
52 | 52 | String[] tokens = text.split(NON_ALPHANUMERIC_REGEXP); |
53 | 53 | |
54 | 54 | //remove duplicates |
55 | Set<String> tokenSet = new HashSet<String>(Arrays.asList(tokens)); | |
55 | Set<String> tokenSet = new HashSet<>(Arrays.asList(tokens)); | |
56 | 56 | |
57 | 57 | //wordStartIndex is the index of the last non-alphanumeric before 'offset' in text 'text' |
58 | 58 | int wordStartIndex = findStartingPoint(text, offset); |
59 | 59 | String prefix = text.substring(wordStartIndex, offset); |
60 | 60 | |
61 | List<ICompletionProposal> proposals = new ArrayList<ICompletionProposal>(); | |
61 | List<ICompletionProposal> proposals = new ArrayList<>(); | |
62 | 62 | for (String token : tokenSet) { |
63 | 63 | if ((token==null)||(token.length()<2)) { |
64 | 64 | continue; |
+15
-11
104 | 104 | } |
105 | 105 | |
106 | 106 | IAnnotationModel annotationModel = sourceViewer.getAnnotationModel(); |
107 | synchronized (getLockObject(annotationModel)) { | |
108 | if (annotationModel instanceof IAnnotationModelExtension) { | |
109 | ((IAnnotationModelExtension) annotationModel).replaceAnnotations(fOccurrenceAnnotations, annotationMap); | |
110 | } else { | |
111 | removeOccurrenceAnnotations(); | |
112 | Iterator<Entry<Annotation, Position>> iter = annotationMap.entrySet().iterator(); | |
113 | while (iter.hasNext()) { | |
114 | Entry<Annotation, Position> mapEntry = iter.next(); | |
115 | annotationModel.addAnnotation(mapEntry.getKey(), mapEntry.getValue()); | |
107 | if (annotationModel != null) { | |
108 | synchronized (getLockObject(annotationModel)) { | |
109 | if (annotationModel instanceof IAnnotationModelExtension) { | |
110 | ((IAnnotationModelExtension) annotationModel).replaceAnnotations(fOccurrenceAnnotations, annotationMap); | |
111 | } else { | |
112 | removeOccurrenceAnnotations(); | |
113 | Iterator<Entry<Annotation, Position>> iter = annotationMap.entrySet().iterator(); | |
114 | while (iter.hasNext()) { | |
115 | Entry<Annotation, Position> mapEntry = iter.next(); | |
116 | annotationModel.addAnnotation(mapEntry.getKey(), mapEntry.getValue()); | |
117 | } | |
116 | 118 | } |
117 | } | |
118 | fOccurrenceAnnotations = annotationMap.keySet().toArray(new Annotation[annotationMap.keySet().size()]); | |
119 | fOccurrenceAnnotations = annotationMap.keySet().toArray(new Annotation[annotationMap.keySet().size()]); | |
120 | } | |
121 | } else { | |
122 | fOccurrenceAnnotations = null; | |
119 | 123 | } |
120 | 124 | } |
121 | 125 |
+3
-3
55 | 55 | private ImageDescriptor contentTypeImageDescripter; |
56 | 56 | |
57 | 57 | /** |
58 | * | |
58 | * | |
59 | 59 | */ |
60 | 60 | public ExtensionBasedTextEditor() { |
61 | 61 | configuration = new ExtensionBasedTextViewerConfiguration(this, getPreferenceStore()); |
100 | 100 | |
101 | 101 | /** |
102 | 102 | * Configure the {@link ICharacterPairMatcher} from the "org.eclipse.ui.genericeditor.characterPairMatchers" extension point. |
103 | * | |
103 | * | |
104 | 104 | * @param viewer |
105 | 105 | * the source viewer. |
106 | * | |
106 | * | |
107 | 107 | * @param support |
108 | 108 | * the source viewer decoration support. |
109 | 109 | */ |
+7
-1
16 | 16 | *******************************************************************************/ |
17 | 17 | package org.eclipse.ui.internal.genericeditor; |
18 | 18 | |
19 | import java.util.ArrayList; | |
19 | 20 | import java.util.Arrays; |
20 | 21 | import java.util.Collections; |
21 | 22 | import java.util.LinkedHashSet; |
43 | 44 | import org.eclipse.jface.text.contentassist.IContentAssistant; |
44 | 45 | import org.eclipse.jface.text.presentation.IPresentationReconciler; |
45 | 46 | import org.eclipse.jface.text.quickassist.IQuickAssistAssistant; |
47 | import org.eclipse.jface.text.quickassist.IQuickAssistProcessor; | |
46 | 48 | import org.eclipse.jface.text.quickassist.QuickAssistAssistant; |
47 | 49 | import org.eclipse.jface.text.reconciler.IReconciler; |
48 | 50 | import org.eclipse.jface.text.source.ISourceViewer; |
191 | 193 | |
192 | 194 | @Override public IQuickAssistAssistant getQuickAssistAssistant(ISourceViewer sourceViewer) { |
193 | 195 | QuickAssistAssistant quickAssistAssistant = new QuickAssistAssistant(); |
194 | quickAssistAssistant.setQuickAssistProcessor(new MarkerResoltionQuickAssistProcessor()); | |
196 | List<IQuickAssistProcessor> quickAssistProcessors = new ArrayList<>(); | |
197 | quickAssistProcessors.add(new MarkerResoltionQuickAssistProcessor()); | |
198 | quickAssistProcessors.addAll(GenericEditorPlugin.getDefault().getQuickAssistProcessorRegistry().getQuickAssistProcessors(sourceViewer, editor, getContentTypes(sourceViewer))); | |
199 | CompositeQuickAssistProcessor compQuickAssistProcessor = new CompositeQuickAssistProcessor(quickAssistProcessors); | |
200 | quickAssistAssistant.setQuickAssistProcessor(compQuickAssistProcessor); | |
195 | 201 | quickAssistAssistant.setRestoreCompletionProposalSize(EditorsPlugin.getDefault().getDialogSettingsSection("quick_assist_proposal_size")); //$NON-NLS-1$ |
196 | 202 | quickAssistAssistant.setInformationControlCreator(parent -> new DefaultInformationControl(parent, EditorsPlugin.getAdditionalInfoAffordanceString())); |
197 | 203 | return quickAssistAssistant; |
+1
-1
28 | 28 | |
29 | 29 | /** |
30 | 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. |
31 | * | |
31 | * | |
32 | 32 | * @param <T> |
33 | 33 | * the actual type to proxy, typically the one defined on the extension point. |
34 | 34 | */ |
+15
-1
17 | 17 | import org.eclipse.jface.text.ITextHover; |
18 | 18 | import org.eclipse.jface.text.contentassist.IContentAssistProcessor; |
19 | 19 | import org.eclipse.jface.text.presentation.IPresentationReconciler; |
20 | import org.eclipse.jface.text.quickassist.IQuickAssistProcessor; | |
20 | 21 | import org.eclipse.jface.text.reconciler.IReconciler; |
21 | 22 | import org.eclipse.jface.text.source.ICharacterPairMatcher; |
22 | 23 | import org.eclipse.jface.util.IPropertyChangeListener; |
31 | 32 | |
32 | 33 | /** |
33 | 34 | * Generic editor plugin activator and singletons. |
34 | * | |
35 | * | |
35 | 36 | * @since 1.0 |
36 | 37 | */ |
37 | 38 | public class GenericEditorPlugin extends AbstractUIPlugin { |
42 | 43 | |
43 | 44 | private TextHoverRegistry textHoversRegistry; |
44 | 45 | private ContentAssistProcessorRegistry contentAssistProcessorsRegistry; |
46 | private QuickAssistProcessorRegistry quickAssistProcessorRegistry; | |
45 | 47 | private ReconcilerRegistry reconcilierRegistry; |
46 | 48 | private PresentationReconcilerRegistry presentationReconcilierRegistry; |
47 | 49 | private AutoEditStrategyRegistry autoEditStrategyRegistry; |
106 | 108 | } |
107 | 109 | |
108 | 110 | /** |
111 | * @return the registry allowing to access contributed | |
112 | * {@link IQuickAssistProcessor}s. | |
113 | * @since 1.2 | |
114 | */ | |
115 | public synchronized QuickAssistProcessorRegistry getQuickAssistProcessorRegistry() { | |
116 | if (this.quickAssistProcessorRegistry == null) { | |
117 | this.quickAssistProcessorRegistry = new QuickAssistProcessorRegistry(); | |
118 | } | |
119 | return this.quickAssistProcessorRegistry; | |
120 | } | |
121 | ||
122 | /** | |
109 | 123 | * @return the registry allowing to access contributed {@link IReconciler}s. |
110 | 124 | * @since 1.1 |
111 | 125 | */ |
+1
-1
28 | 28 | */ |
29 | 29 | public class GenericEditorWithIconAssociationOverride implements IEditorAssociationOverride { |
30 | 30 | |
31 | private Map<String, IEditorDescriptor> descriptorMap = new HashMap<String, IEditorDescriptor>(); | |
31 | private Map<String, IEditorDescriptor> descriptorMap = new HashMap<>(); | |
32 | 32 | |
33 | 33 | @Override |
34 | 34 | public IEditorDescriptor[] overrideEditors(IEditorInput editorInput, IContentType contentType, |
+2
-2
33 | 33 | /** |
34 | 34 | * A registry of presentation reconciliers provided by extension <code>org.eclipse.ui.genericeditor.presentationReconcilers</code>. |
35 | 35 | * Those extensions are specific to a given {@link IContentType}. |
36 | * | |
36 | * | |
37 | 37 | * @since 1.0 |
38 | 38 | */ |
39 | 39 | public class PresentationReconcilerRegistry { |
57 | 57 | |
58 | 58 | /** |
59 | 59 | * Get the contributed {@link IPresentationReconciliers}s that are relevant to hook on source viewer according |
60 | * to document content types. | |
60 | * to document content types. | |
61 | 61 | * @param sourceViewer the source viewer we're hooking completion to. |
62 | 62 | * @param editor the text editor |
63 | 63 | * @param contentTypes the content types of the document we're editing. |
+92
-0
0 | /******************************************************************************* | |
1 | * Copyright (c) 2016-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 | * - Andrew Obuchowicz (Red Hat Inc.) | |
12 | *******************************************************************************/ | |
13 | package org.eclipse.ui.internal.genericeditor; | |
14 | ||
15 | import java.util.HashMap; | |
16 | import java.util.HashSet; | |
17 | import java.util.List; | |
18 | import java.util.Map; | |
19 | import java.util.Set; | |
20 | import java.util.stream.Collectors; | |
21 | ||
22 | import org.eclipse.core.runtime.IConfigurationElement; | |
23 | import org.eclipse.core.runtime.IRegistryChangeEvent; | |
24 | import org.eclipse.core.runtime.IRegistryChangeListener; | |
25 | import org.eclipse.core.runtime.IStatus; | |
26 | import org.eclipse.core.runtime.Platform; | |
27 | import org.eclipse.core.runtime.Status; | |
28 | import org.eclipse.core.runtime.content.IContentType; | |
29 | import org.eclipse.jface.text.quickassist.IQuickAssistProcessor; | |
30 | import org.eclipse.jface.text.source.ISourceViewer; | |
31 | import org.eclipse.ui.texteditor.ITextEditor; | |
32 | ||
33 | public class QuickAssistProcessorRegistry { | |
34 | ||
35 | private static final String EXTENSION_POINT_ID = GenericEditorPlugin.BUNDLE_ID + ".quickAssistProcessors"; //$NON-NLS-1$ | |
36 | private Map<IConfigurationElement, GenericContentTypeRelatedExtension<IQuickAssistProcessor>> extensions = new HashMap<>(); | |
37 | private boolean outOfSync = true; | |
38 | ||
39 | /** | |
40 | * Creates the registry and binds it to the extension point. | |
41 | */ | |
42 | public QuickAssistProcessorRegistry() { | |
43 | Platform.getExtensionRegistry().addRegistryChangeListener(new IRegistryChangeListener() { | |
44 | @Override | |
45 | public void registryChanged(IRegistryChangeEvent event) { | |
46 | outOfSync = true; | |
47 | } | |
48 | }, EXTENSION_POINT_ID); | |
49 | } | |
50 | ||
51 | /** | |
52 | * Get the contributed {@link IQuickAssistProcessor}s | |
53 | * | |
54 | * @return the list of {@link IQuickAssistProcessor} contributed | |
55 | */ | |
56 | ||
57 | public List<IQuickAssistProcessor> getQuickAssistProcessors(ISourceViewer sourceViewer, ITextEditor editor, | |
58 | Set<IContentType> contentTypes) { | |
59 | if (this.outOfSync) { | |
60 | sync(); | |
61 | } | |
62 | return this.extensions.values().stream() | |
63 | .filter(ext -> contentTypes.contains(ext.targetContentType)) | |
64 | .filter(ext -> ext.matches(sourceViewer, editor)) | |
65 | .sorted(new ContentTypeSpecializationComparator<IQuickAssistProcessor>()) | |
66 | .map(GenericContentTypeRelatedExtension<IQuickAssistProcessor>::createDelegate) | |
67 | .collect(Collectors.toList()); | |
68 | } | |
69 | ||
70 | private void sync() { | |
71 | Set<IConfigurationElement> toRemoveExtensions = new HashSet<>(this.extensions.keySet()); | |
72 | for (IConfigurationElement extension : Platform.getExtensionRegistry() | |
73 | .getConfigurationElementsFor(EXTENSION_POINT_ID)) { | |
74 | toRemoveExtensions.remove(extension); | |
75 | if (!this.extensions.containsKey(extension)) { | |
76 | try { | |
77 | this.extensions.put(extension, | |
78 | new GenericContentTypeRelatedExtension<IQuickAssistProcessor>(extension)); | |
79 | } catch (Exception ex) { | |
80 | GenericEditorPlugin.getDefault().getLog() | |
81 | .log(new Status(IStatus.ERROR, GenericEditorPlugin.BUNDLE_ID, ex.getMessage(), ex)); | |
82 | } | |
83 | } | |
84 | } | |
85 | for (IConfigurationElement toRemove : toRemoveExtensions) { | |
86 | this.extensions.remove(toRemove); | |
87 | } | |
88 | this.outOfSync = false; | |
89 | } | |
90 | ||
91 | } |
+3
-3
69 | 69 | /** |
70 | 70 | * Get the contributed {@link IReconciliers}s that are relevant to hook on |
71 | 71 | * source viewer according to document content types. |
72 | * | |
72 | * | |
73 | 73 | * @param sourceViewer the source viewer we're hooking completion to. |
74 | 74 | * @param editor the text editor |
75 | 75 | * @param contentTypes the content types of the document we're editing. |
92 | 92 | /** |
93 | 93 | * Get the contributed highlight {@link IReconciliers}s that are relevant to |
94 | 94 | * hook on source viewer according to document content types. |
95 | * | |
95 | * | |
96 | 96 | * @param sourceViewer the source viewer we're hooking completion to. |
97 | 97 | * @param editor the text editor |
98 | 98 | * @param contentTypes the content types of the document we're editing. |
116 | 116 | /** |
117 | 117 | * Get the contributed folding {@link IReconciliers}s that are relevant to hook |
118 | 118 | * on source viewer according to document content types. |
119 | * | |
119 | * | |
120 | 120 | * @param sourceViewer the source viewer we're hooking completion to. |
121 | 121 | * @param editor the text editor |
122 | 122 | * @param contentTypes the content types of the document we're editing. |
+17
-17
6 | 6 | * https://www.eclipse.org/legal/epl-2.0/ |
7 | 7 | * |
8 | 8 | * SPDX-License-Identifier: EPL-2.0 |
9 | * | |
9 | * | |
10 | 10 | * Contributors: |
11 | 11 | * IBM Corporation - initial API and implementation |
12 | 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 | |
13 | * [generic editor] Default Code folding for generic editor should use IndentFoldingStrategy - Bug 520659 | |
14 | 14 | */ |
15 | 15 | package org.eclipse.ui.internal.genericeditor.folding; |
16 | 16 | |
67 | 67 | |
68 | 68 | /** |
69 | 69 | * Creates a new FoldingAnnotation. |
70 | * | |
70 | * | |
71 | 71 | * @param isCollapsed true if this annotation should be collapsed, false |
72 | 72 | * otherwise |
73 | 73 | */ |
79 | 79 | /** |
80 | 80 | * Does not paint hidden annotations. Annotations are hidden when they only span |
81 | 81 | * one line. |
82 | * | |
82 | * | |
83 | 83 | * @see ProjectionAnnotation#paint(org.eclipse.swt.graphics.GC, |
84 | 84 | * org.eclipse.swt.widgets.Canvas, org.eclipse.swt.graphics.Rectangle) |
85 | 85 | */ |
117 | 117 | |
118 | 118 | /** |
119 | 119 | * The folding strategy must be associated with a viewer for it to function |
120 | * | |
120 | * | |
121 | 121 | * @param viewer the viewer to associate this folding strategy with |
122 | 122 | */ |
123 | 123 | public void setViewer(ProjectionViewer viewer) { |
173 | 173 | |
174 | 174 | // these are what are passed off to the annotation model to |
175 | 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>(); | |
176 | List<Annotation> modifications = new ArrayList<>(); | |
177 | List<FoldingAnnotation> deletions = new ArrayList<>(); | |
178 | List<FoldingAnnotation> existing = new ArrayList<>(); | |
179 | Map<Annotation, Position> additions = new HashMap<>(); | |
180 | 180 | |
181 | 181 | // find and mark all folding annotations with length 0 for deletion |
182 | 182 | markInvalidAnnotationsForDeletion(dirtyRegion, deletions, existing); |
183 | 183 | |
184 | List<LineIndent> previousRegions = new ArrayList<LineIndent>(); | |
184 | List<LineIndent> previousRegions = new ArrayList<>(); | |
185 | 185 | |
186 | 186 | int tabSize = 1; |
187 | 187 | int minimumRangeSize = 1; |
290 | 290 | |
291 | 291 | /** |
292 | 292 | * Returns the line state for line which starts with a given keyword. |
293 | * | |
293 | * | |
294 | 294 | * @param lineContent line content. |
295 | 295 | * @param lastLineForKeyword last line for the given keyword. |
296 | 296 | * @return |
313 | 313 | |
314 | 314 | /** |
315 | 315 | * Compute indentation level of the given line by using the given tab size. |
316 | * | |
316 | * | |
317 | 317 | * @param line the line text. |
318 | 318 | * @param tabSize the tab size. |
319 | 319 | * @return the indentation level of the given line by using the given tab size. |
341 | 341 | /** |
342 | 342 | * Given a {@link DirtyRegion} returns an {@link Iterator} of the already |
343 | 343 | * existing annotations in that region. |
344 | * | |
344 | * | |
345 | 345 | * @param dirtyRegion the {@link DirtyRegion} to check for existing annotations |
346 | 346 | * in |
347 | * | |
347 | * | |
348 | 348 | * @return an {@link Iterator} over the annotations in the given |
349 | 349 | * {@link DirtyRegion}. The iterator could have no annotations in it. Or |
350 | 350 | * <code>null</code> if projection has been disabled. |
361 | 361 | |
362 | 362 | /** |
363 | 363 | * Update annotations. |
364 | * | |
364 | * | |
365 | 365 | * @param modifications the folding annotations to update. |
366 | 366 | * @param deletions the folding annotations to delete. |
367 | 367 | * @param existing the existing folding annotations. |
386 | 386 | |
387 | 387 | /** |
388 | 388 | * Update annotations. |
389 | * | |
389 | * | |
390 | 390 | * @param existingAnnotation the existing annotations that need to be updated |
391 | 391 | * based on the given dirtied IndexRegion |
392 | 392 | * @param newPos the new position that caused the annotations need |
423 | 423 | * These {@link FoldingAnnotation}s are then added to the {@link List} of |
424 | 424 | * {@link FoldingAnnotation}s to be deleted |
425 | 425 | * </p> |
426 | * | |
426 | * | |
427 | 427 | * @param dirtyRegion find the now invalid {@link FoldingAnnotation}s in this |
428 | 428 | * {@link DirtyRegion} |
429 | 429 | * @param deletions the current list of {@link FoldingAnnotation}s marked for |
+1
-1
112 | 112 | } while (thisIterator.hasNext()); |
113 | 113 | return true; |
114 | 114 | } |
115 | ||
115 | ||
116 | 116 | |
117 | 117 | @Override |
118 | 118 | public IInformationControl createInformationControl(Shell parent) { |
+1
-1
65 | 65 | } |
66 | 66 | return resolutions.toArray(new ICompletionProposal[resolutions.size()]); |
67 | 67 | } |
68 | ||
68 | ||
69 | 69 | } |
+4
-4
37 | 37 | * <p> |
38 | 38 | * Value is of type <code>Boolean</code>. |
39 | 39 | * </p> |
40 | * | |
40 | * | |
41 | 41 | * @since 1.2 |
42 | 42 | */ |
43 | 43 | public final static String EDITOR_MATCHING_BRACKETS = "matchingBrackets"; //$NON-NLS-1$ |
51 | 51 | * |
52 | 52 | * @see org.eclipse.jface.resource.StringConverter |
53 | 53 | * @see org.eclipse.jface.preference.PreferenceConverter |
54 | * | |
54 | * | |
55 | 55 | * @since 1.2 |
56 | 56 | */ |
57 | 57 | public final static String EDITOR_MATCHING_BRACKETS_COLOR = "matchingBracketsColor"; //$NON-NLS-1$ |
62 | 62 | * <p> |
63 | 63 | * Value is of type <code>Boolean</code>. |
64 | 64 | * </p> |
65 | * | |
65 | * | |
66 | 66 | * @since 1.2 |
67 | 67 | */ |
68 | 68 | public final static String EDITOR_HIGHLIGHT_BRACKET_AT_CARET_LOCATION = "highlightBracketAtCaretLocation"; //$NON-NLS-1$ |
73 | 73 | * <p> |
74 | 74 | * Value is of type <code>Boolean</code>. |
75 | 75 | * </p> |
76 | * | |
76 | * | |
77 | 77 | * @since 1.2 |
78 | 78 | */ |
79 | 79 | public final static String EDITOR_ENCLOSING_BRACKETS = "enclosingBrackets"; //$NON-NLS-1$ |
1 | 1 | Bundle-ManifestVersion: 2 |
2 | 2 | Bundle-Name: Examples for Generic Editor |
3 | 3 | Bundle-SymbolicName: org.eclipse.ui.genericeditor.examples;singleton:=true |
4 | Bundle-Version: 1.1.400.qualifier | |
4 | Bundle-Version: 1.1.500.qualifier | |
5 | 5 | Bundle-Vendor: Eclipse.org |
6 | 6 | Bundle-RequiredExecutionEnvironment: JavaSE-1.8 |
7 | 7 | Require-Bundle: org.eclipse.ui.genericeditor;bundle-version="1.0.0", |
0 | <?xml version="1.0" encoding="UTF-8"?> | |
1 | <!-- | |
2 | Copyright (c) 2016 Red Hat Inc. and others. | |
3 | All rights reserved. This program and the accompanying materials | |
4 | are made available under the terms of the Eclipse Distribution License v1.0 | |
5 | which accompanies this distribution, and is available at | |
6 | http://www.eclipse.org/org/documents/edl-v10.php | |
7 | ||
8 | Contributors: | |
9 | Mickael Istria (Red Hat Inc.) - initial implementation | |
10 | --> | |
11 | <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | |
12 | <modelVersion>4.0.0</modelVersion> | |
13 | <parent> | |
14 | <artifactId>eclipse.platform.text</artifactId> | |
15 | <groupId>eclipse.platform.text</groupId> | |
16 | <version>4.13.0-SNAPSHOT</version> | |
17 | </parent> | |
18 | <groupId>org.eclipse.ui</groupId> | |
19 | <artifactId>org.eclipse.ui.genericeditor.examples</artifactId> | |
20 | <version>1.1.400-SNAPSHOT</version> | |
21 | <packaging>eclipse-plugin</packaging> | |
22 | </project> |
+5
-5
38 | 38 | import org.eclipse.ui.texteditor.spelling.SpellingService; |
39 | 39 | |
40 | 40 | public class SpellCheckDocumentListener implements IDocumentListener { |
41 | ||
41 | ||
42 | 42 | Job lastJob = null; |
43 | 43 | SpellingService service = EditorsUI.getSpellingService(); |
44 | 44 | |
72 | 72 | Region region = new Region(commentStart, commentEnd - commentStart); |
73 | 73 | service.check(event.getDocument(), new Region[] { region }, new SpellingContext(), new ISpellingProblemCollector() { |
74 | 74 | private Map<SpellingAnnotation, Position> annotations = new HashMap<>(); |
75 | ||
75 | ||
76 | 76 | @Override |
77 | 77 | public void endCollecting() { |
78 | 78 | Set<SpellingAnnotation> previous = new HashSet<>(); |
85 | 85 | ((IAnnotationModelExtension)model).replaceAnnotations( |
86 | 86 | previous.toArray(new SpellingAnnotation[previous.size()]), |
87 | 87 | annotations); |
88 | ||
88 | ||
89 | 89 | } else { |
90 | 90 | previous.forEach(model::removeAnnotation); |
91 | 91 | annotations.forEach(model::addAnnotation); |
92 | 92 | } |
93 | 93 | } |
94 | ||
94 | ||
95 | 95 | @Override |
96 | 96 | public void beginCollecting() { |
97 | 97 | } |
98 | ||
98 | ||
99 | 99 | @Override |
100 | 100 | public void accept(SpellingProblem problem) { |
101 | 101 | this.annotations.put(new SpellingAnnotation(problem), new Position(problem.getOffset(), problem.getLength())); |
1 | 1 | Bundle-ManifestVersion: 2 |
2 | 2 | Bundle-Name: %Plugin.name |
3 | 3 | Bundle-SymbolicName: org.eclipse.ui.genericeditor.tests;singleton:=true |
4 | Bundle-Version: 1.1.400.qualifier | |
4 | Bundle-Version: 1.1.500.qualifier | |
5 | 5 | Bundle-Vendor: %Plugin.providerName |
6 | 6 | Bundle-Localization: plugin |
7 | 7 | Export-Package: org.eclipse.ui.genericeditor.tests, |
12 | 12 | org.eclipse.text;bundle-version="[3.5.0,4.0.0)", |
13 | 13 | org.eclipse.ui.genericeditor, |
14 | 14 | org.eclipse.core.resources;bundle-version="3.11.0", |
15 | org.eclipse.jface.text;bundle-version="3.11.0", | |
15 | org.eclipse.jface.text;bundle-version="3.16.0", | |
16 | 16 | org.eclipse.ui;bundle-version="3.108.0", |
17 | 17 | org.eclipse.ui.workbench.texteditor;bundle-version="3.10.0", |
18 | 18 | org.eclipse.ui.ide;bundle-version="3.11.0", |
34 | 34 | </test> |
35 | 35 | </enabledWhen> |
36 | 36 | </contentAssistProcessor> |
37 | <contentAssistProcessor | |
38 | class="org.eclipse.ui.genericeditor.tests.contributions.ToUpperCaseContentAssistProcessor" | |
39 | contentType="org.eclipse.ui.genericeditor.tests.content-type"> | |
40 | </contentAssistProcessor> | |
37 | 41 | </extension> |
38 | 42 | <extension |
39 | 43 | point="org.eclipse.ui.genericeditor.hoverProviders"> |
274 | 278 | contentType="org.eclipse.ui.genericeditor.tests.sub-specialized-content-type" |
275 | 279 | icon="platform:/plugin/org.eclipse.ui.ide/icons/full/etool16/newprj_wiz.png"/> |
276 | 280 | </extension> |
281 | <extension | |
282 | point="org.eclipse.ui.genericeditor.quickAssistProcessors"> | |
283 | <quickAssistProcessor | |
284 | class="org.eclipse.ui.genericeditor.tests.contributions.MockQuickAssistProcessor" | |
285 | contentType="org.eclipse.ui.genericeditor.tests.content-type"> | |
286 | </quickAssistProcessor> | |
287 | </extension> | |
277 | 288 | </plugin> |
13 | 13 | <parent> |
14 | 14 | <artifactId>tests-pom</artifactId> |
15 | 15 | <groupId>eclipse.platform.text</groupId> |
16 | <version>4.13.0-SNAPSHOT</version> | |
16 | <version>4.14.0-SNAPSHOT</version> | |
17 | 17 | <relativePath>../tests-pom/</relativePath> |
18 | 18 | </parent> |
19 | 19 | <groupId>org.eclipse.ui</groupId> |
20 | 20 | <artifactId>org.eclipse.ui.genericeditor.tests</artifactId> |
21 | <version>1.1.400-SNAPSHOT</version> | |
21 | <version>1.1.500-SNAPSHOT</version> | |
22 | 22 | <packaging>eclipse-test-plugin</packaging> |
23 | 23 | <properties> |
24 | 24 | <testSuite>${project.artifactId}</testSuite> |
+7
-7
40 | 40 | /** |
41 | 41 | * Closes intro, create {@link #project}, create {@link #file} and open {@link #editor}; and clean up. |
42 | 42 | * Also contains additional utility methods |
43 | * @since 1.0 | |
43 | * @since 1.0 | |
44 | 44 | */ |
45 | 45 | public class AbstratGenericEditorTest { |
46 | ||
46 | ||
47 | 47 | protected IProject project; |
48 | 48 | protected IFile file; |
49 | 49 | protected ExtensionBasedTextEditor editor; |
50 | 50 | protected IWorkbenchWindow window; |
51 | ||
51 | ||
52 | 52 | /** |
53 | 53 | * Closes intro, create {@link #project}, create {@link #file} and open {@link #editor} |
54 | 54 | * @throws Exception ex |
69 | 69 | protected void createAndOpenFile() throws Exception { |
70 | 70 | createAndOpenFile("foo.txt", "bar 'bar'"); |
71 | 71 | } |
72 | ||
72 | ||
73 | 73 | /** |
74 | 74 | * Creates a new file in the project, opens it, and associate that file with the test state |
75 | 75 | * @param name name of the file in the project |
102 | 102 | file = null; |
103 | 103 | } |
104 | 104 | } |
105 | ||
105 | ||
106 | 106 | protected SourceViewer getSourceViewer() { |
107 | 107 | SourceViewer sourceViewer= (SourceViewer) new Accessor(editor, AbstractTextEditor.class).invoke("getSourceViewer", new Object[0]); |
108 | 108 | return sourceViewer; |
109 | 109 | } |
110 | ||
110 | ||
111 | 111 | @After |
112 | 112 | public void tearDown() throws Exception { |
113 | 113 | cleanFileAndEditor(); |
123 | 123 | UITestCase.processEvents(); |
124 | 124 | } |
125 | 125 | } |
126 | ||
126 | ||
127 | 127 | public static void waitAndDispatch(long milliseconds) { |
128 | 128 | long timeout = milliseconds; //ms |
129 | 129 | long start = System.currentTimeMillis(); |
+33
-14
28 | 28 | import org.eclipse.swt.custom.StyledText; |
29 | 29 | import org.eclipse.swt.widgets.Composite; |
30 | 30 | import org.eclipse.swt.widgets.Control; |
31 | import org.eclipse.swt.widgets.Display; | |
31 | 32 | import org.eclipse.swt.widgets.Event; |
32 | 33 | import org.eclipse.swt.widgets.Shell; |
33 | 34 | import org.eclipse.swt.widgets.Table; |
55 | 56 | @Test |
56 | 57 | public void testCompletion() throws Exception { |
57 | 58 | final Set<Shell> beforeShells = Arrays.stream(editor.getSite().getShell().getDisplay().getShells()).filter(Shell::isVisible).collect(Collectors.toSet()); |
58 | openConentAssist(); | |
59 | this.completionShell= findNewShell(beforeShells); | |
59 | editor.selectAndReveal(3, 0); | |
60 | openConentAssist(); | |
61 | this.completionShell= findNewShell(beforeShells, editor.getSite().getShell().getDisplay()); | |
60 | 62 | final Table completionProposalList = findCompletionSelectionControl(completionShell); |
61 | 63 | checkCompletionContent(completionProposalList); |
62 | 64 | // TODO find a way to actually trigger completion and verify result against Editor content |
64 | 66 | } |
65 | 67 | |
66 | 68 | @Test |
69 | public void testCompletionUsingViewerSelection() throws Exception { | |
70 | final Set<Shell> beforeShells = Arrays.stream(editor.getSite().getShell().getDisplay().getShells()).filter(Shell::isVisible).collect(Collectors.toSet()); | |
71 | editor.getDocumentProvider().getDocument(editor.getEditorInput()).set("abc"); | |
72 | editor.selectAndReveal(0, 3); | |
73 | openConentAssist(); | |
74 | this.completionShell= findNewShell(beforeShells, editor.getSite().getShell().getDisplay()); | |
75 | final Table completionProposalList = findCompletionSelectionControl(completionShell); | |
76 | assertTrue(new DisplayHelper() { | |
77 | @Override | |
78 | protected boolean condition() { | |
79 | return Arrays.stream(completionProposalList.getItems()).map(TableItem::getText).anyMatch("ABC"::equals); | |
80 | } | |
81 | }.waitForCondition(completionProposalList.getDisplay(), 200)); | |
82 | } | |
83 | ||
84 | @Test | |
67 | 85 | public void testEnabledWhenCompletion() throws Exception { |
68 | 86 | // Confirm that when disabled, a completion shell is present |
69 | 87 | EnabledPropertyTester.setEnabled(false); |
70 | 88 | createAndOpenFile("enabledWhen.txt", "bar 'bar'"); |
71 | 89 | final Set<Shell> beforeShells = Arrays.stream(editor.getSite().getShell().getDisplay().getShells()).filter(Shell::isVisible).collect(Collectors.toSet()); |
90 | editor.selectAndReveal(3, 0); | |
72 | 91 | openConentAssist(); |
73 | 92 | Shell[] afterShells = Arrays.stream(editor.getSite().getShell().getDisplay().getShells()) |
74 | 93 | .filter(Shell::isVisible) |
81 | 100 | EnabledPropertyTester.setEnabled(true); |
82 | 101 | createAndOpenFile("enabledWhen.txt", "bar 'bar'"); |
83 | 102 | final Set<Shell> beforeEnabledShells = Arrays.stream(editor.getSite().getShell().getDisplay().getShells()).filter(Shell::isVisible).collect(Collectors.toSet()); |
84 | openConentAssist(); | |
85 | assertNotNull(findNewShell(beforeEnabledShells)); | |
103 | editor.selectAndReveal(3, 0); | |
104 | openConentAssist(); | |
105 | assertNotNull(findNewShell(beforeEnabledShells, editor.getSite().getShell().getDisplay())); | |
86 | 106 | } |
87 | 107 | |
88 | 108 | private void openConentAssist() { |
89 | editor.selectAndReveal(3, 0); | |
90 | 109 | ContentAssistAction action = (ContentAssistAction) editor.getAction(ITextEditorActionConstants.CONTENT_ASSIST); |
91 | 110 | action.update(); |
92 | 111 | action.run(); |
102 | 121 | */ |
103 | 122 | private void checkCompletionContent(final Table completionProposalList) { |
104 | 123 | // should be instantaneous, but happens to go asynchronous on CI so let's allow a wait |
105 | new DisplayHelper() { | |
124 | assertTrue(new DisplayHelper() { | |
106 | 125 | @Override |
107 | 126 | protected boolean condition() { |
108 | 127 | return completionProposalList.getItemCount() == 2; |
109 | 128 | } |
110 | }.waitForCondition(completionProposalList.getDisplay(), 200); | |
111 | assertEquals(2, completionProposalList.getItemCount()); | |
129 | }.waitForCondition(completionProposalList.getDisplay(), 200)); | |
112 | 130 | final TableItem computingItem = completionProposalList.getItem(0); |
113 | 131 | assertTrue("Missing computing info entry", computingItem.getText().contains("Computing")); //$NON-NLS-1$ //$NON-NLS-2$ |
114 | 132 | TableItem completionProposalItem = completionProposalList.getItem(1); |
129 | 147 | assertEquals("Addition of completion proposal should keep selection", selectedProposal, completionProposalList.getSelection()[0].getData()); |
130 | 148 | } |
131 | 149 | |
132 | private Shell findNewShell(Set<Shell> beforeShells) { | |
133 | Shell[] afterShells = Arrays.stream(editor.getSite().getShell().getDisplay().getShells()) | |
150 | public static Shell findNewShell(Set<Shell> beforeShells, Display display) { | |
151 | Shell[] afterShells = Arrays.stream(display.getShells()) | |
134 | 152 | .filter(Shell::isVisible) |
135 | 153 | .filter(shell -> !beforeShells.contains(shell)) |
136 | 154 | .toArray(Shell[]::new); |
141 | 159 | @Test |
142 | 160 | public void testCompletionFreeze_bug521484() throws Exception { |
143 | 161 | final Set<Shell> beforeShells = Arrays.stream(editor.getSite().getShell().getDisplay().getShells()).filter(Shell::isVisible).collect(Collectors.toSet()); |
144 | openConentAssist(); | |
145 | this.completionShell= findNewShell(beforeShells); | |
162 | editor.selectAndReveal(3, 0); | |
163 | openConentAssist(); | |
164 | this.completionShell= findNewShell(beforeShells, editor.getSite().getShell().getDisplay()); | |
146 | 165 | final Table completionProposalList = findCompletionSelectionControl(this.completionShell); |
147 | 166 | // should be instantaneous, but happens to go asynchronous on CI so let's allow a wait |
148 | 167 | new DisplayHelper() { |
169 | 188 | testCompletion(); |
170 | 189 | emulatePressLeftArrowKey(); |
171 | 190 | DisplayHelper.sleep(editor.getSite().getShell().getDisplay(), LongRunningBarContentAssistProcessor.DELAY + 500); // adding delay is a workaround for bug521484, use only 100ms without the bug |
172 | this.completionShell= findNewShell(beforeShells); | |
191 | this.completionShell= findNewShell(beforeShells, editor.getSite().getShell().getDisplay()); | |
173 | 192 | final Table completionProposalList = findCompletionSelectionControl(this.completionShell); |
174 | 193 | assertEquals("Missing proposals from a Processor", 2, completionProposalList.getItemCount()); // replace with line below when #5214894 is done |
175 | 194 | // checkCompletionContent(completionProposalList); // use this instead of assert above when #521484 is done |
186 | 205 | styledText.notifyListeners(ST.VerifyKey, e); |
187 | 206 | } |
188 | 207 | |
189 | private Table findCompletionSelectionControl(Widget control) { | |
208 | public static Table findCompletionSelectionControl(Widget control) { | |
190 | 209 | if (control instanceof Table) { |
191 | 210 | return (Table)control; |
192 | 211 | } else if (control instanceof Composite) { |
+21
-6
33 | 33 | import org.eclipse.jface.text.source.SourceViewer; |
34 | 34 | |
35 | 35 | import org.eclipse.ui.genericeditor.tests.contributions.BarContentAssistProcessor; |
36 | import org.eclipse.ui.tests.harness.util.UITestCase; | |
36 | 37 | |
37 | 38 | import org.eclipse.ui.texteditor.ITextEditorActionConstants; |
38 | 39 | import org.eclipse.ui.texteditor.TextOperationAction; |
53 | 54 | TextOperationAction action = (TextOperationAction) editor.getAction(ITextEditorActionConstants.CONTENT_ASSIST_CONTEXT_INFORMATION); |
54 | 55 | |
55 | 56 | editor.selectAndReveal(4, 0); |
57 | UITestCase.processEvents(); | |
58 | ||
56 | 59 | action.update(); |
57 | 60 | action.run(); |
58 | waitAndDispatch(100); | |
59 | 61 | this.completionShell= findNewShell(beforeShells); |
60 | 62 | assertEquals("idx= 0", getInfoText(this.completionShell)); |
61 | 63 | |
62 | 64 | editor.selectAndReveal(8, 0); |
65 | UITestCase.processEvents(); | |
66 | ||
63 | 67 | action.update(); |
64 | 68 | action.run(); |
65 | waitAndDispatch(100); | |
66 | 69 | this.completionShell= findNewShell(beforeShells); |
67 | 70 | assertEquals("idx= 1", getInfoText(this.completionShell)); |
68 | 71 | } |
76 | 79 | TextOperationAction action = (TextOperationAction) editor.getAction(ITextEditorActionConstants.CONTENT_ASSIST_CONTEXT_INFORMATION); |
77 | 80 | |
78 | 81 | editor.selectAndReveal(4, 0); |
82 | UITestCase.processEvents(); | |
83 | ||
79 | 84 | action.update(); |
80 | 85 | action.run(); |
81 | waitAndDispatch(100); | |
82 | 86 | this.completionShell= findNewShell(beforeShells); |
83 | 87 | |
84 | 88 | editor.selectAndReveal(8, 0); |
89 | UITestCase.processEvents(); | |
90 | ||
85 | 91 | action.update(); |
86 | 92 | action.run(); |
87 | waitAndDispatch(100); | |
88 | 93 | this.completionShell= findNewShell(beforeShells); |
89 | 94 | |
90 | 95 | editor.getAction(ITextEditorActionConstants.DELETE_LINE).run(); |
96 | 101 | |
97 | 102 | |
98 | 103 | private Shell findNewShell(Set<Shell> beforeShells) { |
104 | waitAndDispatch(100); | |
105 | Shell[] afterShells= findNewShells(beforeShells); | |
106 | if(afterShells.length == 0) { | |
107 | waitAndDispatch(1000); | |
108 | } | |
109 | afterShells= findNewShells(beforeShells); | |
110 | assertEquals("No new shell found", 1, afterShells.length); | |
111 | return afterShells[0]; | |
112 | } | |
113 | ||
114 | private Shell[] findNewShells(Set<Shell> beforeShells) { | |
99 | 115 | Shell[] afterShells = Arrays.stream(editor.getSite().getShell().getDisplay().getShells()) |
100 | 116 | .filter(Shell::isVisible) |
101 | 117 | .filter(shell -> !beforeShells.contains(shell)) |
102 | 118 | .toArray(Shell[]::new); |
103 | assertEquals("No new shell found", 1, afterShells.length); | |
104 | return afterShells[0]; | |
119 | return afterShells; | |
105 | 120 | } |
106 | 121 | |
107 | 122 | private String getInfoText(final Shell shell) { |
+1
-1
45 | 45 | Assert.assertTrue(editorTextWidget.getWordWrap()); |
46 | 46 | Assert.assertTrue(this.editor.isWordWrapEnabled()); |
47 | 47 | } |
48 | ||
48 | ||
49 | 49 | @Test |
50 | 50 | public void testGenericEditorCanShowWhitespaceCharacters() throws Exception { |
51 | 51 | this.editor.setFocus(); |
+2
-1
28 | 28 | AutoEditTest.class, |
29 | 29 | ReconcilerTest.class, |
30 | 30 | HighlightTest.class, |
31 | IconsTest.class | |
31 | IconsTest.class, | |
32 | TestQuickAssist.class | |
32 | 33 | }) |
33 | 34 | public class GenericEditorTestSuite { |
34 | 35 | // see @SuiteClasses |
+84
-0
0 | /******************************************************************************* | |
1 | * Copyright (c) 2016-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 | * Andrew Obuchowicz (Red Hat Inc.) | |
12 | *******************************************************************************/ | |
13 | package org.eclipse.ui.genericeditor.tests; | |
14 | ||
15 | import static org.junit.Assert.assertEquals; | |
16 | import static org.junit.Assert.assertTrue; | |
17 | ||
18 | import java.util.Arrays; | |
19 | import java.util.Set; | |
20 | import java.util.stream.Collectors; | |
21 | ||
22 | import org.junit.After; | |
23 | import org.junit.Test; | |
24 | ||
25 | import org.eclipse.swt.widgets.Shell; | |
26 | import org.eclipse.swt.widgets.Table; | |
27 | import org.eclipse.swt.widgets.TableItem; | |
28 | ||
29 | import org.eclipse.jface.text.tests.util.DisplayHelper; | |
30 | ||
31 | import org.eclipse.ui.texteditor.ITextEditorActionConstants; | |
32 | import org.eclipse.ui.texteditor.TextOperationAction; | |
33 | ||
34 | /** | |
35 | * @since 1.2 | |
36 | */ | |
37 | public class TestQuickAssist extends AbstratGenericEditorTest { | |
38 | ||
39 | private Shell completionShell; | |
40 | ||
41 | @Test | |
42 | public void testCompletion() throws Exception { | |
43 | final Set<Shell> beforeShells = Arrays.stream(editor.getSite().getShell().getDisplay().getShells()).filter(Shell::isVisible).collect(Collectors.toSet()); | |
44 | openQuickAssist(); | |
45 | this.completionShell= CompletionTest.findNewShell(beforeShells, editor.getSite().getShell().getDisplay()); | |
46 | final Table completionProposalList = CompletionTest.findCompletionSelectionControl(completionShell); | |
47 | checkCompletionContent(completionProposalList); | |
48 | } | |
49 | ||
50 | private void openQuickAssist() { | |
51 | editor.selectAndReveal(3, 0); | |
52 | TextOperationAction action = (TextOperationAction) editor.getAction(ITextEditorActionConstants.QUICK_ASSIST); | |
53 | action.update(); | |
54 | action.run(); | |
55 | waitAndDispatch(100); | |
56 | } | |
57 | ||
58 | /** | |
59 | * Checks that a mock quick assist proposal comes up | |
60 | * @param completionProposalList the quick assist proposal list | |
61 | */ | |
62 | private void checkCompletionContent(final Table completionProposalList) { | |
63 | // should be instantaneous, but happens to go asynchronous on CI so let's allow a wait | |
64 | new DisplayHelper() { | |
65 | @Override | |
66 | protected boolean condition() { | |
67 | return completionProposalList.getItemCount() == 1; | |
68 | } | |
69 | }.waitForCondition(completionProposalList.getDisplay(), 200); | |
70 | assertEquals(1, completionProposalList.getItemCount()); | |
71 | final TableItem quickAssistItem = completionProposalList.getItem(0); | |
72 | assertTrue("Missing quick assist proposal", quickAssistItem.getText().contains("QUICK ASSIST PROPOSAL")); //$NON-NLS-1$ //$NON-NLS-2$ | |
73 | ||
74 | } | |
75 | ||
76 | ||
77 | @After | |
78 | public void closeShell() { | |
79 | if (this.completionShell != null && !completionShell.isDisposed()) { | |
80 | completionShell.close(); | |
81 | } | |
82 | } | |
83 | } |
+1
-1
67 | 67 | } |
68 | 68 | |
69 | 69 | /** |
70 | * Creates context info "idx= <word index in #PROPOSAL>" at the end of a word. | |
70 | * Creates context info "idx= <word index in #PROPOSAL>" at the end of a word. | |
71 | 71 | **/ |
72 | 72 | @Override |
73 | 73 | public IContextInformation[] computeContextInformation(ITextViewer viewer, int offset) { |
+2
-2
27 | 27 | public class MarkerResolutionGenerator implements IMarkerResolutionGenerator { |
28 | 28 | |
29 | 29 | public static final String FIXME= MarkerResolutionGenerator.class.getName() + ".fixme"; |
30 | ||
30 | ||
31 | 31 | private static class MarkerResolution implements IMarkerResolution2 { |
32 | 32 | @Override |
33 | 33 | public String getDescription() { |
50 | 50 | e.printStackTrace(); |
51 | 51 | } |
52 | 52 | } |
53 | ||
53 | ||
54 | 54 | } |
55 | 55 | |
56 | 56 | @Override |
+46
-0
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 | * Andrew Obuchowicz (Red Hat Inc.) | |
12 | *******************************************************************************/ | |
13 | package org.eclipse.ui.genericeditor.tests.contributions; | |
14 | ||
15 | import org.eclipse.jface.text.contentassist.CompletionProposal; | |
16 | import org.eclipse.jface.text.contentassist.ICompletionProposal; | |
17 | import org.eclipse.jface.text.quickassist.IQuickAssistInvocationContext; | |
18 | import org.eclipse.jface.text.quickassist.IQuickAssistProcessor; | |
19 | import org.eclipse.jface.text.source.Annotation; | |
20 | ||
21 | public class MockQuickAssistProcessor implements IQuickAssistProcessor{ | |
22 | ||
23 | @Override | |
24 | public String getErrorMessage() { | |
25 | return "A MOCK ERROR MESSAGE"; | |
26 | } | |
27 | ||
28 | @Override | |
29 | public boolean canFix(Annotation annotation) { | |
30 | return true; | |
31 | } | |
32 | ||
33 | @Override | |
34 | public boolean canAssist(IQuickAssistInvocationContext invocationContext) { | |
35 | return true; | |
36 | } | |
37 | ||
38 | @Override | |
39 | public ICompletionProposal[] computeQuickAssistProposals(IQuickAssistInvocationContext invocationContext) { | |
40 | CompletionProposal proposal = new CompletionProposal("QUICK ASSIST PROPOSAL", 0, 10, 0); | |
41 | ICompletionProposal[] proposals = {proposal}; | |
42 | return proposals; | |
43 | } | |
44 | ||
45 | } |
+71
-0
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 | package org.eclipse.ui.genericeditor.tests.contributions; | |
11 | ||
12 | import org.eclipse.jface.text.BadLocationException; | |
13 | import org.eclipse.jface.text.ITextSelection; | |
14 | import org.eclipse.jface.text.ITextViewer; | |
15 | import org.eclipse.jface.text.ITextViewerExtension9; | |
16 | import org.eclipse.jface.text.contentassist.CompletionProposal; | |
17 | import org.eclipse.jface.text.contentassist.ICompletionProposal; | |
18 | import org.eclipse.jface.text.contentassist.IContentAssistProcessor; | |
19 | import org.eclipse.jface.text.contentassist.IContextInformation; | |
20 | import org.eclipse.jface.text.contentassist.IContextInformationValidator; | |
21 | ||
22 | public class ToUpperCaseContentAssistProcessor implements IContentAssistProcessor { | |
23 | ||
24 | @Override | |
25 | public ICompletionProposal[] computeCompletionProposals(ITextViewer viewer, int offset) { | |
26 | if (!(viewer instanceof ITextViewerExtension9)) { | |
27 | return new ICompletionProposal[0]; | |
28 | } | |
29 | ITextSelection selection= ((ITextViewerExtension9)viewer).getLastKnownSelection(); | |
30 | if (selection.isEmpty() || selection.getLength() == 0) { | |
31 | return new ICompletionProposal[0]; | |
32 | } | |
33 | String initialText; | |
34 | try { | |
35 | initialText= viewer.getDocument().get(selection.getOffset(), selection.getLength()); | |
36 | return new ICompletionProposal[] { | |
37 | new CompletionProposal(initialText.toUpperCase(), selection.getOffset(), initialText.length(), selection.getOffset() + initialText.length()) | |
38 | }; | |
39 | } catch (BadLocationException e) { | |
40 | return new ICompletionProposal[0]; | |
41 | } | |
42 | ||
43 | } | |
44 | ||
45 | @Override | |
46 | public IContextInformation[] computeContextInformation(ITextViewer viewer, int offset) { | |
47 | return new IContextInformation[0]; | |
48 | } | |
49 | ||
50 | @Override | |
51 | public char[] getCompletionProposalAutoActivationCharacters() { | |
52 | return new char[0]; | |
53 | } | |
54 | ||
55 | @Override | |
56 | public char[] getContextInformationAutoActivationCharacters() { | |
57 | return new char[0]; | |
58 | } | |
59 | ||
60 | @Override | |
61 | public String getErrorMessage() { | |
62 | return getClass().getName(); | |
63 | } | |
64 | ||
65 | @Override | |
66 | public IContextInformationValidator getContextInformationValidator() { | |
67 | return null; | |
68 | } | |
69 | ||
70 | } |
1 | 1 | Bundle-ManifestVersion: 2 |
2 | 2 | Bundle-Name: %pluginName |
3 | 3 | Bundle-SymbolicName: org.eclipse.ui.workbench.texteditor; singleton:=true |
4 | Bundle-Version: 3.13.0.qualifier | |
4 | Bundle-Version: 3.14.0.qualifier | |
5 | 5 | Bundle-Activator: org.eclipse.ui.internal.texteditor.TextEditorPlugin |
6 | 6 | Bundle-ActivationPolicy: lazy |
7 | 7 | Bundle-Vendor: %providerName |
0 | <?xml version="1.0" encoding="UTF-8"?> | |
1 | <!-- | |
2 | Copyright (c) 2012, 2019 Eclipse Foundation and others. | |
3 | All rights reserved. This program and the accompanying materials | |
4 | are made available under the terms of the Eclipse Distribution License v1.0 | |
5 | which accompanies this distribution, and is available at | |
6 | http://www.eclipse.org/org/documents/edl-v10.php | |
7 | ||
8 | Contributors: | |
9 | Igor Fedorenko - initial implementation | |
10 | --> | |
11 | <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | |
12 | <modelVersion>4.0.0</modelVersion> | |
13 | <parent> | |
14 | <artifactId>eclipse.platform.text</artifactId> | |
15 | <groupId>eclipse.platform.text</groupId> | |
16 | <version>4.13.0-SNAPSHOT</version> | |
17 | </parent> | |
18 | <groupId>org.eclipse.ui</groupId> | |
19 | <artifactId>org.eclipse.ui.workbench.texteditor</artifactId> | |
20 | <version>3.13.0-SNAPSHOT</version> | |
21 | <packaging>eclipse-plugin</packaging> | |
22 | </project> |
+1
-1
901 | 901 | */ |
902 | 902 | private void reinitOnError(Exception e) { |
903 | 903 | if (DEBUG) |
904 | System.err.println("reinitializing quickdiff:\n" + e.getLocalizedMessage() + "\n" + e.getStackTrace()); //$NON-NLS-1$//$NON-NLS-2$ | |
904 | System.err.println("reinitializing quickdiff:\n" + e.getLocalizedMessage() + "\n" + Arrays.toString(e.getStackTrace())); //$NON-NLS-1$//$NON-NLS-2$ | |
905 | 905 | initialize(); |
906 | 906 | } |
907 | 907 |
+18
-1
6752 | 6752 | boolean showOffset = getPreferenceStore().getBoolean(PREFERENCE_SHOW_CARET_OFFSET); |
6753 | 6753 | Point selectedRange = fSourceViewer.getSelectedRange(); |
6754 | 6754 | int selectionLength = selectedRange != null ? selectedRange.y : 0; |
6755 | fOffsetLabel.fValue = selectionLength == 0 ? caret : selectionLength; | |
6756 | 6755 | showSelection = showSelection && selectionLength > 0; |
6756 | fOffsetLabel.fValue = showSelection ? selectionLength : caret; | |
6757 | 6757 | if (!showSelection) { |
6758 | 6758 | if (!showOffset) { |
6759 | 6759 | // shows line : column |
7273 | 7273 | TabsToSpacesConverter tabToSpacesConverter= new TabsToSpacesConverter(); |
7274 | 7274 | tabToSpacesConverter.setLineTracker(new DefaultLineTracker()); |
7275 | 7275 | tabToSpacesConverter.setNumberOfSpacesPerTab(tabWidth); |
7276 | tabToSpacesConverter.setDeleteSpacesAsTab(isSpacesAsTabsDeletionEnabled()); | |
7276 | 7277 | ((ITextViewerExtension7)fSourceViewer).setTabsToSpacesConverter(tabToSpacesConverter); |
7277 | 7278 | updateIndentPrefixes(); |
7278 | 7279 | } |
7303 | 7304 | * @since 3.3 |
7304 | 7305 | */ |
7305 | 7306 | protected boolean isTabsToSpacesConversionEnabled() { |
7307 | return false; | |
7308 | } | |
7309 | ||
7310 | /** | |
7311 | * Tells whether delete and backspace keys should remove multiple spaces as | |
7312 | * if they were a tab. Only relevant when | |
7313 | * {@link #isTabsToSpacesConversionEnabled()} returns true. | |
7314 | * | |
7315 | * <p> | |
7316 | * Subclasses may override this method. | |
7317 | * </p> | |
7318 | * | |
7319 | * @return <code>true</code> if spaces should be removed as tabs | |
7320 | * @since 3.14 | |
7321 | */ | |
7322 | protected boolean isSpacesAsTabsDeletionEnabled() { | |
7306 | 7323 | return false; |
7307 | 7324 | } |
7308 | 7325 |
+1
-1
53 | 53 | * line</li> |
54 | 54 | * <li><code>setActiveEditor</code> - extend to react to editor changes</li> |
55 | 55 | * </ul> |
56 | * | |
56 | * | |
57 | 57 | * @see org.eclipse.ui.texteditor.ITextEditorActionConstants |
58 | 58 | */ |
59 | 59 | public class BasicTextEditorActionContributor extends EditorActionBarContributor { |
+3
-2
10 | 10 | # Contributors: |
11 | 11 | # IBM Corporation - initial API and implementation |
12 | 12 | # Pierre-Yves B., pyvesdev@gmail.com - Bug 121634: [find/replace] status bar must show the string being searched when "String Not Found" |
13 | # Pierre-Yves B., pyvesdev@gmail.com - Bug 552069: Clarify "File Changed" dialog | |
13 | 14 | ############################################################################### |
14 | 15 | |
15 | 16 | |
31 | 32 | Editor_error_activated_outofsync_title=File Changed |
32 | 33 | Editor_error_activated_outofsync_message=The file ''{0}'' has been changed on the file system. Do you want to replace the editor contents with these changes? |
33 | 34 | |
34 | Editor_error_replace_button_label=&Replace | |
35 | Editor_error_dontreplace_button_label=&Do not replace | |
35 | Editor_error_replace_button_label=&Replace editor content | |
36 | Editor_error_dontreplace_button_label=&Ignore file change | |
36 | 37 | |
37 | 38 | Editor_error_activated_deleted_save_title=File Not Accessible |
38 | 39 | Editor_error_activated_deleted_save_message=The file ''{0}'' has been deleted or is not accessible. Do you want to save your changes or close the editor without saving? |
+3
-5
397 | 397 | */ |
398 | 398 | private String getFirstLine(String selection) { |
399 | 399 | if (!selection.isEmpty()) { |
400 | int[] info= TextUtilities.indexOf(TextUtilities.DELIMITERS, selection, 0); | |
401 | if (info[0] > 0) | |
402 | return selection.substring(0, info[0]); | |
403 | else if (info[0] == -1) | |
404 | return selection; | |
400 | int delimiterOffset = TextUtilities.nextDelimiter(selection, 0).delimiterIndex; | |
401 | if (delimiterOffset > 0) | |
402 | return selection.substring(0, delimiterOffset); | |
405 | 403 | } |
406 | 404 | return selection; |
407 | 405 | } |
+4
-4
1047 | 1047 | */ |
1048 | 1048 | private String getFirstLine(String selection) { |
1049 | 1049 | if (!selection.isEmpty()) { |
1050 | int[] info= TextUtilities.indexOf(TextUtilities.DELIMITERS, selection, 0); | |
1051 | if (info[0] > 0) | |
1052 | return selection.substring(0, info[0]); | |
1053 | else if (info[0] == -1) | |
1050 | int delimiterOffset = TextUtilities.nextDelimiter(selection, 0).delimiterIndex; | |
1051 | if (delimiterOffset > 0) | |
1052 | return selection.substring(0, delimiterOffset); | |
1053 | else if (delimiterOffset == -1) | |
1054 | 1054 | return selection; |
1055 | 1055 | } |
1056 | 1056 | return ""; //$NON-NLS-1$ |
+1
-7
31 | 31 | |
32 | 32 | import org.eclipse.ui.internal.texteditor.CompoundEditExitStrategy; |
33 | 33 | import org.eclipse.ui.internal.texteditor.HippieCompletionEngine; |
34 | import org.eclipse.ui.internal.texteditor.ICompoundEditListener; | |
35 | 34 | import org.eclipse.ui.internal.texteditor.TextEditorPlugin; |
36 | 35 | |
37 | 36 | |
211 | 210 | */ |
212 | 211 | HippieCompleteAction(ResourceBundle bundle, String prefix, ITextEditor editor) { |
213 | 212 | super(bundle, prefix, editor); |
214 | fExitStrategy.addCompoundListener(new ICompoundEditListener() { | |
215 | @Override | |
216 | public void endCompoundEdit() { | |
217 | clearState(); | |
218 | } | |
219 | }); | |
213 | fExitStrategy.addCompoundListener(this::clearState); | |
220 | 214 | } |
221 | 215 | |
222 | 216 | /** |
+1
-1
484 | 484 | * </p> |
485 | 485 | * (value |
486 | 486 | * <code>"org.eclipse.jdt.ui.edit.text.java.correction.assist.proposals"</code>). |
487 | * | |
487 | * | |
488 | 488 | * @since 3.2 |
489 | 489 | */ |
490 | 490 | String QUICK_ASSIST= "org.eclipse.jdt.ui.edit.text.java.correction.assist.proposals"; //$NON-NLS-1$ |
+1
-7
31 | 31 | import org.eclipse.jface.text.TextUtilities; |
32 | 32 | |
33 | 33 | import org.eclipse.ui.internal.texteditor.CompoundEditExitStrategy; |
34 | import org.eclipse.ui.internal.texteditor.ICompoundEditListener; | |
35 | 34 | |
36 | 35 | /** |
37 | 36 | * Action for moving selected lines in an editor. |
91 | 90 | fCopy= copy; |
92 | 91 | String[] commandIds= copy ? new String[] {ITextEditorActionDefinitionIds.COPY_LINES_UP, ITextEditorActionDefinitionIds.COPY_LINES_DOWN } : new String[] {ITextEditorActionDefinitionIds.MOVE_LINES_UP, ITextEditorActionDefinitionIds.MOVE_LINES_DOWN }; |
93 | 92 | fStrategy= new CompoundEditExitStrategy(commandIds); |
94 | fStrategy.addCompoundListener(new ICompoundEditListener() { | |
95 | @Override | |
96 | public void endCompoundEdit() { | |
97 | MoveLinesAction.this.endCompoundEdit(); | |
98 | } | |
99 | }); | |
93 | fStrategy.addCompoundListener(MoveLinesAction.this::endCompoundEdit); | |
100 | 94 | update(); |
101 | 95 | } |
102 | 96 |
+2
-2
57 | 57 | * Default number of characters that should fit into the item. |
58 | 58 | * @since 3.0 |
59 | 59 | */ |
60 | static final int DEFAULT_WIDTH_IN_CHARS= 14; | |
60 | static final int DEFAULT_WIDTH_IN_CHARS = 19; | |
61 | 61 | /** |
62 | 62 | * Pre-computed label width hint. |
63 | 63 | * @since 2.1 |
268 | 268 | } |
269 | 269 | |
270 | 270 | /** |
271 | * Escapes '&' with '&' in the given text. | |
271 | * Escapes '&' with '&' in the given text. | |
272 | 272 | * |
273 | 273 | * @param text the text to escape, can be <code>null</code> |
274 | 274 | * @return the escaped string or <code>null</code> if text was <code>null</code> |
13 | 13 | <parent> |
14 | 14 | <artifactId>tests-pom</artifactId> |
15 | 15 | <groupId>eclipse.platform.text</groupId> |
16 | <version>4.13.0-SNAPSHOT</version> | |
16 | <version>4.14.0-SNAPSHOT</version> | |
17 | 17 | <relativePath>../tests-pom/</relativePath> |
18 | 18 | </parent> |
19 | 19 | <groupId>org.eclipse.ui</groupId> |
14 | 14 | <parent> |
15 | 15 | <groupId>org.eclipse</groupId> |
16 | 16 | <artifactId>eclipse-platform-parent</artifactId> |
17 | <version>4.13.0-SNAPSHOT</version> | |
17 | <version>4.14.0-SNAPSHOT</version> | |
18 | 18 | <relativePath>../eclipse-platform-parent</relativePath> |
19 | 19 | </parent> |
20 | 20 | |
21 | 21 | <groupId>eclipse.platform.text</groupId> |
22 | 22 | <artifactId>eclipse.platform.text</artifactId> |
23 | <version>4.13.0-SNAPSHOT</version> | |
23 | <version>4.14.0-SNAPSHOT</version> | |
24 | 24 | <packaging>pom</packaging> |
25 | 25 | |
26 | 26 | <properties> |
13 | 13 | <parent> |
14 | 14 | <artifactId>eclipse.platform.text</artifactId> |
15 | 15 | <groupId>eclipse.platform.text</groupId> |
16 | <version>4.13.0-SNAPSHOT</version> | |
16 | <version>4.14.0-SNAPSHOT</version> | |
17 | 17 | </parent> |
18 | 18 | <artifactId>tests-pom</artifactId> |
19 | <version>4.13.0-SNAPSHOT</version> | |
19 | <version>4.14.0-SNAPSHOT</version> | |
20 | 20 | <packaging>pom</packaging> |
21 | 21 | <properties> |
22 | 22 | <code.ignoredWarnings>${tests.ignoredWarnings}</code.ignoredWarnings> |