Skip to content

Commit

Permalink
馃彿 Add filename to code & include directives
Browse files Browse the repository at this point in the history
  • Loading branch information
rowanc1 committed Sep 26, 2023
1 parent d35e02b commit 60cf9a5
Show file tree
Hide file tree
Showing 6 changed files with 52 additions and 31 deletions.
7 changes: 7 additions & 0 deletions .changeset/silver-suits-rush.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'myst-directives': patch
'myst-transforms': patch
'myst-spec-ext': patch
---

Add filename to codeblock and include directives
48 changes: 19 additions & 29 deletions docs/code.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ numbering:
```{warning}
The code blocks on this page are for **presentation** of code only, they are not executed.
For code execution, see the `{code-cell}` directive in the execution section of the documentation.
For code execution, see the {myst:directive}`code-cell` directive in the execution section of the documentation.
```

You can include code in your documents using the standard markup syntax of ` ```language `,
Expand All @@ -31,10 +31,10 @@ A list of language names supported by the `myst-react` package is here: [HLJS l

## Code blocks

The above code is not a directive, it is just standard markdown syntax, which cannot add a caption or label. To caption or label blocks of code use the `code-block` directive.
The above code is not a directive, it is just standard markdown syntax, which cannot add a {myst:directive}`code.caption` or {myst:directive}`code.label`. To caption or label blocks of code use the {myst:directive}`code` directive.

````{myst}
```{code-block} python
```{code} python
:name: my-program
:caption: Creating a TensorMesh using SimPEG
from discretize import TensorMesh
Expand All @@ -50,47 +50,37 @@ In the [](#my-program), we create a mesh for simulation using [SimPEG](https://d

## Numbering and Highlighting

To add numbers and emphasis to lines, we are following the [sphinx](https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html#directive-code-block) `code-block` directive. You can use `linenos` which is a flag, with no value, and `emphasize-lines` with a comma-separated list of line numbers to emphasize.
To add numbers and emphasis to lines use the {myst:directive}`code` directive. You can use {myst:directive}`code.linenos` which is a flag, with no value, and {myst:directive}`code.emphasize-lines` with a comma-separated list of line numbers to emphasize.

````{code-block} md
````{code} md
:linenos:
:emphasize-lines: 2,3
:caption: Emphasize lines inside of a `code` block.
```{code-block}
```{code}
:linenos:
:emphasize-lines: 2,3
...
````

You can also set the start number using the `lineno-start` directive, and all emphasized lines will be relative to that number.
You can also set the start number using the {myst:directive}`code.lineno-start` directive, and all emphasized lines will be relative to that number.

## `code-block` reference

linenos (no value)
: Show line numbers for the code block

lineno-start (number)
: Set the first line number of the code block. If present, `linenos` option is also automatically activated.
: Default line numbering starts at `1`.

emphasize-lines (string)
: Emphasize lines of the code block, for example, `1, 2` highlights the first and second lines.
: The line number counting starts at `lineno-start`, which is by default `1`.

caption (string)
: Add a caption to the code block.
```{tip} Docutils and Sphinx Compatibility
:class: dropdown
name (string)
: The target label for the code-block, can be used by `ref` and `numref` roles.
For full compatibility with Sphinx we suggest using `{code-block}` directive, which is an alias of the {myst:directive}`code` directive. The MyST implementation supports both the Sphinx [`{code-block} directive`](https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html#directive-code-block) as well as the `docutils` [{code} directive](https://docutils.sourceforge.io/docs/ref/rst/directives.html#code) implementation, which only supports the `number-lines` option.
```{note} Alternative implementations
:class: dropdown
You can use either `code` or `code-block` directive documented above or even a normal markdown code block.
All implementations in MyST are resolved to the same `code` type in the abstract syntax tree.
```

The parser also supports the `docutils` implementation (see [docutils documentation](https://docutils.sourceforge.io/docs/ref/rst/directives.html#code)) of a `{code}` directive, which only supports the `number-lines` option.
## Showing a Filename

It is recommended to use the more fully featured `code-block` directive documented above, or a simple markdown code block.
Adding a {myst:directive}`code.filename` option will show the name of the file at the top of the code block. For example, `myst.yml` in the following example:

All implementations are resolved to the same `code` type in the abstract syntax tree.
```{code} yaml
:filename: myst.yml
project:
title: Showing Filenames in code-blocks
```

## Including Files
Expand Down
18 changes: 17 additions & 1 deletion packages/myst-directives/src/code.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ function parseEmphasizeLines(emphasizeLinesString?: string | undefined): number[
export function getCodeBlockOptions(
options: DirectiveData['options'],
vfile: VFile,
): Pick<Code, 'emphasizeLines' | 'showLineNumbers' | 'startingLineNumber'> {
defaultFilename?: string,
): Pick<Code, 'emphasizeLines' | 'showLineNumbers' | 'startingLineNumber' | 'filename'> {
if (options?.['lineno-start'] != null && options?.['number-lines'] != null) {
fileWarn(vfile, 'Cannot use both "lineno-start" and "number-lines"', {
source: 'code-block:options',
Expand All @@ -39,16 +40,24 @@ export function getCodeBlockOptions(
} else if (startingLineNumber == null || startingLineNumber <= 1) {
startingLineNumber = undefined;
}
let filename = options?.['filename'] as string | undefined;
if (filename?.toLowerCase() === 'false') {
filename = undefined;
} else if (!filename && defaultFilename) {
filename = defaultFilename;
}
return {
emphasizeLines,
showLineNumbers,
startingLineNumber,
filename,
};
}

export const CODE_DIRECTIVE_OPTIONS: DirectiveSpec['options'] = {
caption: {
type: 'myst',
doc: 'A parsed caption for the code block.',
},
linenos: {
type: Boolean,
Expand All @@ -66,6 +75,10 @@ export const CODE_DIRECTIVE_OPTIONS: DirectiveSpec['options'] = {
type: String,
doc: 'Emphasize particular lines (comma-separated numbers), e.g. "3,5"',
},
filename: {
type: String,
doc: 'Show the filename in addition to the rendered code. The `include` directive will use the filename by default, to turn off this default set the filename to `false`.',
},
// dedent: {
// type: Number,
// doc: 'Strip indentation characters from the code block',
Expand All @@ -78,9 +91,11 @@ export const CODE_DIRECTIVE_OPTIONS: DirectiveSpec['options'] = {

export const codeDirective: DirectiveSpec = {
name: 'code',
doc: 'A code-block environment with a language as the argument, and options for highlighting, showing line numbers, and an optional filename.',
alias: ['code-block', 'sourcecode'],
arg: {
type: String,
doc: 'Code language, for example `python` or `typescript`',
},
options: {
label: {
Expand All @@ -95,6 +110,7 @@ export const codeDirective: DirectiveSpec = {
},
body: {
type: String,
doc: 'The raw code to display for the code block.',
},
run(data, vfile): GenericNode[] {
const { label, identifier } = normalizeLabel(data.options?.label as string | undefined) || {};
Expand Down
7 changes: 6 additions & 1 deletion packages/myst-directives/src/include.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,12 @@ export const includeDirective: DirectiveSpec = {
];
}
const lang = (data.options?.lang as string) ?? extToLanguage(file.split('.').pop());
const opts = getCodeBlockOptions(data.options, vfile);
const opts = getCodeBlockOptions(
data.options,
vfile,
// Set the filename in the literal include by default
file.split(/\/|\\/).pop(),
);
const filter: Include['filter'] = {};
ensureOnlyOneOf(vfile, data.options, ['start-at', 'start-line', 'start-after', 'lines']);
ensureOnlyOneOf(vfile, data.options, ['end-at', 'end-line', 'end-before', 'lines']);
Expand Down
2 changes: 2 additions & 0 deletions packages/myst-spec-ext/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ export type Admonition = SpecAdmonition & {

export type Code = SpecCode & {
executable?: boolean;
filename?: string;
visibility?: 'show' | 'hide' | 'remove';
};

Expand Down Expand Up @@ -170,6 +171,7 @@ export type Include = {
/** The `match` will be removed in a transform */
startingLineNumber?: number | 'match';
emphasizeLines?: number[];
filename?: string;
identifier?: string;
label?: string;
children?: (FlowContent | ListContent | PhrasingContent)[];
Expand Down
1 change: 1 addition & 0 deletions packages/myst-transforms/src/include.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ export async function includeDirectiveTransform(tree: GenericParent, file: VFile
'startingLineNumber',
'label',
'identifier',
'filename',
] as const
).forEach((attr) => {
if (!node[attr]) return;
Expand Down

0 comments on commit 60cf9a5

Please sign in to comment.