Skip to content

Commit 6db5759

Browse files
committed
implement basic support for \label and \ref in a Jupyter notebook
- this is pretty minimal and works, but doesn't yet implement doing a global pass on first load. It also doesn't update the label/ref index when the document changes. It's basically meant to be useful when the markdown is NOT being edited -- it's for consumption.
1 parent cad9d53 commit 6db5759

File tree

2 files changed

+33
-0
lines changed

2 files changed

+33
-0
lines changed

src/packages/frontend/jupyter/cell-input.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,9 @@ export const CellInput: React.FC<CellInputProps> = React.memo(
233233
value = "";
234234
}
235235
value = value.trim();
236+
if (props.actions?.processRenderedMarkdown != null) {
237+
value = props.actions.processRenderedMarkdown({ value, id: props.id });
238+
}
236239
return (
237240
<div
238241
onDoubleClick={handle_md_double_click}

src/packages/jupyter/redux/actions.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ export abstract class JupyterActions extends Actions<JupyterStoreState> {
7474
public _complete_request?: number;
7575
public store: JupyterStore;
7676
public syncdb: SyncDB;
77+
private labels: { [label: string]: { tag: string; id: string } } = {};
7778

7879
public _init(
7980
project_id: string,
@@ -2726,6 +2727,35 @@ export abstract class JupyterActions extends Actions<JupyterStoreState> {
27262727
// [ ] TODO: we also need to do this on compute servers, but
27272728
// they don't yet have the listings table.
27282729
};
2730+
2731+
processRenderedMarkdown = ({ value, id }: { value: string; id: string }) => {
2732+
const labels = this.labels;
2733+
const labelRegExp = /\s*\\label\{.*?\}\s*/g;
2734+
const noLabels = value.replace(labelRegExp, (labelContent) => {
2735+
const label = extractLabel(labelContent);
2736+
if (labels[label] == null) {
2737+
labels[label] = { tag: `${misc.len(labels) + 1}`, id };
2738+
}
2739+
return `\\tag{${labels[label].tag}}`;
2740+
});
2741+
const refRegExp = /\\ref\{.*?\}/g;
2742+
const noRefs = noLabels.replace(refRegExp, (refContent) => {
2743+
const label = extractLabel(refContent);
2744+
if (labels[label] == null) {
2745+
// nothing to do but strip it
2746+
return "";
2747+
}
2748+
const { tag, id } = labels[label];
2749+
return `[${tag}](#id=${id})`;
2750+
});
2751+
return noRefs;
2752+
};
2753+
}
2754+
2755+
function extractLabel(content: string): string {
2756+
const i = content.indexOf("{");
2757+
const j = content.lastIndexOf("}");
2758+
return content.slice(i + 1, j);
27292759
}
27302760

27312761
function bounded_integer(n: any, min: any, max: any, def: any) {

0 commit comments

Comments
 (0)