incorporate code listings from an external file in knitr/markdown

痴心易碎 提交于 2021-01-22 06:54:48

问题


I would like to incorporate listings of code drawn from external files in an Rmarkdown file. I would like it pretty (syntax highlighting, auto-indentation, etc.).

  • The code is not R code (otherwise I could use some of the existing tricks to pretty-print R functions) - specifically, it's BUGS and Stan code.
  • I'm not necessarily targeting LaTeX/PDF output: otherwise I could use the listings package.
  • I'd like to be able to incorporate the files without an unwieldy external cat firstpart.rmd codefile.rmd lastpart.rmd >wholefile.rmd system command, and without a pre-processing step: this question suggests that Markdown processors like Multimarkdown and Marked 2 have file inclusion syntax, but I think I'm stuck with pandoc.
  • At present I'm using code chunks like this
```{r jagsmodel, echo=FALSE, results="markup", comment=""}
cat(readLines("logist.bug"),sep="\n")
```

which works OK but doesn't get me syntax highlighting ...


回答1:


Here's one approach. You need pygments installed (pip install pygments) and it has to be able to put (it should on it's own) "pygmentize somewhere on your system. If you don't have python or can't install that module, then this answer is obviously not going to be an answer for you.

The following knitr chunks (all but the last one which is pure R) call pygmentize to create HTML markup for the code. It should be possible to modify https://github.com/hrbrmstr/knitrengines to make this more "automagical" but that's not on my short-term TODO.

---
title: "lexers"
output: 
  html_document:
    css: code.css
    keep_md: true
---

```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
```

### Bugs

```{r bugs1, echo=FALSE, results="asis"}
tf <- tempfile(fileext=".html")
system(sprintf("/usr/local/bin/pygmentize -o %s incl.bug", tf))
cat(readLines(tf), sep="\n")
unlink(tf)
```

### Elixir

```{r elixir1, echo=FALSE, results="asis"}
tf <- tempfile(fileext=".html")
system(sprintf("/usr/local/bin/pygmentize -o %s incl.ex", tf))
cat(readLines(tf), sep="\n")
unlink(tf)
```

### Python

```{r py1, echo=FALSE, results="asis"}
tf <- tempfile(fileext=".html")
system(sprintf("/usr/local/bin/pygmentize -o %s incl.py", tf))
cat(readLines(tf), sep="\n")
unlink(tf)
```

### Plain ol' R

```{r}
summary(mtcars)
```

That makes:

You can use any pygments CSS file you like for a different scheme, this is what's in code.css:

<style>
.gl .hll { background-color: #ffffcc }
.highlight  { background: #f8f8f8; }
.highlight .c { color: #408080; font-style: italic } /* Comment */
.highlight .err { border: 1px solid #FF0000 } /* Error */
.highlight .k { color: #008000; font-weight: bold } /* Keyword */
.highlight .o { color: #666666 } /* Operator */
.highlight .cm { color: #408080; font-style: italic } /* Comment.Multiline */
.highlight .cp { color: #BC7A00 } /* Comment.Preproc */
.highlight .c1 { color: #408080; font-style: italic } /* Comment.Single */
.highlight .cs { color: #408080; font-style: italic } /* Comment.Special */
.highlight .gd { color: #A00000 } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .gr { color: #FF0000 } /* Generic.Error */
.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */
.highlight .gi { color: #00A000 } /* Generic.Inserted */
.highlight .go { color: #808080 } /* Generic.Output */
.highlight .gp { color: #000080; font-weight: bold } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
.highlight .gt { color: #0040D0 } /* Generic.Traceback */
.highlight .kc { color: #008000; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #008000 } /* Keyword.Pseudo */
.highlight .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #B00040 } /* Keyword.Type */
.highlight .m { color: #666666 } /* Literal.Number */
.highlight .s { color: #BA2121 } /* Literal.String */
.highlight .na { color: #7D9029 } /* Name.Attribute */
.highlight .nb { color: #008000 } /* Name.Builtin */
.highlight .nc { color: #0000FF; font-weight: bold } /* Name.Class */
.highlight .no { color: #880000 } /* Name.Constant */
.highlight .nd { color: #AA22FF } /* Name.Decorator */
.highlight .ni { color: #999999; font-weight: bold } /* Name.Entity */
.highlight .ne { color: #D2413A; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #0000FF } /* Name.Function */
.highlight .nl { color: #A0A000 } /* Name.Label */
.highlight .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */
.highlight .nt { color: #008000; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #19177C } /* Name.Variable */
.highlight .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mf { color: #666666 } /* Literal.Number.Float */
.highlight .mh { color: #666666 } /* Literal.Number.Hex */
.highlight .mi { color: #666666 } /* Literal.Number.Integer */
.highlight .mo { color: #666666 } /* Literal.Number.Oct */
.highlight .sb { color: #BA2121 } /* Literal.String.Backtick */
.highlight .sc { color: #BA2121 } /* Literal.String.Char */
.highlight .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */
.highlight .s2 { color: #BA2121 } /* Literal.String.Double */
.highlight .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */
.highlight .sh { color: #BA2121 } /* Literal.String.Heredoc */
.highlight .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */
.highlight .sx { color: #008000 } /* Literal.String.Other */
.highlight .sr { color: #BB6688 } /* Literal.String.Regex */
.highlight .s1 { color: #BA2121 } /* Literal.String.Single */
.highlight .ss { color: #19177C } /* Literal.String.Symbol */
.highlight .bp { color: #008000 } /* Name.Builtin.Pseudo */
.highlight .vc { color: #19177C } /* Name.Variable.Class */
.highlight .vg { color: #19177C } /* Name.Variable.Global */
.highlight .vi { color: #19177C } /* Name.Variable.Instance */
.highlight .il { color: #666666 } /* Literal.Number.Integer.Long */
</style>
#

UPDATE

If you're willing to put the code (that won't get executed but will get formatted) inline, I just made an update to the aforementioned knitrengines package that lets you do this:

---
title: "pygtest"
output: html_document
---

```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
library(knitrengines)
```

```{pygments test, pyg.ext="py", pyg.sty="github"}
import something.please

print("Hello, world!")
```

```{pygments test2, pyg.ext="go", pyg.sty="github"}
package main

import "fmt"

func main() {

    s := make([]string, 3)
    fmt.Println("emp:", s)

    s[0] = "a"
    s[1] = "b"
    s[2] = "c"
    twoD := make([][]int, 3)
    for i := 0; i < 3; i++ {
        innerLen := i + 1
        twoD[i] = make([]int, innerLen)
        for j := 0; j < innerLen; j++ {
            twoD[i][j] = i + j
        }
    }
    fmt.Println("2d: ", twoD)
}
```

```{pygments test3, pyg.ext="ex", pyg.sty="github"}
defmodule Math do
  def sum(a, b) do
    a + b
  end
end

IO.puts "The answer is #{ Math.sum(4,3) }"    
```

and produces this:

I can make it use different styles per code block, but I barely had cycles to crank this out. It shouldn't be too much work tho.



来源:https://stackoverflow.com/questions/32857212/incorporate-code-listings-from-an-external-file-in-knitr-markdown

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!