Skip to content

Commit

Permalink
[StickyScrolling] Add extension point for sticky lines provider
Browse files Browse the repository at this point in the history
In order to implement editor/language specific sticky lines provider, a new extension point is introduced.
  • Loading branch information
Christopher-Hermann committed Dec 19, 2024
1 parent 8bd169c commit b82b52b
Show file tree
Hide file tree
Showing 19 changed files with 600 additions and 40 deletions.
3 changes: 2 additions & 1 deletion bundles/org.eclipse.ui.editors/META-INF/MANIFEST.MF
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ Export-Package:
org.eclipse.ui.internal.editors.text.codemining.annotation;x-internal:=true,
org.eclipse.ui.internal.texteditor;x-internal:=true,
org.eclipse.ui.internal.texteditor.stickyscroll;x-internal:=true,
org.eclipse.ui.texteditor
org.eclipse.ui.texteditor,
org.eclipse.ui.texteditor.stickyscroll
Require-Bundle:
org.eclipse.core.runtime;bundle-version="[3.29.0,4.0.0)",
org.eclipse.core.expressions;bundle-version="[3.9.0,4.0.0)",
Expand Down
1 change: 1 addition & 0 deletions bundles/org.eclipse.ui.editors/plugin.properties
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ ExtPoint.documentProviders= Document Provider
ExtPoint.markerAnnotationSpecification= Marker Annotation Specification
ExtPoint.annotationTypes= Annotation Types
ExtPoint.editorTemplate= Editor Template
ExtPoint.stickyLinesProviders= Sticky Lines Provider

convertDelimiters.Windows.name= Convert Line Delimiters to Windows (CRLF, \\r\\n, 0D0A, \u00A4\u00B6)
convertDelimiters.Windows.label= &Windows (CRLF, \\r\\n, 0D0A, \u00A4\u00B6)
Expand Down
1 change: 1 addition & 0 deletions bundles/org.eclipse.ui.editors/plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
<extension-point id="markerAnnotationSpecification" name="%ExtPoint.markerAnnotationSpecification" schema="schema/markerAnnotationSpecification.exsd"/>
<extension-point id="annotationTypes" name="%ExtPoint.annotationTypes" schema="schema/annotationTypes.exsd"/>
<extension-point id="templates" name="%ExtPoint.editorTemplate" schema="schema/templates.exsd"/>
<extension-point id="stickyLinesProviders" name="%ExtPoint.stickyLinesProviders" schema="schema/stickyLinesProviders.exsd"/>

<extension point="org.eclipse.core.runtime.preferences">
<initializer class="org.eclipse.ui.internal.editors.text.EditorsPluginPreferenceInitializer"/>
Expand Down
165 changes: 165 additions & 0 deletions bundles/org.eclipse.ui.editors/schema/stickyLinesProviders.exsd
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
<?xml version='1.0' encoding='UTF-8'?>
<!-- Schema file written by PDE -->
<schema targetNamespace="org.eclipse.ui.editors" xmlns="http://www.w3.org/2001/XMLSchema">
<annotation>
<appInfo>
<meta.schema plugin="org.eclipse.ui.editors" id="stickyLinesProviders" name="Sticky Lines Providers"/>
</appInfo>
<documentation>
This extension point is used to register sticky lines providers for editors.
</documentation>
</annotation>

<include schemaLocation="schema://org.eclipse.core.expressions/schema/expressionLanguage.exsd"/>

<element name="extension">
<annotation>
<appInfo>
<meta.element />
</appInfo>
</annotation>
<complexType>
<sequence>
<element ref="stickyLinesProvider" minOccurs="1" maxOccurs="unbounded"/>
</sequence>
<attribute name="point" type="string" use="required">
<annotation>
<documentation>
a fully qualified identifier of the target extension point
</documentation>
</annotation>
</attribute>
<attribute name="id" type="string">
<annotation>
<documentation>
an optional identifier of the extension instance
</documentation>
</annotation>
</attribute>
<attribute name="name" type="string">
<annotation>
<documentation>
an optional name of the extension instance
</documentation>
<appInfo>
<meta.attribute translatable="true"/>
</appInfo>
</annotation>
</attribute>
</complexType>
</element>

<element name="stickyLinesProvider">
<annotation>
<documentation>
A sticky lines provider.
</documentation>
</annotation>
<complexType>
<sequence>
<element ref="enabledWhen" minOccurs="0" maxOccurs="1"/>
</sequence>
<attribute name="id" type="string" use="required">
<annotation>
<documentation>
A string uniquely identifying this sticky line provider
</documentation>
</annotation>
</attribute>
<attribute name="class" type="string" use="required">
<annotation>
<documentation>
The fully qualified class name implementing the interface &lt;code&gt;org.eclipse.ui.texteditor.stickyscroll.IStickyLinesProvider&lt;/code&gt;.
</documentation>
<appInfo>
<meta.attribute kind="java" basedOn=":org.eclipse.ui.texteditor.stickyscroll.IStickyLinesProvider"/>
</appInfo>
</annotation>
</attribute>
</complexType>
</element>

<element name="enabledWhen">
<annotation>
<documentation>
A core Expression that controls the enabled of the given sticky lines provider
</documentation>
</annotation>
<complexType>
<choice minOccurs="0" maxOccurs="1">
<element ref="not"/>
<element ref="or"/>
<element ref="and"/>
<element ref="instanceof"/>
<element ref="test"/>
<element ref="systemTest"/>
<element ref="equals"/>
<element ref="count"/>
<element ref="with"/>
<element ref="resolve"/>
<element ref="adapt"/>
<element ref="iterate"/>
<element ref="reference"/>
</choice>
</complexType>
</element>

<annotation>
<appInfo>
<meta.section type="since"/>
</appInfo>
<documentation>
3.20
</documentation>
</annotation>

<annotation>
<appInfo>
<meta.section type="examples"/>
</appInfo>
<documentation>
The following is an example of a sticky line provider definition:
&lt;pre&gt;
&lt;extension
point=&quot;org.eclipse.ui.editors.stickyLinesProviders&quot;&gt;
&lt;stickyLinesProvider
class=&quot;org.eclipse.ui.internal.texteditor.stickyscroll.DefaultStickyLinesProvider&quot;
id=&quot;org.eclipse.ui.editors.stickyLinesProviderExample&quot;
label=&quot;Example sticky lines provider registration&quot;&gt;
&lt;enabledWhen&gt;
&lt;and&gt;
&lt;with variable=&quot;editor&quot;&gt;
&lt;instanceof value=&quot;org.example.MyEditorWithStickyScrolling&quot;/&gt;
&lt;/with&gt;
&lt;/and&gt;
&lt;/enabledWhen&gt;
&lt;/stickyLinesProvider&gt;
&lt;/extension&gt;
&lt;/pre&gt;
</documentation>
</annotation>

<annotation>
<appInfo>
<meta.section type="apiInfo"/>
</appInfo>
<documentation>
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.
</documentation>
</annotation>


<annotation>
<appInfo>
<meta.section type="copyright"/>
</appInfo>
<documentation>
Copyright (c) 2024 SAP SE.&lt;br&gt;
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;/
SPDX-License-Identifier: EPL-2.0
Contributors:
SAP SE - initial API and implementation
</documentation>
</annotation>

</schema>
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@
import org.eclipse.jface.text.ITextViewerExtension5;
import org.eclipse.jface.text.source.ISourceViewer;

import org.eclipse.ui.texteditor.stickyscroll.IStickyLine;
import org.eclipse.ui.texteditor.stickyscroll.IStickyLinesProvider;
import org.eclipse.ui.texteditor.stickyscroll.StickyLine;

/**
* This class provides sticky lines for the given source code in the source viewer. The
* implementation is completely based on indentation and therefore works by default for several
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
/*******************************************************************************
* Copyright (c) 2024 SAP SE.
*
* 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
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* SAP SE - initial API and implementation
*******************************************************************************/
package org.eclipse.ui.internal.texteditor.stickyscroll;

import org.eclipse.core.expressions.ElementHandler;
import org.eclipse.core.expressions.EvaluationContext;
import org.eclipse.core.expressions.EvaluationResult;
import org.eclipse.core.expressions.Expression;
import org.eclipse.core.expressions.ExpressionConverter;

import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;

import org.eclipse.jface.text.source.ISourceViewer;

import org.eclipse.ui.internal.editors.text.EditorsPlugin;

import org.eclipse.ui.texteditor.ITextEditor;
import org.eclipse.ui.texteditor.stickyscroll.IStickyLinesProvider;

import org.eclipse.ui.editors.text.EditorsUI;

/**
* Describes an extension to the <code>stickyLinesProviders</code> extension point.
*
* @noextend This class is not intended to be extended by clients.
*/
class StickyLinesProviderDescriptor {
/** Name of the <code>class</code> attribute. */
private static final String CLASS_ATTRIBUTE= "class"; //$NON-NLS-1$

/** Name of the <code>id</code> attribute. */
private static final String ID_ATTRIBUTE= "id"; //$NON-NLS-1$

/** Name of the <code>enabledWhen</code> attribute. **/
private static final String ENABLED_WHEN_ATTR= "enabledWhen"; //$NON-NLS-1$

/** The configuration element describing this extension. */
private IConfigurationElement configuration;

/** The value of the <code>id</code> attribute, if read. */
private String id;

/** The expression value of the <code>enabledWhen</code> attribute. */
private final Expression enabledWhen;

/**
* Creates a new descriptor for <code>element</code>.
* <p>
* This method is for internal use only.
* </p>
*
* @param element the extension point element to be described.
* @throws CoreException when <code>enabledWhen</code> expression is not valid.
*/
public StickyLinesProviderDescriptor(IConfigurationElement element) throws CoreException {
Assert.isLegal(element != null);
configuration= element;
enabledWhen= createEnabledWhen(configuration, getId());
}

/**
* Returns the expression {@link Expression} declared in the <code>enabledWhen</code> element.
*
* @param configElement the configuration element
* @param id the id of the sticky lines provider.
* @return the expression {@link Expression} declared in the enabledWhen element.
* @throws CoreException when enabledWhen expression is not valid.
*/
private static Expression createEnabledWhen(IConfigurationElement configElement, String id) throws CoreException {
final IConfigurationElement[] children= configElement.getChildren(ENABLED_WHEN_ATTR);
if (children.length > 0) {
IConfigurationElement[] subChildren= children[0].getChildren();
if (subChildren.length != 1) {
throw new CoreException(new Status(IStatus.ERROR, EditorsUI.PLUGIN_ID,
"One <enabledWhen> element is accepted. Disabling " + id)); //$NON-NLS-1$
}
final ElementHandler elementHandler= ElementHandler.getDefault();
final ExpressionConverter converter= ExpressionConverter.getDefault();
return elementHandler.create(converter, subChildren[0]);
}
return null;
}

/**
* Reads (if needed) and returns the id of this extension.
*
* @return the id for this extension.
*/
public String getId() {
if (id == null) {
id= configuration.getAttribute(ID_ATTRIBUTE);
Assert.isNotNull(id);
}
return id;
}

/**
* Creates a sticky lines provider as described in the extension's XML and null otherwise.
*
* @return the created sticky lines provider and null otherwise.
*/
protected IStickyLinesProvider createStickyLinesProvider() {
try {
Object extension= configuration.createExecutableExtension(CLASS_ATTRIBUTE);
if (extension instanceof IStickyLinesProvider stickyLinesProvider) {
return stickyLinesProvider;
} else {
String message= "Invalid extension to stickyLinesProvider. Must extends IStickyLinesProvider: " //$NON-NLS-1$
+ getId();
EditorsPlugin.getDefault().getLog()
.log(new Status(IStatus.ERROR, EditorsUI.PLUGIN_ID, message));
return null;
}
} catch (CoreException e) {
EditorsPlugin.getDefault().getLog().log(new Status(IStatus.ERROR, EditorsUI.PLUGIN_ID,
"Error while creating stickyLinesProvider: " + getId(), e)); //$NON-NLS-1$
return null;
}
}

/**
* Returns true if the given viewer, editor matches the enabledWhen expression and false
* otherwise.
*
* @param viewer the viewer
* @param editor the editor
* @return true if the given viewer, editor matches the enabledWhen expression and false
* otherwise.
*/
public boolean matches(ISourceViewer viewer, ITextEditor editor) {
if (enabledWhen == null) {
return true;
}
EvaluationContext context= new EvaluationContext(null, editor);
context.setAllowPluginActivation(true);
context.addVariable("viewer", viewer); //$NON-NLS-1$
context.addVariable("editor", editor); //$NON-NLS-1$
context.addVariable("editorInput", editor.getEditorInput()); //$NON-NLS-1$
try {
return enabledWhen.evaluate(context) == EvaluationResult.TRUE;
} catch (CoreException e) {
EditorsPlugin.getDefault().getLog().log(
new Status(IStatus.ERROR, EditorsUI.PLUGIN_ID, "Error while 'enabledWhen' evaluation", e)); //$NON-NLS-1$
return false;
}
}
}
Loading

0 comments on commit b82b52b

Please sign in to comment.