@krassowski/jupyterlab_go_to_definition
Version:
Jump to definition of a variable or function in JupyterLab
80 lines • 2.81 kB
JavaScript
import { LanguageWithOptionalSemicolons } from './analyzer';
export class RAnalyzer extends LanguageWithOptionalSemicolons {
constructor() {
super(...arguments);
this.definitionRules = [
this.isStandaloneAssignment,
this.isImport,
this.isForLoop
];
}
isAssignment(token) {
return ((token.type === 'operator' && token.value === '=') ||
(token.type === 'operator arrow' &&
(token.value === '<-' || token.value === '<<-')));
}
// Matching standalone variable assignment:
isStandaloneAssignment(context) {
let { previous, next } = context;
return (
// standard, leftwards assignments:
(next.exists && this.isAssignment(next)) ||
// rightwards assignments:
(previous.exists &&
previous.type === 'operator arrow' &&
(previous.value === '->' || previous.value === '->>')));
}
// Matching imports:
isImport(context) {
let { previous } = context;
if (previous.exists &&
previous.type === 'variable' &&
(previous.value === 'library' || previous.value === 'require')) {
return true;
}
previous = this.traverse_left(previous, ', ');
if (previous.exists &&
previous.value === 'here' &&
previous.type === 'variable' &&
previous.previous.value === '::' &&
previous.previous.previous.value === 'import') {
return true;
}
return false;
}
// Matching `for` loop and comprehensions:
isForLoop(context) {
let { previous, next } = context;
return (previous.exists &&
previous.type === 'keyword' &&
previous.value === 'for' &&
next.exists &&
next.type === 'keyword' &&
next.value === 'in');
}
guessReferencePath(context) {
let { next } = context;
if (context.value === 'source') {
return [next.next.value.slice(0, -1)];
}
// TODO for now only works when alt-clicking on ".from"
// ideally clicking on the file name would be preferred
return [next.next.next.value.slice(0, -1)];
}
isCrossFileReference(context) {
// case: "source('test.R')" - clicking on source will open test.R
let { next } = context;
if (context.type === 'variable' &&
context.value === 'source' &&
next.exists &&
(next.value === "'" || next.value === '"') &&
next.next.exists) {
return true;
}
if (this.isImport(context.previous)) {
return true;
}
return false;
}
}
//# sourceMappingURL=r.js.map