Skip to content

CodeLens Extension Point

Angelo edited this page Aug 18, 2017 · 6 revisions

Here a quick tutorial to implement your own CodeLens inside your own editor.

Customize CodeLens

The first step is to create your own CodeLens class to register needed data used to resolve Codelens or implement action when the CodeLens is clicked:

package org.eclipse.codelens.samples;

import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.text.provisional.codelens.CodeLens;
import org.eclipse.swt.widgets.Display;

public class ClassCodeLens extends CodeLens {

	private String className;
	
	public ClassCodeLens(String className, int startLineNumber) {
		super(startLineNumber);
		this.className = className;
	}

	public String getClassName() {
		return className;
	}

	@Override
	public void open() {
		Display.getDefault().asyncExec(new Runnable() {
			
			@Override
			public void run() {				
				MessageDialog.openInformation(Display.getDefault().getActiveShell(), "Open class CodeLens", ClassCodeLens.this.className);
	
			}
		});		
	}
}

ICodeLensProvider class implementation

Async

ICodeLensProvider API works with CompletableFuture:

package org.eclipse.jface.text.provisional.codelens;

import java.util.concurrent.CompletableFuture;

import org.eclipse.core.runtime.IProgressMonitor;

/**
 * A code lens provider adds [commands](#Command) to source text. The commands
 * will be shown as dedicated horizontal lines in between the source text.
 */
public interface ICodeLensProvider {

	/**
	 * Compute a list of [lenses](#CodeLens). This call should return as fast as
	 * possible and if computing the commands is expensive implementors should only
	 * return code lens objects with the range set and implement
	 * [resolve](#CodeLensProvider.resolveCodeLens).
	 *
	 * @param document
	 *            The document in which the command was invoked.
	 * @param token
	 *            A cancellation token.
	 * @return An array of code lenses or a thenable that resolves to such. The lack
	 *         of a result can be signaled by returning `undefined`, `null`, or an
	 *         empty array.
	 */
	CompletableFuture<ICodeLens[]> provideCodeLenses(ICodeLensContext context, IProgressMonitor monitor);

	/**
	 * This function will be called for each visible code lens, usually when
	 * scrolling and after calls to
	 * [compute](#CodeLensProvider.provideCodeLenses)-lenses.
	 *
	 * @param codeLens
	 *            code lens that must be resolved.
	 * @param token
	 *            A cancellation token.
	 * @return The given, resolved code lens or thenable that resolves to such.
	 */
	CompletableFuture<ICodeLens> resolveCodeLens(ICodeLensContext context, ICodeLens codeLens,
			IProgressMonitor monitor);
}

Sync

If you don't want to use CompletableFutire, you can AbstractSyncCodeLensProvider At this step you can implement you own CodeLens Provider like this:

package org.eclipse.codelens.samples;

import java.util.ArrayList;
import java.util.List;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.ITextViewer;
import org.eclipse.jface.text.provisional.codelens.AbstractSyncCodeLensProvider;
import org.eclipse.jface.text.provisional.codelens.Command;
import org.eclipse.jface.text.provisional.codelens.ICodeLens;
import org.eclipse.jface.text.provisional.codelens.ICodeLensContext;

public class ClassReferencesCodeLensProvider extends AbstractSyncCodeLensProvider {

	@Override
	public ICodeLens[] provideSyncCodeLenses(ICodeLensContext context, IProgressMonitor monitor) {
		ITextViewer textViewer = context.getViewer();
		IDocument document = textViewer.getDocument();
		List<ICodeLens> lenses = new ArrayList<>();
		int lineCount = document.getNumberOfLines();
		for (int i = 0; i < lineCount; i++) {
			String line = getLineText(document, i, false);
			int index = line.indexOf("class ");
			if (index != -1) {
				String className = line.substring(index + "class ".length(), line.length());
				index = className.indexOf(" ");
				if (index != -1) {
					className = className.substring(0, index);
				}
				if (className.length() > 0) {
					lenses.add(new ClassCodeLens(className, i + 1));
				}
			}
		}
		return lenses.toArray(new ICodeLens[0]);
	}

	@Override
	public ICodeLens resolveSyncCodeLens(ICodeLensContext context, ICodeLens codeLens, IProgressMonitor monitor) {
		ITextViewer textViewer = context.getViewer();
		IDocument document = textViewer.getDocument();
		String className = ((ClassCodeLens) codeLens).getClassName();
		int refCount = 0;
		int lineCount = document.getNumberOfLines();
		for (int i = 0; i < lineCount; i++) {
			String line = getLineText(document, i, false);
			refCount += line.contains("new " + className) ? 1 : 0;
		}
		((ClassCodeLens) codeLens).setCommand(new Command(refCount + " references", ""));
		return codeLens;
	}

	private static String getLineText(IDocument document, int line, boolean withLineDelimiter) {
		try {
			int lo = document.getLineOffset(line);
			int ll = document.getLineLength(line);
			if (!withLineDelimiter) {
				String delim = document.getLineDelimiter(line);
				ll = ll - (delim != null ? delim.length() : 0);
			}
			return document.get(lo, ll);
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

}

Extension Point

You can register your custom CodeLens provider with Extension Point.

The target mylanguage.codeLens is used to define which Codelens provider should be executed with your editor:

<!-- "references" CodeLens -->
<extension
  point="org.eclipse.codelens.codeLensProviders">
   <codeLensProvider
         name="References"
         class="org.eclipse.codelens.samples.ClassReferencesCodeLensProvider"
         targetId="mylanguage.codeLens">
   </codeLensProvider>
</extension>

<!-- "implementations" CodeLens -->
<extension
  point="org.eclipse.codelens.codeLensProviders">
   <codeLensProvider
         name="Implementations"
         class="org.eclipse.codelens.samples.ClassImplementationsCodeLensProvider"
         targetId="mylanguage.codeLens">
   </codeLensProvider>
</extension>

CodeLensStrategy

Create an instance of CodeLensStrategy bound with the text viewer of your editor and target .

ITextViewer textViewer = ...
CodeLensStrategy codelens = new CodeLensStrategy(new DefaultCodeLensContext(textViewer), false);		
codelensStategy.addTarget("mylanguage.codeLens");

When editor changed, codelens strategy should be updated. In a Thread background or other thing update codelensStategy when your editor changed:

codelensStategy.reconcile(null, null);