Skip to content

Commit 536aa91

Browse files
[StickyScrolling] Add extension point for sticky lines provider
In order to implement editor/language specific sticky lines provider, a new extension point is introduced.
1 parent 55481d3 commit 536aa91

19 files changed

+604
-45
lines changed

Diff for: bundles/org.eclipse.ui.editors/META-INF/MANIFEST.MF

+2-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ Export-Package:
1515
org.eclipse.ui.internal.editors.text.codemining.annotation;x-internal:=true,
1616
org.eclipse.ui.internal.texteditor;x-internal:=true,
1717
org.eclipse.ui.internal.texteditor.stickyscroll;x-internal:=true,
18-
org.eclipse.ui.texteditor
18+
org.eclipse.ui.texteditor,
19+
org.eclipse.ui.texteditor.stickyscroll;x-internal:=true
1920
Require-Bundle:
2021
org.eclipse.core.runtime;bundle-version="[3.29.0,4.0.0)",
2122
org.eclipse.core.expressions;bundle-version="[3.9.0,4.0.0)",

Diff for: bundles/org.eclipse.ui.editors/plugin.properties

+1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ ExtPoint.documentProviders= Document Provider
2020
ExtPoint.markerAnnotationSpecification= Marker Annotation Specification
2121
ExtPoint.annotationTypes= Annotation Types
2222
ExtPoint.editorTemplate= Editor Template
23+
ExtPoint.stickyLinesProviders= Sticky Lines Provider
2324

2425
convertDelimiters.Windows.name= Convert Line Delimiters to Windows (CRLF, \\r\\n, 0D0A, \u00A4\u00B6)
2526
convertDelimiters.Windows.label= &Windows (CRLF, \\r\\n, 0D0A, \u00A4\u00B6)

Diff for: bundles/org.eclipse.ui.editors/plugin.xml

+1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
<extension-point id="markerAnnotationSpecification" name="%ExtPoint.markerAnnotationSpecification" schema="schema/markerAnnotationSpecification.exsd"/>
2121
<extension-point id="annotationTypes" name="%ExtPoint.annotationTypes" schema="schema/annotationTypes.exsd"/>
2222
<extension-point id="templates" name="%ExtPoint.editorTemplate" schema="schema/templates.exsd"/>
23+
<extension-point id="stickyLinesProviders" name="%ExtPoint.stickyLinesProviders" schema="schema/stickyLinesProviders.exsd"/>
2324

2425
<extension point="org.eclipse.core.runtime.preferences">
2526
<initializer class="org.eclipse.ui.internal.editors.text.EditorsPluginPreferenceInitializer"/>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
<?xml version='1.0' encoding='UTF-8'?>
2+
<!-- Schema file written by PDE -->
3+
<schema targetNamespace="org.eclipse.ui.editors" xmlns="http://www.w3.org/2001/XMLSchema">
4+
<annotation>
5+
<appInfo>
6+
<meta.schema plugin="org.eclipse.ui.editors" id="stickyLinesProviders" name="Sticky Lines Providers"/>
7+
</appInfo>
8+
<documentation>
9+
This extension point is used to register sticky lines providers for editors.
10+
</documentation>
11+
</annotation>
12+
13+
<include schemaLocation="schema://org.eclipse.core.expressions/schema/expressionLanguage.exsd"/>
14+
15+
<element name="extension">
16+
<annotation>
17+
<appInfo>
18+
<meta.element />
19+
</appInfo>
20+
</annotation>
21+
<complexType>
22+
<sequence>
23+
<element ref="stickyLinesProvider" minOccurs="1" maxOccurs="unbounded"/>
24+
</sequence>
25+
<attribute name="point" type="string" use="required">
26+
<annotation>
27+
<documentation>
28+
a fully qualified identifier of the target extension point
29+
</documentation>
30+
</annotation>
31+
</attribute>
32+
<attribute name="id" type="string">
33+
<annotation>
34+
<documentation>
35+
an optional identifier of the extension instance
36+
</documentation>
37+
</annotation>
38+
</attribute>
39+
<attribute name="name" type="string">
40+
<annotation>
41+
<documentation>
42+
an optional name of the extension instance
43+
</documentation>
44+
<appInfo>
45+
<meta.attribute translatable="true"/>
46+
</appInfo>
47+
</annotation>
48+
</attribute>
49+
</complexType>
50+
</element>
51+
52+
<element name="stickyLinesProvider">
53+
<annotation>
54+
<documentation>
55+
A sticky lines provider.
56+
</documentation>
57+
</annotation>
58+
<complexType>
59+
<sequence>
60+
<element ref="enabledWhen" minOccurs="0" maxOccurs="1"/>
61+
</sequence>
62+
<attribute name="id" type="string" use="required">
63+
<annotation>
64+
<documentation>
65+
A string uniquely identifying this sticky line provider
66+
</documentation>
67+
</annotation>
68+
</attribute>
69+
<attribute name="class" type="string" use="required">
70+
<annotation>
71+
<documentation>
72+
The fully qualified class name implementing the interface &lt;code&gt;org.eclipse.ui.texteditor.stickyscroll.IStickyLinesProvider&lt;/code&gt;.
73+
</documentation>
74+
<appInfo>
75+
<meta.attribute kind="java" basedOn=":org.eclipse.ui.texteditor.stickyscroll.IStickyLinesProvider"/>
76+
</appInfo>
77+
</annotation>
78+
</attribute>
79+
</complexType>
80+
</element>
81+
82+
<element name="enabledWhen">
83+
<annotation>
84+
<documentation>
85+
A core Expression that controls the enabled of the given sticky lines provider
86+
</documentation>
87+
</annotation>
88+
<complexType>
89+
<choice minOccurs="0" maxOccurs="1">
90+
<element ref="not"/>
91+
<element ref="or"/>
92+
<element ref="and"/>
93+
<element ref="instanceof"/>
94+
<element ref="test"/>
95+
<element ref="systemTest"/>
96+
<element ref="equals"/>
97+
<element ref="count"/>
98+
<element ref="with"/>
99+
<element ref="resolve"/>
100+
<element ref="adapt"/>
101+
<element ref="iterate"/>
102+
<element ref="reference"/>
103+
</choice>
104+
</complexType>
105+
</element>
106+
107+
<annotation>
108+
<appInfo>
109+
<meta.section type="since"/>
110+
</appInfo>
111+
<documentation>
112+
3.20
113+
</documentation>
114+
</annotation>
115+
116+
<annotation>
117+
<appInfo>
118+
<meta.section type="examples"/>
119+
</appInfo>
120+
<documentation>
121+
The following is an example of a sticky line provider definition:
122+
&lt;pre&gt;
123+
&lt;extension
124+
point=&quot;org.eclipse.ui.editors.stickyLinesProviders&quot;&gt;
125+
&lt;stickyLinesProvider
126+
class=&quot;org.eclipse.ui.internal.texteditor.stickyscroll.DefaultStickyLinesProvider&quot;
127+
id=&quot;org.eclipse.ui.editors.stickyLinesProviderExample&quot;
128+
label=&quot;Example sticky lines provider registration&quot;&gt;
129+
&lt;enabledWhen&gt;
130+
&lt;and&gt;
131+
&lt;with variable=&quot;editor&quot;&gt;
132+
&lt;instanceof value=&quot;org.example.MyEditorWithStickyScrolling&quot;/&gt;
133+
&lt;/with&gt;
134+
&lt;/and&gt;
135+
&lt;/enabledWhen&gt;
136+
&lt;/stickyLinesProvider&gt;
137+
&lt;/extension&gt;
138+
&lt;/pre&gt;
139+
</documentation>
140+
</annotation>
141+
142+
<annotation>
143+
<appInfo>
144+
<meta.section type="apiInfo"/>
145+
</appInfo>
146+
<documentation>
147+
See the org.eclipse.ui.texteditor.stickyscroll.IStickyLinesProvider interface and the org.eclipse.ui.editors.stickyLinesProviders extension point. As default implementation for the IStickyLine, see org.eclipse.ui.texteditor.stickyscroll.StickyLine.
148+
</documentation>
149+
</annotation>
150+
151+
152+
<annotation>
153+
<appInfo>
154+
<meta.section type="copyright"/>
155+
</appInfo>
156+
<documentation>
157+
Copyright (c) 2024 SAP SE.&lt;br&gt;
158+
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 &lt;a href=&quot;https://www.eclipse.org/legal/epl-2.0&quot;&gt;https://www.eclipse.org/legal/epl-v20.html&lt;/a&gt;/
159+
SPDX-License-Identifier: EPL-2.0
160+
Contributors:
161+
SAP SE - initial API and implementation
162+
</documentation>
163+
</annotation>
164+
165+
</schema>

Diff for: bundles/org.eclipse.ui.editors/src/org/eclipse/ui/internal/texteditor/stickyscroll/DefaultStickyLinesProvider.java

+4
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@
2222
import org.eclipse.jface.text.ITextViewerExtension5;
2323
import org.eclipse.jface.text.source.ISourceViewer;
2424

25+
import org.eclipse.ui.texteditor.stickyscroll.IStickyLine;
26+
import org.eclipse.ui.texteditor.stickyscroll.IStickyLinesProvider;
27+
import org.eclipse.ui.texteditor.stickyscroll.StickyLine;
28+
2529
/**
2630
* This class provides sticky lines for the given source code in the source viewer. The
2731
* implementation is completely based on indentation and therefore works by default for several
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2024 SAP SE.
3+
*
4+
* This program and the accompanying materials
5+
* are made available under the terms of the Eclipse Public License 2.0
6+
* which accompanies this distribution, and is available at
7+
* https://www.eclipse.org/legal/epl-2.0/
8+
*
9+
* SPDX-License-Identifier: EPL-2.0
10+
*
11+
* Contributors:
12+
* SAP SE - initial API and implementation
13+
*******************************************************************************/
14+
package org.eclipse.ui.internal.texteditor.stickyscroll;
15+
16+
import org.eclipse.core.expressions.ElementHandler;
17+
import org.eclipse.core.expressions.EvaluationContext;
18+
import org.eclipse.core.expressions.EvaluationResult;
19+
import org.eclipse.core.expressions.Expression;
20+
import org.eclipse.core.expressions.ExpressionConverter;
21+
22+
import org.eclipse.core.runtime.Assert;
23+
import org.eclipse.core.runtime.CoreException;
24+
import org.eclipse.core.runtime.IConfigurationElement;
25+
import org.eclipse.core.runtime.IStatus;
26+
import org.eclipse.core.runtime.Status;
27+
28+
import org.eclipse.jface.text.source.ISourceViewer;
29+
30+
import org.eclipse.ui.internal.editors.text.EditorsPlugin;
31+
32+
import org.eclipse.ui.texteditor.ITextEditor;
33+
import org.eclipse.ui.texteditor.stickyscroll.IStickyLinesProvider;
34+
35+
import org.eclipse.ui.editors.text.EditorsUI;
36+
37+
/**
38+
* Describes an extension to the <code>stickyLinesProviders</code> extension point.
39+
*
40+
* @noextend This class is not intended to be extended by clients.
41+
*/
42+
class StickyLinesProviderDescriptor {
43+
/** Name of the <code>class</code> attribute. */
44+
private static final String CLASS_ATTRIBUTE= "class"; //$NON-NLS-1$
45+
46+
/** Name of the <code>id</code> attribute. */
47+
private static final String ID_ATTRIBUTE= "id"; //$NON-NLS-1$
48+
49+
/** Name of the <code>enabledWhen</code> attribute. **/
50+
private static final String ENABLED_WHEN_ATTR= "enabledWhen"; //$NON-NLS-1$
51+
52+
/** The configuration element describing this extension. */
53+
private IConfigurationElement configuration;
54+
55+
/** The value of the <code>id</code> attribute, if read. */
56+
private String id;
57+
58+
/** The expression value of the <code>enabledWhen</code> attribute. */
59+
private final Expression enabledWhen;
60+
61+
/**
62+
* Creates a new descriptor for <code>element</code>.
63+
* <p>
64+
* This method is for internal use only.
65+
* </p>
66+
*
67+
* @param element the extension point element to be described.
68+
* @throws CoreException when <code>enabledWhen</code> expression is not valid.
69+
*/
70+
public StickyLinesProviderDescriptor(IConfigurationElement element) throws CoreException {
71+
Assert.isLegal(element != null);
72+
configuration= element;
73+
enabledWhen= createEnabledWhen(configuration, getId());
74+
}
75+
76+
/**
77+
* Returns the expression {@link Expression} declared in the <code>enabledWhen</code> element.
78+
*
79+
* @param configElement the configuration element
80+
* @param id the id of the sticky lines provider.
81+
* @return the expression {@link Expression} declared in the enabledWhen element.
82+
* @throws CoreException when enabledWhen expression is not valid.
83+
*/
84+
private static Expression createEnabledWhen(IConfigurationElement configElement, String id) throws CoreException {
85+
final IConfigurationElement[] children= configElement.getChildren(ENABLED_WHEN_ATTR);
86+
if (children.length > 0) {
87+
IConfigurationElement[] subChildren= children[0].getChildren();
88+
if (subChildren.length != 1) {
89+
throw new CoreException(new Status(IStatus.ERROR, EditorsUI.PLUGIN_ID,
90+
"One <enabledWhen> element is accepted. Disabling " + id)); //$NON-NLS-1$
91+
}
92+
final ElementHandler elementHandler= ElementHandler.getDefault();
93+
final ExpressionConverter converter= ExpressionConverter.getDefault();
94+
return elementHandler.create(converter, subChildren[0]);
95+
}
96+
return null;
97+
}
98+
99+
/**
100+
* Reads (if needed) and returns the id of this extension.
101+
*
102+
* @return the id for this extension.
103+
*/
104+
public String getId() {
105+
if (id == null) {
106+
id= configuration.getAttribute(ID_ATTRIBUTE);
107+
Assert.isNotNull(id);
108+
}
109+
return id;
110+
}
111+
112+
/**
113+
* Creates a sticky lines provider as described in the extension's XML and null otherwise.
114+
*
115+
* @return the created sticky lines provider and null otherwise.
116+
*/
117+
protected IStickyLinesProvider createStickyLinesProvider() {
118+
try {
119+
Object extension= configuration.createExecutableExtension(CLASS_ATTRIBUTE);
120+
if (extension instanceof IStickyLinesProvider stickyLinesProvider) {
121+
return stickyLinesProvider;
122+
} else {
123+
String message= "Invalid extension to stickyLinesProvider. Must extends IStickyLinesProvider: " //$NON-NLS-1$
124+
+ getId();
125+
EditorsPlugin.getDefault().getLog()
126+
.log(new Status(IStatus.ERROR, EditorsUI.PLUGIN_ID, message));
127+
return null;
128+
}
129+
} catch (CoreException e) {
130+
EditorsPlugin.getDefault().getLog().log(new Status(IStatus.ERROR, EditorsUI.PLUGIN_ID,
131+
"Error while creating stickyLinesProvider: " + getId(), e)); //$NON-NLS-1$
132+
return null;
133+
}
134+
}
135+
136+
/**
137+
* Returns true if the given viewer, editor matches the enabledWhen expression and false
138+
* otherwise.
139+
*
140+
* @param viewer the viewer
141+
* @param editor the editor
142+
* @return true if the given viewer, editor matches the enabledWhen expression and false
143+
* otherwise.
144+
*/
145+
public boolean matches(ISourceViewer viewer, ITextEditor editor) {
146+
if (enabledWhen == null) {
147+
return true;
148+
}
149+
EvaluationContext context= new EvaluationContext(null, editor);
150+
context.setAllowPluginActivation(true);
151+
context.addVariable("viewer", viewer); //$NON-NLS-1$
152+
context.addVariable("editor", editor); //$NON-NLS-1$
153+
context.addVariable("editorInput", editor.getEditorInput()); //$NON-NLS-1$
154+
try {
155+
return enabledWhen.evaluate(context) == EvaluationResult.TRUE;
156+
} catch (CoreException e) {
157+
EditorsPlugin.getDefault().getLog().log(
158+
new Status(IStatus.ERROR, EditorsUI.PLUGIN_ID, "Error while 'enabledWhen' evaluation", e)); //$NON-NLS-1$
159+
return false;
160+
}
161+
}
162+
}

0 commit comments

Comments
 (0)