{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ ] } , { "cell_type": "code", "metadata": { "dotnet_interactive": { "language": "fsharp" }, "polyglot_notebook": { "kernelName": "fsharp" } }, "execution_count": null, "outputs": [], "source": [ "#r \"nuget: FSharp.Formatting,1.0.0\"\n" ] } , { "cell_type": "markdown", "metadata": {}, "source": [ "[![Binder](img/badge-binder.svg)](https://mybinder.org/v2/gh/fsprojects/fsharp.formatting/gh-pages?filepath=literate.ipynb)\u0026emsp;\n", "[![Script](img/badge-script.svg)](https://fsprojects.github.io/FSharp.Formatting//literate.fsx)\u0026emsp;\n", "[![Notebook](img/badge-notebook.svg)](https://fsprojects.github.io/FSharp.Formatting//literate.ipynb)\n", "\n", "# Literate Scripts\n", "\n", "The following example shows most of the features that can be used in a literate\n", "F# script file with `.fsx` extension. Most of the features should be quite self-explanatory:\n", "\n", " (**\n", " # First-level heading\n", " Some more documentation using `Markdown`.\n", " *)\n", "\n", " let helloWorld() = printfn \"Hello world!\"\n", "\n", " (**\n", " ## Second-level heading\n", " With some more documentation\n", " *)\n", "\n", " let numbers = [ 0 .. 99 ]\n", " (*** include-value: numbers ***)\n", "\n", " List.sum numbers\n", " (*** include-it ***)\n", "\n", "The F# script files is processed as follows:\n", "\n", "* A multi-line comment starting with `(**` and ending with `*)` is\n", "turned into text and is processed using the F# Markdown processor\n", "(which supports standard Markdown commands).\n", " \n", "\n", "* A single-line comment starting with `(***` and ending with `***)`\n", "is treated as a special command. The command can consist of\n", "`key`, `key: value` or `key=value` pairs.\n", " \n", "\n", "Literate Command | Description\n", ":--- | :---\n", "`(** ... *)` | Markdown\n", "`(*** condition: prepare ***)` | Utilise a code snippet when analyzing for tooltips or executing for outputs\n", "`(*** condition: ipynb ***)` | Include a code snippet when making a .ipynb notebook\n", "`(*** condition: tex ***)` | Include a code snippet when making a .tex output\n", "`(*** condition: html ***)` | Include a code snippet when making HTML output\n", "`(*** hide ***)` | Hide the subsequent snippet\n", "`(*** raw ***)` | The subsequent code is treated as raw text\n", "\n", "\n", "### Naming and including snippets\n", "\n", "The command `define` defines a named snippet (such as `final-sample`) and removes the command together with\n", "the following F# code block from the main document. The snippet can then\n", "be referred to in \u0027include\u0027. This makes it\n", "possible to write documents without the ordering requirements of the\n", "F# language.\n", "\n", "Literate Command | Description\n", ":--- | :---\n", "`(*** define: snippet-name ***)` | Define a named snippet\n", "`(*** include: snippet-name ***)` | Include the code of the named snippet\n", "\n", "\n", "### Naming and including outputs\n", "\n", "Literate Command | Description\n", ":--- | :---\n", "`(*** define-output: output-name ***)` | Define a name for the outputs of the preceding snippet\n", "`(*** include-output ***)` | The console output of the preceding snippet\n", "`(*** include-output: output-name ***)` | The console output of the snippet (named with define-output)\n", "`(*** include-fsi-output ***)` | The F# Interactive output of the preceding snippet\n", "`(*** include-fsi-output: output-name ***)` | The F# Interactive output of the snippet (named with define-output)\n", "`(*** include-fsi-merged-output ***)` | The merge of console output and F# Interactive output of the preceding snippet\n", "`(*** include-fsi-merged-output: output-name ***)` | The merge of console output and F# Interactive output of the snippet (named with define-output)\n", "`(*** include-it ***)` | The formatted result of the preceding snippet\n", "`(*** include-it: output-name ***)` | The formatted result of the snippet (named with define-output)\n", "`(*** include-it-raw ***)` | The unformatted result of the preceding snippet\n", "`(*** include-it-raw: output-name ***)` | The unformatted result of the snippet (named with define-output)\n", "`(*** include-value: value-name ***)` | The formatted value, an F# identifier name\n", "\n", "\n", "#### Hiding code snippets\n", "\n", "The command `hide` specifies that the following F# code block (until the next comment or command) should be\n", "omitted from the output.\n", "\n", "#### Evaluating and formatting results\n", "\n", "The commands to evaluate and format results are explained in [evaluation](evaluation.html).\n", "You must build your documentation with evaluation turned on using `--eval`.\n", "\n", "#### Substitutions\n", "\n", "Substitutions are applied to content, see [content](content.html).\n", "\n", "### Literate Markdown Documents\n", "\n", "For files with `.md` extension, the entire file is a Markdown document, which may\n", "contain F# code snippets (but also other code snippets). As usual, snippets are\n", "indented with four spaces. In addition, the snippets can be annotated with special\n", "commands. Some of them are demonstrated in the following example:\n", "\n", " [lang=text]\n", " # First-level heading\n", "\n", " [hide]\n", " let print s = printfn \"%s\" s\n", "\n", " Some more documentation using `Markdown`.\n", "\n", " [module=Hello]\n", " let helloWorld() = print \"Hello world!\"\n", "\n", " ## Second-level heading\n", " With some more documentation\n", "\n", " [lang=csharp]\n", " Console.WriteLine(\"Hello world!\");\n", "\n", "When processing the document, all F# snippets are copied to a separate file that\n", "is type-checked using the F# compiler (to obtain colours and tool tips).\n", "The commands are written on the first line of the named snippet, wrapped in `[...]`:\n", "\n", "* The `hide` command specifies that the F# snippet should not be included in the\n", "final document. This can be used to include code that is needed to type-check\n", "the code, but is not visible to the reader.\n", " \n", "\n", "* The `module=Foo` command can be used to specify F# `module` where the snippet\n", "is placed. Use this command if you need multiple versions of the same snippet\n", "or if you need to separate code from different snippets.\n", " \n", "\n", "* The `lang=foo` command specifies the language of the named snippet. If the language\n", "is other than `fsharp`, the snippet is copied to the output as `\u003cpre\u003e` HTML\n", "tag without any processing.\n", " \n", "\n", "### LaTeX in Literate Scripts and Markdown Documents\n", "\n", "Literate Scripts may contain LaTeX sections in Markdown using these forms:\n", "\n", "0 Single line latex starting with `$$`.\n", " \n", "\n", "1 A block delimited by `\\begin{equation}...\\end{equation}` or `\\begin{align}...\\end{align}`.\n", " \n", "\n", "2 An indented paragraph starting with `$$$`. This is F#-literate-specific and corresponds to\n", "`\\begin{equation}...\\end{equation}`.\n", " \n", "\n", "For example\n", "\n", " [lang=text]\n", " $$\\frac{x}{y}$$\n", "\n", " \\begin{equation}\n", " \\frac{d}{dx} \\left. \\left( x \\left( \\left. \\frac{d}{dy} x y \\; \\right|_{y=3} \\right) \\right) \\right|_{x=2}\n", " \\end{equation}\n", "\n", "Becomes\n", "\n", "\\begin{equation}\n", "\\frac{x}{y}\n", "\\end{equation}\n", "\n", "\\begin{equation}\n", " \\frac{d}{dx} \\left. \\left( x \\left( \\left. \\frac{d}{dy} x y \\; \\right|_{y=3} \\right) \\right) \\right|_{x=2}\n", "\\end{equation}\n", "\n", "The LaTeX will also be used in HTML and iPython notebook outputs.\n", "\n", "### Making literate scripts work for different outputs\n", "\n", "Literate scripts and markdown can by turned into LaTex, Python Notebooks and F# scripts.\n", "\n", "A header may be needed to get the code to load, a typical example is this:\n", "\n", "```text\n", " (*** condition: prepare ***)\n", " #nowarn \"211\"\n", " #I \"../src/FSharp.Formatting/bin/Release/netstandard2.1\"\n", " #r \"FSharp.Formatting.Common.dll\"\n", " #r \"FSharp.Formatting.Markdown.dll\"\n", " #r \"FSharp.Formatting.CodeFormat.dll\"\n", " #r \"FSharp.Formatting.Literate.dll\"\n", " (*** condition: fsx ***)\n", "#if FSX\n", " #r \"nuget: FSharp.Formatting,1.0.0\"\n", "#endif // FSX\n", " (*** condition: ipynb ***)\n", "#if IPYNB\n", " #r \"nuget: FSharp.Formatting,1.0.0\"\n", "#endif // IPYNB\n", "```\n", "\n", "### Processing literate files programatically\n", "\n", "To process file Use the two static methods to turn single documents into HTML\n", "as follows using functionality from the [Literate](https://fsprojects.github.io/FSharp.Formatting/reference/fsharp-formatting-literate-literate.html) type:\n", "\n" ] } , { "cell_type": "code", "metadata": { "dotnet_interactive": { "language": "fsharp" }, "polyglot_notebook": { "kernelName": "fsharp" } }, "execution_count": null, "outputs": [], "source": [ "open System.IO\n", "open FSharp.Formatting.Literate\n", "\n", "let source = __SOURCE_DIRECTORY__\n", "let template = Path.Combine(source, \"template.html\")\n", "\n", "let script = Path.Combine(source, \"../docs/script.fsx\")\n", "\n", "Literate.ConvertScriptFile(script, template)\n", "\n", "let doc = Path.Combine(source, \"../docs/document.md\")\n", "\n", "Literate.ConvertMarkdownFile(doc, template)\n" ] } , { "cell_type": "markdown", "metadata": {}, "source": [ "The following sample also uses optional parameter `parameters` to specify additional\n", "keywords that will be replaced in the template file (this matches the `template-project.html`\n", "file which is included as a sample in the package):\n", "\n" ] } , { "cell_type": "code", "metadata": { "dotnet_interactive": { "language": "fsharp" }, "polyglot_notebook": { "kernelName": "fsharp" } }, "execution_count": null, "outputs": [], "source": [ "// Load the template \u0026 specify project information\n", "let projTemplate = source + \"template-project.html\"\n", "\n", "let projInfo =\n", " [ \"fsdocs-authors\", \"Tomas Petricek\"\n", " \"fsdocs-source-link\", \"https://github.com/fsprojects/FSharp.Formatting\"\n", " \"fsdocs-collection-name\", \"F# Formatting\" ]\n" ] } , { "cell_type": "markdown", "metadata": {}, "source": [ "The methods used above ([Literate.ConvertScriptFile](https://fsprojects.github.io/FSharp.Formatting/reference/fsharp-formatting-literate-literate.html#ConvertScriptFile), [Literate.ConvertMarkdownFile](https://fsprojects.github.io/FSharp.Formatting/reference/fsharp-formatting-literate-literate.html#ConvertMarkdownFile))\n", "produce HTML output by default, but they can be also used to produce LaTeX output. This is done\n", "by setting the output kind. The following\n", "example shows how to call the methods to generate LaTeX documents:\n", "\n" ] } , { "cell_type": "code", "metadata": { "dotnet_interactive": { "language": "fsharp" }, "polyglot_notebook": { "kernelName": "fsharp" } }, "execution_count": null, "outputs": [], "source": [ "let templateTex = Path.Combine(source, \"template.tex\")\n", "\n", "let scriptTex = Path.Combine(source, \"../docs/script.fsx\")\n", "\n", "Literate.ConvertScriptFile(scriptTex, templateTex, outputKind = OutputKind.Latex)\n", "\n", "let docTex = Path.Combine(source, \"../docs/document.md\")\n", "\n", "Literate.ConvertMarkdownFile(docTex, templateTex, outputKind = OutputKind.Latex)\n" ] } , { "cell_type": "markdown", "metadata": {}, "source": [ "The methods used above (`ConvertScriptFile`, `ConvertMarkdownFile`)\n", "can also produce iPython Notebook output. This is done\n", "by setting the named parameter `format` to `OutputKind.Pynb`:\n", "\n" ] } , { "cell_type": "code", "metadata": { "dotnet_interactive": { "language": "fsharp" }, "polyglot_notebook": { "kernelName": "fsharp" } }, "execution_count": null, "outputs": [], "source": [ "// Process script file, Markdown document and a directory\n", "let scriptPynb = Path.Combine(source, \"../docs/script.fsx\")\n", "\n", "Literate.ConvertScriptFile(scriptPynb, outputKind = OutputKind.Pynb)\n", "\n", "let docPynb = Path.Combine(source, \"../docs/document.md\")\n", "\n", "Literate.ConvertMarkdownFile(docPynb, outputKind = OutputKind.Pynb)\n" ] } , { "cell_type": "markdown", "metadata": {}, "source": [ "All of the three methods discussed in the previous two sections take a number of optional\n", "parameters that can be used to tweak how the formatting works\n", "\n" ] } ], "metadata": { "kernelspec": { "display_name": ".NET (F#)", "language": "F#", "name": ".net-fsharp" }, "language_info": { "file_extension": ".fs", "mimetype": "text/x-fsharp", "name": "polyglot-notebook", "pygments_lexer": "fsharp" }, "polyglot_notebook": { "kernelInfo": { "defaultKernelName": "fsharp", "items": [ { "aliases": [], "languageName": "fsharp", "name": "fsharp" } ] } } }, "nbformat": 4, "nbformat_minor": 2 }