Skip to content

Commit

Permalink
Feat: add expr support
Browse files Browse the repository at this point in the history
  • Loading branch information
agoose77 committed Jun 11, 2022
1 parent ca0f746 commit b87d202
Show file tree
Hide file tree
Showing 6 changed files with 178 additions and 64 deletions.
5 changes: 5 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@ dynamic = [
"version",
]

[project.optional-dependencies]
eval = [
"jupyterlab-imarkdown>=0.2.0a0",
]

[project.urls]
Homepage = "https://github.com/executablebooks/jupyterlab-myst"

Expand Down
64 changes: 0 additions & 64 deletions src/builtins/docutils.ts

This file was deleted.

1 change: 1 addition & 0 deletions src/builtins/docutils/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const EXPR_CLASS = 'eval-expr';
78 changes: 78 additions & 0 deletions src/builtins/docutils/directives.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import {
directiveOptions,
IDirectiveData,
directivesDefault,
Directive
} from 'markdown-it-docutils';
import { EXPR_CLASS } from './constants';
import type Token from 'markdown-it/lib/token';

const Figure = directivesDefault['figure'];
const { uri } = directiveOptions;

export class EvalDirectiveAny extends Directive {
public required_arguments = 1;
public optional_arguments = 0;
public final_argument_whitespace = false;
public has_content = false;
public rawOptions = true;

run(data: IDirectiveData<keyof EvalDirectiveAny['option_spec']>): Token[] {
// TODO store options and the fact that this is a code cell rather than a fence?
const token = this.createToken('expr', 'input', 0, {
content: data.body,
map: data.bodyMap
});
const expr = uri(data.args[0] || '');
token.attrSet('type', 'hidden');
token.attrSet('class', EXPR_CLASS);
token.attrSet('value', expr);
return [token];
}
}

/** Directive for parsing code outputs from notebooks, wrapped in a figure.
*
* Adapted from: docutils/docutils/parsers/rst/directives/images.py
*/
export class EvalFigureDirective extends Figure {
create_image(
data: IDirectiveData<keyof EvalFigureDirective['option_spec']>
): Token {
// get URI
const expr = uri(data.args[0] || '');
const token = this.createToken('expr', 'input', 0, {
map: data.map,
block: true
});
token.attrSet('type', 'hidden');
token.attrSet('class', EXPR_CLASS);
token.attrSet('value', expr);
token.attrSet('alt', data.options.alt || '');
// TODO markdown-it default renderer requires the alt as children tokens
const altTokens: Token[] = [];
if (data.options.alt) {
this.state.md.inline.parse(
data.options.alt,
this.state.md,
this.state.env,
altTokens
);
}
token.children = altTokens;
if (data.options.height) {
token.attrSet('height', data.options.height);
}
if (data.options.width) {
token.attrSet('width', data.options.width);
}
if (data.options.align) {
token.attrJoin('class', `align-${data.options.align}`);
}
if (data.options.class) {
token.attrJoin('class', data.options.class.join(' '));
}

return token;
}
}
80 changes: 80 additions & 0 deletions src/builtins/docutils/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import { simpleMarkdownItPlugin } from '@agoose77/jupyterlab-markup';
import { JupyterFrontEndPlugin } from '@jupyterlab/application';
import type MarkdownIt from 'markdown-it';
import katex from 'katex';

import { PACKAGE_NS } from '../tokens';
import { EvalRole } from './roles';
import { EvalDirectiveAny, EvalFigureDirective } from './directives';

import {
directivesDefault,
rolesDefault,
IOptions
} from 'markdown-it-docutils';

/**
* Provides docutils roles and directives
*/
export const docutils: JupyterFrontEndPlugin<void> = simpleMarkdownItPlugin(
PACKAGE_NS,
{
id: 'markdown-it-docutils',
title: 'Docutils',
description:
'Plugin for implementing docutils style roles (inline extension point) and directives (block extension point)',
documentationUrls: {
Plugin: 'https://github.com/executablebooks/markdown-it-docutils'
},
examples: {
'Example ': '```{name} argument\n:option: value\n\ncontent\n```'
},
plugin: async () => {
const docutilsPlugin = await import(
/* webpackChunkName: "markdown-it-docutils" */ 'markdown-it-docutils'
);
function wrappedDocutilsPlugin(md: MarkdownIt, options: IOptions) {
const roles = {
...(options?.roles ?? rolesDefault),
eval: EvalRole
};
const directives = {
...(options?.directives ?? directivesDefault),
'eval:figure': EvalFigureDirective,
eval: EvalDirectiveAny
};

docutilsPlugin.default(md, {
...options,
roles: roles,
directives: directives
});

// Add renderers to MarkdownIt
md.renderer.rules['math_block'] = (tokens, idx) => {
const token = tokens[idx];
const content = token.content.trim();
const rendered = katex.renderToString(content, {
displayMode: true,
throwOnError: false,
output: 'htmlAndMathml'
});
return `<div class="${token.attrGet('class')}">${rendered}</div>`;
};

md.renderer.rules['math_inline'] = (tokens, idx) => {
const token = tokens[idx];
const content = token.content.trim();
const rendered = katex.renderToString(content, {
displayMode: false,
throwOnError: false,
output: 'htmlAndMathml'
});
return `<span class="${token.attrGet('class')}">${rendered}</span>`;
};
}

return [wrappedDocutilsPlugin];
}
}
);
14 changes: 14 additions & 0 deletions src/builtins/docutils/roles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { IRoleData, Role } from 'markdown-it-docutils';
import { EXPR_CLASS } from './constants';
import type Token from 'markdown-it/lib/token';

export class EvalRole extends Role {
run(data: IRoleData): Token[] {
const inline = new this.state.Token('expr', 'input', 0);
inline.attrSet('class', EXPR_CLASS);
inline.attrSet('type', 'hidden');
inline.attrSet('value', data.content);
inline.content = data.content;
return [inline];
}
}

0 comments on commit b87d202

Please sign in to comment.