@krassowski/jupyterlab_go_to_definition
Version:
Jump to definition of a variable or function in JupyterLab
132 lines • 5.46 kB
JavaScript
import { CodeJumper, jumpers } from './jumper';
import { _ensureFocus, _findCell, _findTargetCell } from '../notebook_private';
import { JumpHistory } from '../history';
import { TokenContext } from '../languages/analyzer';
export class NotebookJumper extends CodeJumper {
constructor(notebook_widget, document_manager) {
super();
this.widget = notebook_widget;
this.notebook = notebook_widget.content;
this.history = new JumpHistory(this.notebook.model.modelDB);
this.document_manager = document_manager;
}
get kernel() {
var _a;
return (_a = this.widget.context.sessionContext.session) === null || _a === void 0 ? void 0 : _a.kernel;
}
get cwd() {
return this.widget.model.modelDB.basePath
.split('/')
.slice(0, -1)
.join('/');
}
get editors() {
return this.notebook.widgets.map(cell => cell.editor);
}
get language() {
let languageInfo = this.notebook.model.metadata.get('language_info');
// TODO: consider version of the language as well
return languageInfo.name;
}
jump(position) {
let { token, index } = position;
// Prevents event propagation issues
setTimeout(() => {
this.notebook.deselectAll();
this.notebook.activeCellIndex = index;
_ensureFocus(this.notebook);
this.notebook.mode = 'edit';
// find out offset for the element
let activeEditor = this.notebook.activeCell.editor;
// place cursor in the line with the definition
let position = activeEditor.getPositionAt(token.offset);
activeEditor.setSelection({ start: position, end: position });
}, 0);
}
jump_to_definition(jump, index) {
if (index === undefined) {
// Using `index = this._findCell(editor.host)` does not work,
// as the host editor has not switched to the clicked cell yet.
// The mouse event is utilized to workaround Firefox's issue.
if (jump.mouseEvent !== undefined) {
index = _findTargetCell(this.notebook, jump.mouseEvent).index;
}
else {
index = _findCell(this.notebook, jump.origin);
}
}
// if the definition is in a different file:
// only support cases like:
// "from x import y" (clicking on y opens x.py)
// or
// "y.x" (clicking on y opens y.py)
let cell_of_origin_editor = this.editors[index];
let cell_of_origin_analyzer = this._getLanguageAnalyzerForCell(cell_of_origin_editor);
cell_of_origin_analyzer._maybe_setup_tokens();
let context = new TokenContext(jump.token, cell_of_origin_analyzer.tokens, cell_of_origin_analyzer._get_token_index(jump.token));
let after_jump = () => {
this.history.store({ token: jump.token, index: index });
};
if (cell_of_origin_analyzer.isCrossFileReference(context)) {
this.jump_to_cross_file_reference(context, cell_of_origin_analyzer);
}
else {
// try to get the location of definition from the kernel (for Python - using inspect)
// if has location:
// open tab with the file
this.inspect_and_jump(context, cell_of_origin_analyzer, () => {
// TODO when reassigning objects:
// def xyz(): pass
// a = xyz
// x = a
// click on the last 'a' will lead to a jump to 'def xyz(): pass' instead to 'a = xyz'
// when using kernel for resolution. This may not be the expected behaviour!
// maybe we should first try to _findLastDefinition and only jump with kernel if none found
// (plus as an option - when user presses a different combination, it could be labeled "deep jump")
// if it fails, jump to the last definition in the current notebook:
let { token, cellIndex } = this._findLastDefinition(jump.token, index);
// nothing found
if (!token) {
return;
}
this.jump({ token: token, index: cellIndex });
}, after_jump);
}
}
jump_back() {
let previous_position = this.history.recollect();
if (previous_position) {
this.jump(previous_position);
}
}
getOffset(position, cell = 0) {
return this.editors[cell].getOffsetAt(position);
}
getJumpPosition(position, input_number) {
let cells = this.widget.model.cells.iter();
let cell = cells.next();
let i = 0;
let cell_index;
while (cell) {
if (cell.type === 'code') {
let code_cell = cell;
if (code_cell.executionCount === input_number) {
cell_index = i;
break;
}
}
cell = cells.next();
i += 1;
}
// TODO: what if we cannot get the cell index?
return {
token: {
offset: this.getOffset(position, cell_index),
value: ''
},
index: cell_index
};
}
}
jumpers.set('notebook', NotebookJumper);
//# sourceMappingURL=notebook.js.map