Provide a connector to customize tab completion results in a notebook.
- Code structure
- Creating a custom connector
- Aggregating connector responses
- Disabling a JupyterLab plugin
- Asynchronous extension initialization
- Where to go next
In this example, you will learn how to customize the behavior of JupyterLab notebooks' tab completion.
The code is split into two parts:
- the JupyterLab plugin that activates all the extension components and connects them to the main JupyterLab application via commands,
CustomConnector, a lightweight source of mocked completion results.
The first part is contained in the index.ts file, the second is in customconnector.ts.
src/customconnector.ts defines a CustomConnector to generate mock autocomplete suggestions. It implements JupyterLab's interface ICompletionProvider class.
The two methods which must be implemented in your CustomConnector from ICompletionProvider are fetch and isApplicable, which must be implemented in your CustomConnector.
// src/customconnector.ts#L25-L43
/**
* Fetch completion requests.
*
* @param request - The completion request text and details.
* @returns Completion reply
*/
fetch(
request: CompletionHandler.IRequest,
context: ICompletionContext
): Promise<CompletionHandler.ICompletionItemsReply> {
const editor = context.editor;
if (!editor) {
return Promise.reject('No editor');
}
return new Promise<CompletionHandler.ICompletionItemsReply>(resolve => {
resolve(Private.completionHint(editor!));
});
}This calls a private completionHint function, which uses the CodeEditor.IEditor widget to determine the token to suggest matches for.
// src/customconnector.ts#L74-L78
export function completionHint(
editor: CodeEditor.IEditor
): CompletionHandler.ICompletionItemsReply {
// Find the token at the cursor
const token = editor.getTokenAtCursor();A list of mock completion tokens is then created to return as ICompletionItemsReply response.
// src/customconnector.ts#L80-L99
// Create a list of matching tokens.
const tokenList = [
{ value: token.value + 'Magic', offset: token.offset, type: 'magic' },
{ value: token.value + 'Science', offset: token.offset, type: 'science' },
{ value: token.value + 'Neither', offset: token.offset }
];
// Only choose the ones that have a non-empty type field, which are likely to be of interest.
const completionList = tokenList.filter(t => t.type).map(t => t.value);
// Remove duplicate completions from the list
const matches = Array.from(new Set<string>(completionList));
const items = new Array<CompletionHandler.ICompletionItem>();
matches.forEach(label => items.push({ label }));
return {
start: token.offset,
end: token.offset + token.value.length,
items
};JupyterLab's CompletionManager fetches and merges completion responses from KernelConnector and ContextConnector (https://github.com/jupyterlab/jupyterlab/blob/b279092d88de650ea36460689257e1b8e8a418bf/packages/completer-extension/src/index.ts#L29).
We add our new completer provider to it:
// src/index.ts#L23-L23
completionManager.registerProvider(new CustomCompleterProvider());Create a server extension to serve up custom completion matches.
