Skip to content

Commit d18b78e

Browse files
committed
Work to enable possibility of a cache
1 parent 13eac37 commit d18b78e

File tree

2 files changed

+122
-54
lines changed

2 files changed

+122
-54
lines changed

src/core/handlers/embed.ts

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ import { DirectiveCell } from "../lib/break-quarto-md-types.ts";
1717
import { jupyterAssets } from "../jupyter/jupyter.ts";
1818

1919
import { notebookMarkdown, parseNotebookPath } from "./include-notebook.ts";
20-
import { JupyterCell } from "../jupyter/types.ts";
2120

2221
interface EmbedHandler {
2322
name: string;
@@ -52,11 +51,10 @@ const kHandlers: EmbedHandler[] = [
5251
assets,
5352
handlerContext.options.context,
5453
handlerContext.options.flags,
55-
(cell: JupyterCell) => {
56-
cell.metadata["echo"] = false;
57-
cell.metadata["warning"] = false;
58-
cell.metadata["output"] = "asis";
59-
return cell;
54+
{
55+
echo: false,
56+
warning: false,
57+
asis: true,
6058
},
6159
);
6260
if (markdown) {

src/core/handlers/include-notebook.ts

Lines changed: 118 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,10 @@ import {
2727
} from "../../config/format.ts";
2828
import { resolveParams } from "../../command/render/flags.ts";
2929
import { RenderContext, RenderFlags } from "../../command/render/types.ts";
30-
import {
31-
JupyterAssets,
32-
JupyterCell,
33-
JupyterCellOutput,
34-
} from "../jupyter/types.ts";
30+
import { JupyterAssets, JupyterCellOutput } from "../jupyter/types.ts";
3531

3632
import { dirname, extname } from "path/mod.ts";
33+
import { getNamedLifetime } from "../lifetimes.ts";
3734

3835
export interface NotebookAddress {
3936
path: string;
@@ -94,60 +91,133 @@ export function parseNotebookPath(path: string): NotebookAddress | undefined {
9491
}
9592
}
9693

97-
export async function notebookMarkdown(
94+
type JupyterNotebookOutputCache = Record<
95+
string,
96+
{ outputs: JupyterCellOutput[] }
97+
>;
98+
99+
async function getCellOutputs(
98100
nbAddress: NotebookAddress,
99101
assets: JupyterAssets,
100102
context: RenderContext,
101103
flags: RenderFlags,
102-
filter?: (cell: JupyterCell) => JupyterCell,
104+
options?: JupyterMarkdownOptions,
103105
) {
104-
// Read and filter notebook
105-
const notebook = jupyterFromFile(nbAddress.path);
106-
if (filter) {
107-
notebook.cells = notebook.cells.map(filter);
106+
const boolkey = (key: string, value: boolean) => {
107+
return `${key}:${String(value)}`;
108+
};
109+
const optionsKey = options
110+
? Object.keys(options).reduce((key, current) => {
111+
return current + boolkey(key, options[key]);
112+
}, "")
113+
: "";
114+
const notebookKey = `${nbAddress.path}-${optionsKey}`;
115+
116+
// TODO: Ensure that we're properly dealing with formats for includes
117+
// (e.g. docx / pdf
118+
119+
const lifetime = getNamedLifetime("render-file");
120+
/*
121+
if (lifetime === undefined) {
122+
throw new Error("Internal Error: named lifetime render-file not found");
123+
}*/
124+
const nbCache = lifetime
125+
? lifetime.get("notebook-cache") as unknown as JupyterNotebookOutputCache
126+
: undefined ||
127+
{};
128+
129+
if (!nbCache[notebookKey]) {
130+
// Render the notebook and place it in the cache
131+
// Read and filter notebook
132+
const notebook = jupyterFromFile(nbAddress.path);
133+
if (options) {
134+
notebook.cells = notebook.cells.map((cell) => {
135+
if (options.echo !== undefined) {
136+
cell.metadata[kEcho] = options.echo;
137+
}
138+
139+
if (options.warning !== undefined) {
140+
cell.metadata[kWarning] = options.warning;
141+
}
142+
143+
if (options.asis !== undefined) {
144+
cell.metadata[kOutput] = options.asis ? true : false;
145+
}
146+
return cell;
147+
});
148+
}
149+
150+
const format = context.format;
151+
const executeOptions = {
152+
target: context.target,
153+
resourceDir: resourcePath(),
154+
tempDir: context.options.services.temp.createDir(),
155+
dependencies: true,
156+
libDir: context.libDir,
157+
format: context.format,
158+
projectDir: context.project?.dir,
159+
cwd: flags.executeDir ||
160+
dirname(Deno.realPathSync(context.target.source)),
161+
params: resolveParams(flags.params, flags.paramsFile),
162+
quiet: flags.quiet,
163+
previewServer: context.options.previewServer,
164+
handledLanguages: languages(),
165+
};
166+
const result = await jupyterToMarkdown(
167+
notebook,
168+
{
169+
executeOptions,
170+
language: notebook.metadata.kernelspec.language.toLowerCase(),
171+
assets,
172+
execute: format.execute,
173+
keepHidden: format.render[kKeepHidden],
174+
toHtml: isHtmlCompatible(format),
175+
toLatex: isLatexOutput(format.pandoc),
176+
toMarkdown: isMarkdownOutput(format.pandoc),
177+
toIpynb: isIpynbOutput(format.pandoc),
178+
toPresentation: isPresentationOutput(format.pandoc),
179+
figFormat: format.execute[kFigFormat],
180+
figDpi: format.execute[kFigDpi],
181+
figPos: format.render[kFigPos],
182+
},
183+
);
184+
nbCache[notebookKey] = { outputs: result.cellOutputs };
185+
186+
// TODO: set this back into the lifetime
108187
}
188+
return nbCache[notebookKey].outputs;
189+
}
109190

110-
const format = context.format;
111-
const executeOptions = {
112-
target: context.target,
113-
resourceDir: resourcePath(),
114-
tempDir: context.options.services.temp.createDir(),
115-
dependencies: true,
116-
libDir: context.libDir,
117-
format: context.format,
118-
projectDir: context.project?.dir,
119-
cwd: flags.executeDir ||
120-
dirname(Deno.realPathSync(context.target.source)),
121-
params: resolveParams(flags.params, flags.paramsFile),
122-
quiet: flags.quiet,
123-
previewServer: context.options.previewServer,
124-
handledLanguages: languages(),
125-
};
126-
const result = await jupyterToMarkdown(
127-
notebook,
128-
{
129-
executeOptions,
130-
language: notebook.metadata.kernelspec.language.toLowerCase(),
131-
assets,
132-
execute: format.execute,
133-
keepHidden: format.render[kKeepHidden],
134-
toHtml: isHtmlCompatible(format),
135-
toLatex: isLatexOutput(format.pandoc),
136-
toMarkdown: isMarkdownOutput(format.pandoc),
137-
toIpynb: isIpynbOutput(format.pandoc),
138-
toPresentation: isPresentationOutput(format.pandoc),
139-
figFormat: format.execute[kFigFormat],
140-
figDpi: format.execute[kFigDpi],
141-
figPos: format.render[kFigPos],
142-
},
191+
export interface JupyterMarkdownOptions extends Record<string, boolean> {
192+
echo: boolean;
193+
warning: boolean;
194+
asis: boolean;
195+
}
196+
const kEcho = "echo";
197+
const kWarning = "warning";
198+
const kOutput = "output";
199+
200+
export async function notebookMarkdown(
201+
nbAddress: NotebookAddress,
202+
assets: JupyterAssets,
203+
context: RenderContext,
204+
flags: RenderFlags,
205+
options?: JupyterMarkdownOptions,
206+
) {
207+
const cellOutputs = await getCellOutputs(
208+
nbAddress,
209+
assets,
210+
context,
211+
flags,
212+
options,
143213
);
144214

145215
if (nbAddress.ids) {
146216
// If cellIds are present, filter the notebook to only include
147217
// those cells (cellIds can eiher be an explicitly set cellId, a label in the
148218
// cell metadata, or a tag on a cell that matches an id)
149219
const theCells = nbAddress.ids.map((id) => {
150-
const cell = cellForId(id, result.cellOutputs);
220+
const cell = cellForId(id, cellOutputs);
151221
if (cell === undefined) {
152222
throw new Error(
153223
`The cell ${id} does not exist in notebook`,
@@ -160,16 +230,16 @@ export async function notebookMarkdown(
160230
} else if (nbAddress.indexes) {
161231
// Filter and sort based upon cell index
162232
const theCells = nbAddress.indexes.map((idx) => {
163-
if (idx < 0 || idx >= result.cellOutputs.length) {
233+
if (idx < 0 || idx >= cellOutputs.length) {
164234
throw new Error(
165235
`The cell index ${idx} isn't within the range of cells`,
166236
);
167237
}
168-
return result.cellOutputs[idx];
238+
return cellOutputs[idx];
169239
});
170240
return theCells.map((cell) => cell.markdown).join("");
171241
} else {
172-
return result.cellOutputs.map((cell) => cell.markdown).join("");
242+
return cellOutputs.map((cell) => cell.markdown).join("");
173243
}
174244
}
175245

0 commit comments

Comments
 (0)