@krassowski/jupyterlab_go_to_definition
Version:
Jump to definition of a variable or function in JupyterLab
183 lines • 7.54 kB
JavaScript
import { ICommandPalette } from '@jupyterlab/apputils';
import { INotebookTracker } from '@jupyterlab/notebook';
import { CodeMirrorEditor } from '@jupyterlab/codemirror';
import { IEditorTracker } from '@jupyterlab/fileeditor';
import { ISettingRegistry } from '@jupyterlab/settingregistry';
import { IDocumentManager } from '@jupyterlab/docmanager';
import { FileEditorJumper } from './jumpers/fileeditor';
import { NotebookJumper } from './jumpers/notebook';
import { CodeMirrorExtension } from './editors/codemirror';
/**
* The plugin registration information.
*/
const plugin = {
id: '@krassowski/jupyterlab_go_to_definition:plugin',
requires: [
IEditorTracker,
INotebookTracker,
ISettingRegistry,
ICommandPalette,
IDocumentManager
],
activate: (app, fileEditorTracker, notebookTracker, settingRegistry, palette, documentManager) => {
CodeMirrorExtension.configure();
fileEditorTracker.widgetAdded.connect((sender, widget) => {
let fileEditor = widget.content;
if (fileEditor.editor instanceof CodeMirrorEditor) {
let jumper = new FileEditorJumper(widget, documentManager);
let extension = new CodeMirrorExtension(fileEditor.editor, jumper);
extension.connect();
}
});
notebookTracker.widgetAdded.connect((sender, widget) => {
// btw: notebookTracker.currentWidget.content === notebook
let jumper = new NotebookJumper(widget, documentManager);
let notebook = widget.content;
// timeout ain't elegant but the widgets are not populated at the start-up time
// (notebook.widgets.length === 1) - some time is needed for that,
// and I can't see any callbacks for cells.
// more insane idea would be to have it run once every 2 seconds
// more reasonable thing would be to create a PR with .onAddCell
setTimeout(() => {
// now (notebook.widgets.length is likely > 1)
notebook.widgets.every(cell => {
let codemirror_editor = cell.editor;
let extension = new CodeMirrorExtension(codemirror_editor, jumper);
extension.connect();
return true;
});
}, 2000);
// for that cells which will be added later:
notebook.activeCellChanged.connect((notebook, cell) => {
if (cell === undefined) {
return;
}
let codemirror_editor = cell.editor;
let extension = new CodeMirrorExtension(codemirror_editor, jumper);
extension.connect();
});
});
function updateOptions(settings) {
let options = settings.composite;
Object.keys(options).forEach(key => {
if (key === 'modifier') {
let modifier = options[key];
CodeMirrorExtension.modifierKey = modifier;
}
});
}
settingRegistry
.load(plugin.id)
.then(settings => {
updateOptions(settings);
settings.changed.connect(() => {
updateOptions(settings);
});
})
.catch((reason) => {
console.error(reason.message);
});
// Add an application command
const cmdIds = {
jumpNotebook: 'go-to-definition:notebook',
jumpFileEditor: 'go-to-definition:file-editor',
jumpBackNotebook: 'go-to-definition:notebook-back',
jumpBackFileEditor: 'go-to-definition:file-editor-back'
};
// Add the command to the palette.
palette.addItem({
command: cmdIds.jumpNotebook,
category: 'Notebook Cell Operations'
});
palette.addItem({
command: cmdIds.jumpBackNotebook,
category: 'Notebook Cell Operations'
});
palette.addItem({
command: cmdIds.jumpFileEditor,
category: 'Text Editor'
});
palette.addItem({
command: cmdIds.jumpBackFileEditor,
category: 'Text Editor'
});
function isEnabled(tracker) {
return () => tracker.currentWidget != null &&
tracker.currentWidget === app.shell.currentWidget;
}
app.commands.addCommand(cmdIds.jumpNotebook, {
label: 'Jump to definition',
execute: () => {
let notebook_widget = notebookTracker.currentWidget;
let notebook = notebook_widget.content;
let jumper = new NotebookJumper(notebook_widget, documentManager);
let cell = notebook_widget.content.activeCell;
let editor = cell.editor;
let position = editor.getCursorPosition();
let token = editor.getTokenForPosition(position);
jumper.jump_to_definition({ token, origin: null }, notebook.activeCellIndex);
},
isEnabled: isEnabled(notebookTracker)
});
app.commands.addCommand(cmdIds.jumpBackNotebook, {
label: 'Jump back',
execute: () => {
let notebook_widget = notebookTracker.currentWidget;
let jumper = new NotebookJumper(notebook_widget, documentManager);
jumper.jump_back();
},
isEnabled: isEnabled(notebookTracker)
});
app.commands.addCommand(cmdIds.jumpFileEditor, {
label: 'Jump to definition',
execute: () => {
let fileEditorWidget = fileEditorTracker.currentWidget;
let fileEditor = fileEditorWidget.content;
let jumper = new FileEditorJumper(fileEditorWidget, documentManager);
let editor = fileEditor.editor;
let position = editor.getCursorPosition();
let token = editor.getTokenForPosition(position);
jumper.jump_to_definition({ token, origin: null });
},
isEnabled: isEnabled(fileEditorTracker)
});
app.commands.addCommand(cmdIds.jumpBackFileEditor, {
label: 'Jump back',
execute: () => {
let fileEditorWidget = fileEditorTracker.currentWidget;
let jumper = new FileEditorJumper(fileEditorWidget, documentManager);
jumper.jump_back();
},
isEnabled: isEnabled(fileEditorTracker)
});
const bindings = [
{
selector: '.jp-Notebook.jp-mod-editMode',
keys: ['Ctrl Alt B'],
command: cmdIds.jumpNotebook
},
{
selector: '.jp-Notebook',
keys: ['Alt O'],
command: cmdIds.jumpBackNotebook
},
{
selector: '.jp-FileEditor',
keys: ['Ctrl Alt B'],
command: cmdIds.jumpFileEditor
},
{
selector: '.jp-FileEditor',
keys: ['Alt O'],
command: cmdIds.jumpBackFileEditor
}
];
bindings.map(binding => app.commands.addKeyBinding(binding));
},
autoStart: true
};
/**
* Export the plugin as default.
*/
export default plugin;
//# sourceMappingURL=index.js.map